
  Ŀ
   This program is not finished.  There are still bugs left 
   and functionality missing.  I'm grateful for ideas, bug  
   reports etc.  My email address is arnt@swix.ifi.unit.no. 
   Please read this file before you mail me a question.     
  

  Ŀ
   To use this program you need a copy of the Spectrum ROM, 
   which is not included since it is copyrighted.           
  

This program emulates a Sinclair Spectrum 48k Z80-based computer 
on any PC with at least an 80386SX processor and VGA graphics.
  The following Spectrum features are implemented:
- Graphics, nearly perfectly.  The border is implemented, but 
flashing and special effects don't work.
- The keyboard, nearly perfectly.
- Kempston joystick, if you have a PC joystick.  Both buttons on 
the PC joystick press the single Kempston button.
- Sound, but you might not want it.  Since the emulator doesn't 
run at the same speed as a real Spectrum the pitch is most often 
wrong.  (Well, one version does, if it works.)
- Not the tape interface, yet.



                       Licence agreement

JPP is copyright (c) 1991-92 Arnt Gulbrandsen, except convert.exe, 
which is copyright (c) 1992 Henk de Groot, and specdisc.exe, which 
is copyright (c) 1992 Brian Havard.
  All rights are reserved, with the sole exception that, as long 
as the archive is kept together and no fee is involved, JPP may be 
copied by anyone.
  It is acceptable for BBSes to charge for general use but not 
specifically (additionally) for downloading of JPP.
  Disk vendors, user groups, or others who wish to distribute JPP 
for a fee may apply for permission.  Write to Arnt Gulbrandsen, 
Kometv. 8, N-7036 Trondheim, Norway.



                             Files

convert.exe    Converts snapshots between various formats.
                 Written by Henk de Groot.
extract.exe    Extracts the ROM from data files.
jpp.exe        The main emulator.
jpp-486.exe    The exact-speed version, for very fast machines.
jpp.txt        This file.
path.jpp       Contains the locations of support files.
readme.txt     A GIF showing, among others, Traci Lords.
specdisc.exe   Converts snapshots on MGT disks (48K SNP) to
                 .SNA format.  Written by Brian Havard,
                 s902150@minyos.xx.rmit.oz.au.



                             Usage

JPP will try to interpret any command-line argument to be either a 
ROM image or a snapshot, and load it.
  During execution, the 40 keys which correspond in layout to the 
Spectrum keyboard work as you'd expect.  There are also a number 
of extensions:
- Enter is Enter.
- Backspace is Caps-0.
- Both shifts are Caps-shift.
- Both alts are Symbol-shift.
- 0-9 on the keypad should work.
- +-*/ on the keypad work by 'pressing' Symbol-shift and another 
key.
- The cursor keys are Caps-5678.
  If you 'press' Caps-shift or Symbol-shift in several ways (eg. 
by pressing both DEL and a shift key) the (Spectrum) key will be 
released as soon as you release one (PC) key; this is because the 
emulator only counts whether a key is pressed or not, not (I know 
this sounds meaningless) how many times each key is pressed at 
once.
  Seven keys between 0-P-L-M and Backspace-Enter-Shift are unused.  
Unfortunately there's no way to find out what they characters they 
normally send, so JPP can't feed the 'normal' character to the 
Spectrum.  The key immediately to the right of 0, for instance, 
sends - and _ on North American keyboards, but + and ? on my 
Norwegian keyboard.
  Some function keys are interpreted by the emulator:
- F2 saves a snapshot.
- F3 loads a snapshot.
- F4 loads the snapshot which was saved or loaded last; very handy 
if you need to try a difficult part of a game again and again.
- F5 disables the sound.  Oh, blissful silence!
- F6 enables the sound.
- F12 aborts the emulator immediately.
  All other keys are ignored, except Ctrl-Alt-Del, which reboots 
the computer.



                            PATH.JPP

This file acts like the PATH statement for .SNA and .ROM files.  
It must be located in the current directory or along the PATH.



                    Copying the ROM to a PC

I'm not certain of the legal status of the Spectrum ROM.  Three 
other emulators are distributed with the ROM, but one of them 
rumouredly had to be withdrawn because of it.  I'm not risking 
that.
  There are several ways to get the ROM.  A lot of people have 
asked me for a copy, and I've told a lot of people No.  I may give 
you a copy, but *only* if you can prove to me that you have a 
working Spectrum.  Do
    FOR n=0 TO 19: PRINT PEEK n: NEXT n
and mail me the result.
  If you have one which doesn't work, or which is at your parents' 
home, or whatever, please don't ask me.  You won't get the ROM and 
I'll feel bad because I hate to say no.
  The program "extract.exe" will extract the ROM from a file in 
which it is embedded.  The FTP site terminator.cc.umich.edu has 
one, in /atari/emulators/spectrum.lzh.  The file which contains 
the ROM is called specci.dat.  I haven't asked the Terminator 
moderator about the status of the ROM, and you might not care to 
either, at least not before you've downloaded it :-)
  Alternatively, save the ROM do disk using
    CLEAR 49152: FOR n=0 TO 16383: POKE n+49152,PEEK n: NEXT n
    SAVE "ROM" CODE 49152,16384
  The save syntax may be wrong for your disk drive, but you get 
the drift.  If you have a Plus D, MGT or Disciple drive you can 
use Specdisc to convert the file to a Mess-DOS file.  A program 
called 22Disk (22DSKnnn.ZIP, nnn is the version, shareware) may be 
able to copy the file to the hard disk, but anyway you can use a 
sector editor to save the entire disk to a Mess-DOS file and use 
Extract to extract the ROM from that file.  Two good sector 
editors are Norton DE and Anadisk (ANADnnn.ZIP, shareware).  To be 
able to use Anadisk the disk must have interleave 1.  Turn off 
sector headers.
  If you have a serial port for your Spectrum it's easy to 
transfer the ROM to the PC, you probably know how to if you have 
one.



                     Copying games to a PC

The easiest way is to use a Plus D/Disciple/MGT disk drive to snap 
the game, then Specdisc to convert it to .sna format.  This has 
the disadvantage that the game may detect that the Spectrum has a 
disk drive and presume that it won't disappear (which it does once 
the snapshot is run under an emulator).
  Alternatively, a Mirage Microdriver snapshot box may be used to 
snap the game, either to Microdrive or to tape.  From a Microdrive 
it's easy to transfer it to a PC via serial cable.  From tape it's 
rather hard.
  One real hacker rewrote his Spectrum ROM to snap directly to 
serial cable; he just triggers an NMI, the game is sent out and in 
the other end of the cable a COPY command or something stores the 
output directly to a snapshot file.  Not for the novice, but very 
elegant.
  Peter McGavin's emulator can read from tape via a sound sampler, 
and uses the same snapshot format as JPP.
  Another PC emulator seems to be able to read Spectrum tapes via 
the parallel port.  I've a copy of it, but the docs are in Spanish 
or Portuguese; I can't read either language.  I'd like to hear 
from someone who can.  Once I get a translation of the relevant 
docs adding tape support should be a ten-minute job.



                       The CPU emulation

My Z80 emulation code is 50-100% faster than any other Z80 
emulator I've seen on the PC.  The main reasons are that nearly 
all the Z80 registers are kept in 386 registers and that very 
little time is spent on instruction decoding.  The design is based 
on Peter McGavin's Spectrum emulator on the Amiga.
  It is perfectly possible to rewrite JPP to work on a 286, less 
than a day's work, but it would run half as fast again on a 286/16 
as this version does on a 386SX/16.  Too slow to bother, IMHO.
  The register allocation is as follows:
 Z80  386
  AF  AX       F is kept in AH, A in AL
  BC  CX
  DE  DX
  HL  BX       In BX since BX can access memory
  SP  BP
  PC  SI
IX, IY, I, R and the alternates are kept in memory.  DI is used as 
scratch register.  DS points to the Spectrum address space, ES 
points to a special bookkeeping table, FS and GS to a 128k table 
of decoded instructions.  (FS and GS don't exist on the 286.)
  All the other emulators I've seen (except Peter's) decode each 
instruction every time it is used.  I avoid that by storing the 
address of the emulation routine for each address in a special 
128k table.  FS points to a 64k segment which contains the entries 
for the even Z80 addresses, GS  - blah blah - odd.  Each opcode 
knows how long it is and whether it is located on an even or odd 
address so it can jump through the correct table.
  In order to work with self-modifying code the decoding of an 
address must be invalidated whenever it is written to.  Another 
64k table (ES) keeps track of which decodings must be invalidated 
when an address is written to.  Bit N at address M is set if the 
decoding of address M-N depends on address M, for N<4.  Bits 4..6 
are unused (0) and bit 7 is set if the address is write protected.  
Thus, an opcode which writes to eg. [di] need only
    test [byte ptr es:di],255  ;rom, or previously decoded?
    jnz fix_write_di           ;any bit set -> go fix it (slow!)
    jmp [word ptr fs:si]       ;[word ptr gs:si-1] is si is odd
  Each opcode must be emulated twice, 192K RAM must be used for 
extra tables, and the code won't run on anything smaller than a 
386SX since so many segment registers are used, but!  It is twice 
as fast as anything else.
  The only way to speed it up further is to compile and optimise, 
which could eliminate a lot of flag handling (many instructions 
affect several flags, at most one of which is actually used) and 
concatenate some instructions (eg. ld a,e; add a,7; ld e,a).  One 
possibility is to translate the Z80 code to a simple 2-register 
language, optimise the resulting code and finally interpret it.  
But would the optimised code be fast enough to offset the time 
taken to optimise it?
  To return to reality, there are some known bugs:
- The H processor flag is set incorrectly by 16-bit arithmetic 
instructions (it is the carry/borrow between bits 7 and 8, not 11 
and 12).
- The two 'unused' bits in the Z80 F register may be corrupted by 
some instructions on some processors.  The 386 seems ok but future 
Intel processors may not.
- Interrupts can occur only directly after CALL, JR, JP, RET, 
RETI, RETN and HALT instructions.
- LDIR may turn off the write protection of a few bytes at either 
end of the ROM (it resets bit 7 in ES of up to five bytes before 
the start if the destination block and one byte after its end).
- R is not quite perfectly emulated.  LD A,R loads bits 0..6 of A 
from 8253 timer 0 and bit 7 from R (set by LD R,A).
  There also is at least one (more) bug, which I am having trouble 
tracking down.  It probably has to do with flag handling.
  JPP emulates most documented and undocumented opcodes, the 
exceptions being IND, INI, INDR, INIR, OTDR, OTIR and the shift- 
with-autocopy instructions.  Instructions which aren't recognised 
abort the emulator.
  Starion uses OUTI and International Karate OUTD so they are now 
partially emulated.  B and HL are modified, but the flags aren't 
set and the port isn't written to.
  If you want the source, mail me.  It's not completely bug-free, 
but I don't think it ever will be.  It should be relatively 
painless to translate it to other CPUs, or to emulate other Z80 
micros.



                     The graphics emulation

JPP (now) runs in 320*240 16-colour mode.  Flashing is emulated by 
changing the bytes in the PC video memory rather than by changing 
the palette.
  Unfortunately I don't know terribly much about the internals 
about the VGA chips, so some computers may misbehave when JPP 
attempts to switch to 320*240*16 mode.  I made more or less the 
same changes to 320*200*16 as those which change 320*200*256 to 
320*240*256.  Please tell me if JPP behaves strangely on your 
computer.
  The fast version updates the entire PC screen from the Spectrum 
screen every 3rd interrupt (ie. the refresh frequency is 16.67Hz).  
The exact-speed version (JPP-486) updates as many lines as there 
is time to before each interrupt (ie. the refresh frequency is at 
least 2.08Hz, at most 50Hz).



                      The sound emulation

The Spectrum sound system, as you probably know, is simple.  The 
processor controls the loudspeaker level, and by raising and 
lowering it at regular intervals can make tones.
  The PC system is, for practical purposes, exactly the same.  So 
emulating the Spectrum sound system should be simple?
  No, because the PC has to sample the joystick and update the 
screen as well.  Both require rather long time slices.  Also, 
unless the instructions take exactly as long as on the real 
Spectrum, the delay loops won't work and the tones will be thrown 
off.
  The standard JPP ignores timing and just outputs the sound as 
the Spectrum program does.  Hopefully it'll sound much as 
intended.
  JPP-486 is intended to do better, but still has to sample the 
joystick and update the screen.  The method I've chosen is to try 
to get the correct interval between port writes except across 
interrupts.  For technical reasons this means that frequencies 
below approximately 160Hz won't come across very well.  'Not very 
well' indeed.  There also is a limit to how high JPP-486 can go, 
roughly proportional to the speed of the processor, and a limit to 
how accurately it can match the intended frequency.
  Since sound output requires extremely accurate timing the screen 
output is more or less suspended while the sound is being made.  
Currently the refresh frequency may be as low as 2.08Hz, but it 
would be easy to increase that limit.



                          Peripherals

The Spectrum has very little in the way of peripherals, and JPP 
emulates even less.
  On ports XXFEh, JPP emulates the keyboard on input, and the 
speaker and border on output.
  On ports XX1Fh, JPP emulates a Kempston joystick on input and 
nothing on output.  If the PC doesn't have a joystick the Kempston 
always is in the neutral position.
  On all other ports JPP returns FFh on input and ignores output.
  Since reading the PC joystick position is inordinately slow, JPP 
reads it every 0.02 second (starting when the Spectrum program 
first accesses the Kempston) and feeds the value read to the 
Spectrum whenever the Spectrum program reads the Kempston.  The 
button status is read whenever the Spectrum program wants to.



                         General Notes

There is a not very active mailing list for the Spectrum, mail 
mauricio@mozart.aero.ufl.edu to be added.  New versions of JPP 
will be announced on the list.
  You may have wondered about the name JPP.  Try typing J 
Symbolshift-P Symbolshift-P on a Spectrum; I was feeling rather 
sentimental when I named the emulator.
  This document is based on the documentation Peter McGavin wrote 
for his Spectrum emulator.  I am extremely grateful to Peter for 
all his help.
  Henk de Groot has fixed the Spectrum ROM bugs, but at least one 
game breaks on his ROM.  Unfortunately his email address is likely 
to change in the near future; Mauricio or I will know what it is.  
He has also written a program, "convert.exe", to convert snapshots 
between .sp and .sna format.  This program is enclosed.
  The joystick emulation now uses an absolute-time routine which 
should work correctly no matter how fast the processor is.  If the 
558 in your joystick interface is clocked faster or slower than 
mine (the neutral position is off-centre), tell me!  I've also 
changed the autodetect code, JPP now reads the stick and assumes 
it's there if reasonable values are returned.
  There may be some linguistic errors in this document.  Sorry 
about that, but please bear in mind that English is not my first 
language.



                        Other emulators

I have about six other emulators, and there are several that I 
don't have.  All, except where noted, are PD.  They're not easy to 
get hold of, so mail me if you want any.

PC:
  VGASPEC.EXE, originally by Alfonso Olloqui.  Needs 286+VGA, runs 
at less that half the speed of JPP.  A later version by another 
author seems to be better, but I haven't tested it yet.  The newer 
version is supposed to have tape support.  This is the one with 
the Spanish/Portuguese doc file.
  SP.EXE, untested, I've consistently forgotten to bring it home.  
CGA, I think, and a built-in debugger.
  Brian Havard wrote, but didn't release, an emulator.  Simple and 
short, slow, not developed very far since it was so slow.
  There's a Dutch emulator which I've been promised a copy of.
  There may be another emulator, someone on USENET mentioned one 
but didn't reply to my mail.  I foolishly didn't save the original 
posting.  Shareware, source available for US$25, 50% faster than 
JPP, runs on 286.

Amiga:
  Spectrum, by Peter McGavin.  Very good, JPP is based to a large 
extent on it.  Needs about a 25MHz machine to run at full speed.  
Has tape support.
  KGB.  I haven't seen it.  A bit slower than Peter's, and the 
version Peter saw wouldn't work on the Amiga 3000.
  An Italian emulator which I don't know the name of.  Excellent 
compatibility, rather fast.  May be shareware.
  Several unreleased emulators.  Peter knows more about them.

Atari ST/TT:
  One, called Spectrum.  Don't know anything about it, but the doc 
file is written in quite the worst English I've seen.  Available 
by anonymous ftp from terminator.cc.umich.edu.

Acorn Archimedes:
  A company called Arxe wrote one, intended to be commercial but 
never released because Amstrad wouldn't permit Arxe to enclose the 
ROM.
  Someone called D. Lawrence wrote another, or maybe the same.  
This one is floating around but nobody has any documentation.  I 
don't know what its status is.  Runs at about 70% of Spectrum 
speed on an ARM2, not quite perfect graphics emulation.

Commodore 64:
  The Whitby Software Spectrum simulator is a rewrite of the 
Spectrum Basic.  It will not run machine-code programs.  I don't 
know whether it's PD, shareware, or commercial.



                    The snapshot file format

This format (filetype .SNA) is the format used by the Mirage 
Microdriver "Dump" command.  It is also used by Peter McGavin's 
Spectrum emulator for the Amiga.

 Byte offset    Contents

    0          i  register
    1          l' register
    2          h' register
    3          e' register
    4          d' register
    5          c' register
    6          b' register
    7          f' register
    8          a' register
    9          l  register
   10          h  register
   11          e  register
   12          d  register
   13          c  register
   14          b  register
   15          iy low register
   16          iy high register
   17          ix low register
   18          ix high register
   19          bit 2 contains iff2
   20          r register
   21          flags register
   22          a register
   23          sp low register
   24          sp high register
   25          interrupt mode (0, 1 or 2)
   26          border colour (0..7).
 27..49178     48 kbytes ram dump

When the registers have been loaded a RETN command is required to 
start the program.
  Since Peter's emulator stores rubbish in byte 26 JPP sets the 
border to black if byte 26 is larger than 7.



         List of working programs (and some that don't)

I haven't tested them very thoroughly, most games bore me very 
quickly, but at least the title screen and the start of the first 
level work.
  NB:  I'm willing to copy only the stuff in the horizons and demos 
subdirectories.  Don't bother asking for anything else.

/spectrum/demos/cyber2.sna
/spectrum/demos/drill-de.sna
/spectrum/demos/king-dem.sna
/spectrum/demos/mean-dem.sna
/spectrum/demos/trant-de.sna
/spectrum/dontwork/batman.sna
/spectrum/dontwork/full-thr.sna
/spectrum/dontwork/ghosts.sna
/spectrum/dontwork/mugsy.sna
/spectrum/dontwork/scumball.sna
/spectrum/dontwork/sidewise.sna
/spectrum/games/1942.sna
/spectrum/games/3dtank.sna
/spectrum/games/alchemis.sna
/spectrum/games/alien8.sna
/spectrum/games/android2.sna
/spectrum/games/ant-atta.sna
/spectrum/games/arcturus.sna
/spectrum/games/arkanoid.sna
/spectrum/games/ashes.sna
/spectrum/games/atf.sna
/spectrum/games/athena.sna
/spectrum/games/aticatac.sna
/spectrum/games/atrium.sna
/spectrum/games/aufmonty.sna
/spectrum/games/automani.sna
/spectrum/games/backgamm.sna
/spectrum/games/basil.sna
/spectrum/games/batty.sna
/spectrum/games/bombjac2.sna
/spectrum/games/booty.sna
/spectrum/games/bubblebo.sna
/spectrum/games/cavelon.sna
/spectrum/games/chuckegg.sna
/spectrum/games/commando.sna
/spectrum/games/cookie.sna
/spectrum/games/cyber.sna
/spectrum/games/cyberun.sna
/spectrum/games/cyclone.sna
/spectrum/games/daley-d1.sna
/spectrum/games/daley-d2.sna
/spectrum/games/darkside.sna
/spectrum/games/darkstar.sna
/spectrum/games/deathcha.sna
/spectrum/games/defender.sna
/spectrum/games/dictator.sna
/spectrum/games/draughts.sna
/spectrum/games/dustin.sna
/spectrum/games/dynadan1.sna
/spectrum/games/dynadan2.sna
/spectrum/games/eaglenes.sna
/spectrum/games/elite.sna
/spectrum/games/enduro.sna
/spectrum/games/exodus.sna
/spectrum/games/exolon.sna
/spectrum/games/fist.sna
/spectrum/games/force.sna
/spectrum/games/fp.sna
/spectrum/games/froggy.sna
/spectrum/games/g-force.sna
/spectrum/games/galaxian.sna
/spectrum/games/garfield.sna
/spectrum/games/gauntlet.sna
/spectrum/games/gunfrght.sna
/spectrum/games/gyroscop.sna
/spectrum/games/harrier.sna
/spectrum/games/headball.sna
/spectrum/games/headroom.sna
/spectrum/games/heathrow.sna
/spectrum/games/highway.sna
/spectrum/games/hobbit.sna
/spectrum/games/horace.sna
/spectrum/games/ikari.sna
/spectrum/games/is-chess.sna
/spectrum/games/jetpac.sna
/spectrum/games/jsw.sna
/spectrum/games/karate.sna
/spectrum/games/knightlo.sna
/spectrum/games/kokotoni.sna
/spectrum/games/kong.sna
/spectrum/games/kosmic.sna
/spectrum/games/krakout.sna
/spectrum/games/lazerzne.sna
/spectrum/games/lemans.sna
/spectrum/games/lightfor.sna
/spectrum/games/lunarjet.sna
/spectrum/games/madmix.sna
/spectrum/games/manicmin.sna
/spectrum/games/matchpoi.sna
/spectrum/games/maze.sna
/spectrum/games/meteor.sna
/spectrum/games/mission.sna
/spectrum/games/monty-mo.sna
/spectrum/games/mugsy.sna
/spectrum/games/necropol.sna
/spectrum/games/nifty.sna
/spectrum/games/nightgun.sna
/spectrum/games/orbiter.sna
/spectrum/games/orbix.sna
/spectrum/games/pacland.sna
/spectrum/games/pacmania.sna
/spectrum/games/penetrat.sna
/spectrum/games/phenix.sna
/spectrum/games/pioneer.sna
/spectrum/games/pssst.sna
/spectrum/games/rambo-3.sna
/spectrum/games/ranarama.sna
/spectrum/games/renegade.sna
/spectrum/games/rollingt.sna
/spectrum/games/sabre.sna
/spectrum/games/sam-spad.sna
/spectrum/games/sam-stoa.sna
/spectrum/games/samfox.sna
/spectrum/games/scooby.sna
/spectrum/games/scrabble.sna
/spectrum/games/sentinel.sna
/spectrum/games/sherlock.sna
/spectrum/games/sidearms.sna
/spectrum/games/sirfred.sna
/spectrum/games/skiing.sna
/spectrum/games/spiders.sna
/spectrum/games/spindizy.sna
/spectrum/games/spyvsspy.sna
/spectrum/games/st-berna.sna
/spectrum/games/star-rai.sna
/spectrum/games/starion.sna
/spectrum/games/starquak.sna
/spectrum/games/survivor.sna
/spectrum/games/talk-che.sna
/spectrum/games/tech-ted.sna
/spectrum/games/tempest.sna
/spectrum/games/terra.sna
/spectrum/games/tetris.sna
/spectrum/games/thing.sna
/spectrum/games/thingbb.sna
/spectrum/games/thunder.sna
/spectrum/games/thunderc.sna
/spectrum/games/tll.sna
/spectrum/games/tomahawk.sna
/spectrum/games/train-ga.sna
/spectrum/games/transam.sna
/spectrum/games/trantor.sna
/spectrum/games/trashman.sna
/spectrum/games/tron.sna
/spectrum/games/uridium.sna
/spectrum/games/virus.sna
/spectrum/games/wally.sna
/spectrum/games/warlord.sna
/spectrum/games/wheelie.sna
/spectrum/games/whodunit.sna
/spectrum/games/xevious.sna
/spectrum/games/zeus.sna
/spectrum/games/zynaps.sna
/spectrum/games/zzoom.sna
/spectrum/horizons/bubbleso.sna
/spectrum/horizons/characte.sna
/spectrum/horizons/draw.sna
/spectrum/horizons/evolutio.sna
/spectrum/horizons/life.sna
/spectrum/horizons/mon.sna
/spectrum/horizons/montecar.sna
/spectrum/horizons/wall.sna
/spectrum/horizons/waves.sna
/spectrum/test/buggy.sna
/spectrum/test/cheqflag.sna
/spectrum/test/editamon.sna
/spectrum/test/firelord.sna
/spectrum/test/flyshark.sna
/spectrum/test/ground.sna
/spectrum/test/imposbal.sna
/spectrum/test/impossib.sna
/spectrum/test/thrust2.sna

  The games that don't work either use an unknown opcode, (eg. 
Batman, DD CD), non-emulated hardware (eg. Sidewize, port 40FF), 
are faulty snaps (Scumball, probably), or fail for some other 
reason.  I believe there still is at least one emulation bug, 
probably in a memory store instruction.



                            History

  Beta 1
  First release available via anonymous FTP.

  Beta 2
  New joystick routine which doesn't need calibration.
  New joystick autodetect, modeled after Info+ v1.50.
  LD A,R randomises the lower 7 bits of A after loading R into A.
  The two unused flag bits are preserved during RLC (IX+d).
  All jump destinations are placed on even addresses; supposed to 
be slightly faster on the 386SX.
  The border colour is read correctly from snapshots.
  JPP aborts if run on a 286 or smaller.
  "convert.exe" added.

  Beta 3
  Partial OUTI emulation added to make Starion run.  Full 
emulation would be too slow.
  "extract.exe" added.
  Backtracking added, but disabled due to strange crashes.
  "Out of memory" handled gracefully.
  IN {B,C,D,E,H,L},(C) store the result in the correct register, 
not in A.
  Switched to 16-colour mode; flicker-free and slightly faster.  
  The normal colours have been brightened slightly.
  A Kempston is always emulated, but on PCs without a joystick it 
always is in the neutral position.
  Some idiot (me) made the 386 stack pointer point to the Spectrum 
ROM a very short while.  Not any more.
  JPP now doesn't use any 386-specific instructions until it has 
checked that the processor actually is a 386.
  "specdisc.exe" added.

  Beta 4
  Changed to a different CPU test; the old one crashed on at least 
two systems.
  Reenabled VGA-present test; the old CPU test made it crash.
  Carved backtracking completely out of the code.
  Fixed another bug in IN r,(C); carry and the two unused flag 
bits are preserved.
  Fixed a bug which prevented more than 50% of the screen from 
flashing at the same time.  Speeded up the flash routine.
  Fixed a truly horrible bug.  A routine was declared near but 
called far, and so left two bytes on the stack after each 
invocation, eventually overflowing the stack.  Bad shit.
  *Really* fixed IN r,(C); the previous fix cancelled the one 
before.
  Finally wrote the exact-speed version.  No tape support yet and 
it's horrible on my machine (a 16Mhz 386SX), but it may work on 
fast enough machines.  Or again it may not.
  Fixed a bug whereby SLA (HL) rotated a random bit into bit 0.
  Fixed a bug in JPP-486 HALT; the clock counters weren't updated.  
Now the counters are updated and the normal speed control systems 
handles the HALTing.
  Rewrote the sound frequency control system; I stupidly made the 
sound at the correct spot in the 50Hz time slice, wasting time 
until it arrived.
  Added a hack to update the whole screen immediately whenever an 
LDIR has destination 4000h or 5800h.
  Added OUTD (partially) so International Karate will run.
  Changed startup code slightly.
  Added register and memory dump when the emulator aborts.



                              Todo
                 (don't seem to ever get done)

- Implement disk support by breakpointing the ROM save/load 
routines.
- Label the function keys along the top of the screen.
- Implement a help screen on F1 with a picture of a Spectrum 
keyboard.
- Add tape support to the exact-speed version.
- Find out why JPP won't run after BC++ 3.0 has been run.
- Fix Pause.
- Find out why JPP-486 responds like a dead log to keypresses when 
sound is being made.
