home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fresh Fish 2
/
FFMCD02.bin
/
new
/
misc
/
emu
/
z80
/
z80.a
< prev
next >
Wrap
Text File
|
1993-12-21
|
27KB
|
839 lines
** Main file of the Z80 emulator. Compiles to linkable code, using the
** following settings:
** VERBOSE
** Boring Messages During Compilation.
PROCESSOR EQU 68030
** Define to any of 68000, 68010, 68020, 68030 or 68040. The 68000 version
** uses the Move from Status Register instruction. Presently, the > 68000
** versions are all the same.
** GENERIC_OBJECT SET 1
** Define to compile generic Z80 emulator object file, which needs
** linking with separately compiled routines for implementation-
** dependent instructions. If not defined, macros from "machine_macs.i"
** are used and are inline expanded. See the files "extern_instr.a" and
** "impldept.i" for more information about this.
Z80_MEMCHECK SET 1
** Define to use memory write access checking.
** See MemoryHandler below for more information about this.
UPDATECACHE SET 1
** Define to update the cache on every write to Z80 memory. This is done
** by simply clearing the corresponding word in the cache. If this option
** is not used, modified code will never work.
MODIFIEDCODE SET 1
** Define to detect (and allow) modified code even in multi-byte opcodes.
** Pretty damn useless if UPDATECACHE is not defined. If this option is
** not used, then such modifications that only change the second or third
** bytes of an opcode, but not the first byte, will not be detected.
** UNDOCINSTR_UNDEF SET 1
** Define if you want the "undocumented" instructions to be considered
** as undefined instructions.
BCDFLAGS
** Define if you want the arithmetic instructions to store information
** so that a following Daa will work correctly (see the file "notes.txt"
** for details). BASIC interpreters and other programs that work in
** decimal base often use BCD, while most games do not. The main use there
** seems to be for score counter displays.
** If this flag is not defined, then calling the Daa instruction will
** write a nonzero value into the Z80_BCD_OP field, which otherwise will
** always be zero. That way it should be easy to see if it is the missing
** BCD handling that causes any erroneous behaviour.
** AFPUSHPOP_CCR
** Define if you want the Push/Pop AF instructions to store the F register
** on 680x0 CCR form, instead of the real Z80 form. The difference lies in
** how the flags are ordered within the byte. For instance, in the 680x0,
** bit 3 is the sign flag; in the Z80, it is bit 7. Only programs that
** inspect the pushed flags (like a debugger) will ever notice this. The
** CCR version is, of course, a bit quicker, and could be used for games.
** In neither case are bits in the unused positions (including H and N)
** guaranteed to survive an operation that affects any of the flags.
** Is IS guaranteed, that a Pop AF with a following Push AF (or vice versa)
** and no flag-affecting instructions there inbetween, will preserve all
** the transferred bits.
** AFPUSHPOP_BCD
** Define if you want the Push/Pop AF instructions to preserve BCD data.
** If used, the information used for BCD will be stored separately in an
** internal circular stack that keeps the last 7 pushed data units.
** The time penalty is reasonable, but this option is hardly ever needed.
** (Interrupts could be a problem. See the file "notes.txt" for details.)
** For game-playing only, this should definitely be turned off. Many
** games use Push/Pop AF/BC/DE/HL/IX/IY to transfer graphics data quickly.
** ======================================================================
** Register aliases used (see the file Z80_coding.i for definitions):
** TableB pointer to TableBase
** Work pointer to the Z80_Workspace longword
** PPC Pseudo-PC
** ZSP Z80 Stack Pointer (only lower word used)
** Z0 pointer to Z80 address zero
** CacheB pointer to CacheBase (corresponding to Z0)
** FlagsB pointer to FlagsBase (corresponding to Z0)
** InstrB pointer to InstructionBase
** Be careful!! Some aliases might stand for the same register!
** (TableB and Work are presently the same.)
** ---------------------------------------------------------------------
Z80_MAIN = -1 ;Tell include file we are compiling the main file.
INCLUDE user.i ;User definitions. ALWAYS included first of all.
INCLUDE Z80.i
INCLUDE Z80_struct.i
INCLUDE Z80_coding.i
INCLUDE tables.i
INCLUDE helpfuncts.i
** ----------------------------------------------------------------------
** When calling Z80_Init, Z80_Coldstart or Z80_Continue, a pointer to the
** control structure is always passed in a0, and a return value is passed
** in d0. All other registers are automatically protected
ProtectedRegs REG d1-d7/a1-a6 ;push/pop these at entry/exit
** Registers stored at Z80_RegStorage at exit,
** and restored upon continuing:
StoredRegs REG d0-d5/a2-a6
;a0 (TableB) always comes as a parameter.
;a1 (PPC) is recalculated from Real-PC at Continue.
;d6 is recalculated from F at Continue.
;d7 is garbage anyway.
** Remember: if you change this, you must also change the labels
** in the Z80_RegStorage table in Z80_struct.i.
** ======================================================================
** EMULATOR ENTRY POINTS
** Before beginning emulation, the control structure must be initialised
** by calling Z80_Init.
** a0 must point to the control structure. The fields Z80_Memory and
** Z80_Cachemem must be pointing to allocated memory.
** If the memory write access checking feature is used, the field
** Z80_Flagmem must also be set, and if Z80_MemHandler is nonzero
** it is supposed to point to a user memory exception handler. See
** MemoryHandler below for details.
** The user environment data area is not changed. All other fields
** are automatically initialised to zero.
** The return value in d0 is nonzero if an error occurred, and zero
** otherwise. All other registers are automatically protected.
Z80_Init
movem.l a0/a1/a2,-(sp) ;temporaries
;Save the protected control structure entries on the stack:
move.w #(PROT_SIZE>>1)-1,d0 ;word count
lea PROT_FIELDS(a0),a2 ;source ptr in a2
.prot_save move.w (a2)+,-(sp)
dbf d0,.prot_save
;Then clear all entries below envdata:
move.l a0,a1
move.w #(Z80_Envdata>>1)-1,d0 ;envdata offset is even
.clr_struct clr.w (a1)+
dbf d0,.clr_struct
;and restore the saved entries (a2 has retained its value):
move.w #(PROT_SIZE>>1)-1,d0 ;word count
.prot_rest move.w (sp)+,-(a2)
dbf d0,.prot_rest
;Set all entries in the cache (skipping the low end buffer)
;to 'changed', that is, not decoded:
move.l Z80_Cachemem(a0),a1
add.l #Z80_LBUFSIZE,a1
move.l #Z80_MEMSIZE,d0 ;word count
.clr_cache clr.w (a1)+
subq.l #1,d0 ;possibly too large to use dbf
bne.s .clr_cache
;(a1 should now point to the first entry in the high buffer)
;Set all entries in the high buffer to 'out of bounds':
move.w #(Z80_HBUFSIZE>>1)-1,d0 ;buffers are even sized
.set_hibuf move.w #out_of_bounds,(a1)+
dbf d0,.set_hibuf
;Now copy the tables to their places in the structure:
;The parity table
lea ParityTable(pc),a1
lea Z80_Parity(a0),a2
move.w #256-1,d0
.cp_parity move.b (a1)+,(a2)+
dbf d0,.cp_parity
;Calculate the 'address zero' pointers:
move.l Z80_Memory(a0),a1
add.l #Z80_0_OFFSET,a1
move.l a1,Z80_zero(a0)
move.l Z80_Cachemem(a0),a1
add.l #CACHE_0_OFFSET,a1
move.l a1,Z80_cachezero(a0)
IFD Z80_MEMCHECK
move.l Z80_Flagmem(a0),a1
add.l #FLAGS_0_OFFSET,a1
move.l a1,Z80_flagzero(a0)
ENDC
;Create an initial "saved CPU status" frame, so we can
;call Z80_Continue without calling Z80_Coldstart first.
movem.l ProtectedRegs,-(sp)
bsr InitRegisters ;(only use aliases from now)
;Initially look like after a reset.
move.l CacheB,PPC ;PC = address zero
move.b #-1,Z80_INTMOD(TableB) ;Intmode 0
movem.l StoredRegs,Z80_RegStorage(TableB)
movem.l (sp)+,ProtectedRegs
movem.l (sp)+,a0/a1/a2 ;restore temporaries
moveq #0,d0 ;signal 'no error'
rts
** ----------------------------------------------------------------------
** Enter here to start emulation 'from scratch', with a CPU reset.
** a0 must point to the control structure, which must be initialised
** (see Z80_Init above).
** The return value in d0 is nonzero if a