home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fresh Fish 2
/
FFMCD02.bin
/
new
/
misc
/
emu
/
z80
/
z80_coding.i
< prev
next >
Wrap
Text File
|
1993-12-21
|
8KB
|
352 lines
** Definitions for coding of Z80 instruction routines.
** (Macros and register aliases.)
** =====================================================================
** Registers:
** D0 00 A' 00 A A0 TableBase/Work
** D1 00 B' 00 B A1 Pseudo-PC
** D2 00 C' 00 C A2 Z80 SP (high word is garbage)
** D3 00 D' 00 D A3 Z80 address zero
** D4 00 E' 00 E A4 CacheBase
** D5 scratch H L A5 FlagsBase
** D6 scratch saveCCR A6 InstructionBase
** D7 --- scratch --- A7 User Stack Pointer
** Aliases:
A EQUR d0
B EQUR d1
C EQUR d2
D EQUR d3
E EQUR d4
L EQUR d5 ;To indicate byte access
HL EQUR d5 ;To indicate word access
TableB EQUR a0 ;pointer to TableBase
Work EQUR a0 ;pointer to the Z80_Workspace longword
PPC EQUR a1 ;Pseudo-PC
ZSP EQUR a2 ;Z80 Stack Pointer (only lower word used)
Z0 EQUR a3 ;pointer to Z80 address zero
CacheB EQUR a4 ;pointer to CacheBase (corresponding to Z0)
FlagsB EQUR a5 ;pointer to FlagsBase (corresponding to Z0)
InstrB EQUR a6 ;pointer to InstructionBase
** The memory handler refers to most of the base pointers, by their
** aliases. The only address registers that can be used as scratch pads
** are PPC and ZSP, so I'd like them to remain in a1 and a2. If they are
** moved, changes must be done in the memory handler.
** Remember: if you change this, you must also change the labels
** in the Z80_RegStorage table in Z80_struct.i.
** ======================================================================
IFD VERBOSE
LIST
** Compiling the Z80_coding.i file.
NOLIST
ENDC
** Macros and local labels:
**
** Make sure any labels within a macro are truly unique, especially
** if the macro might be repeated between global labels.
** Let local labels be on the form "<number>$", where <number>
** is > 100 in "utility" macros. Local labels in instruction routines
** (or macros defining such routines) that are on that form should have
** <number> less than 100.
** If a macro could be called more than once between global labels, and
** the macro must contain local labels, those labels must be unique for
** each macro call (between global labels), but may not be global since
** that would undefine any other local labels. Standard local labels
** (<number>$) can't be auto-generated, since the macro 'parameter' \@
** expands to "_<number>" (plain stupid, if you ask me).
** My solution (while I can't use Devpac-style local labels here),
** is to use an extra parameter (the last) to specify a "usage number"
** to be joined with the local label numbers, i.e. "<number>\3$".
** This is certainly ugly, but it will work.
** Reserved digit sequences:
** 100-110 testreq
** (111-119)... putz (i.e. anything beginning with 111 to 119.)
** 200-210 opcode_2_bytes
** 300-310 opcode_3_bytes
** End of instruction, execute next.
next MACRO
move.w (PPC)+,d7
jmp (InstrB,d7.w)
ENDM
** ----
** Test for requests. Has a built-in "next" function.
** May only occur once in an instruction routine.
testreq MACRO
move.w Z80_Request(TableB),d7
bne.s 102$ ;skip if no request
101$ move.w (PPC)+,d7
102$ jmp (InstrB,d7.w)
ENDM
;101$ is supposed to be a known entry point used to
;exit to next instruction without testing requests.
;Most jumps/calls use this "feature".
** ----
** Read from z80 memory. Address is a register.
getz MACRO ;address,value
move.b (Z0,\1.w),\2
ENDM
** ----
** Write a byte to memory, marking the cache pointer 'changed'.
** Address is a register. Memory flags are not checked here. See putz.
IFD UPDATECACHE
writemem MACRO ;value,address
move.b \1,(Z0,\2.w)
add.w \2,CacheB
clr.w (CacheB,\2.w)
sub.w \2,CacheB
ENDM
ELSE
writemem MACRO ;value,address
move.b \1,(Z0,\2.w) ;write to z80 memory
ENDM
IFD VERBOSE
LIST
** Writemem does not mark the cache pointer.
NOLIST
ENDC
ENDC ;IFD UPDATECACHE
** ----
** Write to z80 memory. Address is a register.
IFND Z80_MEMCHECK
putz MACRO ;value,address
writemem <\1>,<\2>
ENDM
ELSE
** As above, but do address exception testing.
** May occur several times in a single instruction routine,
** therefore, calls beyond the first must specify a "usage number"
** (preferably a single digit).
putz MACRO ;value,address[,use]
tst.b (FlagsB,\2.w)
beq.s 111\3$
move.w \2,-(sp)
move.b \1,-(sp)
jsr memhandler(InstrB)
addq.l #4,sp
bra.s 112\3$
111\3$ writemem <\1>,<\2>
112\3$
ENDM
;If the handler is called, the write part is skipped. If
;the value should be written, the handler will do it.
;When the memory handler is reached, the stack should
;look like this:
; sp+6 word address
; byte padding (caused by move.b to stack)
; sp+4 byte value
; sp-> long return address
WRITE_ADDR = 6 ;the offsets used by memhandler
WRITE_VAL = 4
ENDC ;IFND Z80_MEMCHECK
** ----
** Word-sized Increment
incw MACRO ;dest
addq.w #1,\1
ENDM
** ----
** Word-sized decrement
decw MACRO ;dest
subq.w #1,\1
ENDM
** ----
** Byte-sized increment
incb MACRO ;dest
addq.b #1,\1
ENDM
** ----
** Byte-sized decrement
decb MACRO ;dest
subq.b #1,\1
ENDM
** ----
** Move PPC 'count' words forward. (Max 4)
skip MACRO ;count
addq.l #2*(\1),PPC
ENDM
** ----
** Calculate the real 16-bit Z80 PC (result in d7).
getRPC MACRO
move.l PPC,d7
sub.l CacheB,d7
lsr.l #1,d7
ENDM
** ----
** Make new PPC from the Real PC in d7.
** PPC=CacheB+2*(extended d7.w)
makePPC MACRO
lea (CacheB,d7.w),PPC
add.w d7,PPC
ENDM
** ----
** Test parity. Bits 8-15 must be zero.
parity MACRO ;register
or.b Z80_Parity(TableB,\1.w),d6
ENDM
** ----
** Store the status register / condition code register.
;Move from SR is privileged on 68010 and higher. On those,
;use Move from CCR (which doesn't exist on 68000).
IFNE PROCESSOR<68010
putsr MACRO ;dest
move SR,\1
ENDM
IFD VERBOSE
LIST
** putsr uses Move from SR.
NOLIST
ENDC
ELSE
putsr MACRO ;dest
move CCR,\1
ENDM
IFD VERBOSE
LIST
** putsr uses Move from CCR.
NOLIST
ENDC
ENDC ;IFND CCR_VERSION
** ----
** Load the condition code register from d6.
getsr MACRO
move d6,CCR
ENDM
** ----
** Make a word of two bytes. Result in d7.
join MACRO ;High,Low
move.b \1,(Work)
move.w (Work),d7
move.b \2,d7
ENDM
** ----
** Index register + offset to d7. Offset is always the third byte.
** The PPC has been increased by one.
index MACRO ;X or Y
getRPC
incw d7
getz d7,d7
ext.w d7
add.w Z80_I\1(TableB),d7
ENDM
** ----
** Execute macro/instruction with all r but H as parameter.
do_r MACRO ;instruction
\1 A
\1 B
\1 C
\1 D
\1 E
\1 L
ENDM
** ----
** Execute macro/instruction with B,C and D,E as parameters.
do_ss MACRO ;instruction
\1 B,C
\1 D,E
ENDM
** ----
** Execute macro/instruction with X and Y as parameter
do_xy MACRO ;instruction
\1 X
\1 Y
ENDM
** ----
** Test multi-byte opcodes for modified code.
** Only negative cache values are allowed for the second and third
** bytes of the opcode.
** This tests the instructions on the form
** prefix (DD/CB)
** opcode
** [offset]
** [data]
;May only occur once in an instruction routine
IFD MODIFIEDCODE
opcode_2_bytes MACRO
tst.w (PPC)
bmi.s 201$
jmp stale_ptr(InstrB)
201$
ENDM
ELSE
opcode_2_bytes MACRO
;do nothing
ENDM
IFD VERBOSE
LIST
** No tests for modified code in 2-byte opcodes are made.
NOLIST
ENDC
ENDC ;IFD MODIFIEDCODE
** This tests the instructions on the form
** prefix (DD/FD)
** prefix (CB)
** offset
** opcode
;May only occur once in an instruction routine
IFD MODIFIEDCODE
opcode_3_bytes MACRO
move.w (PPC),d7
or.w 4(PPC),d7
bmi.s 301$
jmp stale_ptr(InstrB)
301$
ENDM
ELSE
opcode_3_bytes MACRO
;do nothing
ENDM
IFD VERBOSE
LIST
** No tests for modified code in 3-byte opcodes are made.
NOLIST
ENDC
ENDC ;IFD MODIFIEDCODE
** =======================================================================