diff options
| author | Astrid Smith | 2011-10-21 01:07:19 -0700 |
|---|---|---|
| committer | Astrid Smith | 2011-10-21 01:07:19 -0700 |
| commit | 541bce94a4d73e754ce522758dd25ecddb818f04 (patch) | |
| tree | 6bca458ce09cc2b9470410bae62b74a747733165 /flags.s | |
| parent | ef89049eae1d7e2591bef44a3e8151131fb4bed2 (diff) | |
First stage of converting to be GAS-compliant
I (think I) have converted all the A68k directives to their GAS
equivalents. Still remaining are all the inline expressions.
Diffstat (limited to 'flags.s')
| -rw-r--r-- | flags.s | 315 |
1 files changed, 315 insertions, 0 deletions
@@ -0,0 +1,315 @@ + ;; Routine to set the given flags + ;; Noted in \mask by a 1 bit +.macro F_SET mask ; 32 cycles, 8 bytes + or.b \mask,flag_byte-flag_storage(a3) + or.b \mask,flag_valid-flag_storage(a3) +.endm + + ;; Clear the given flags + ;; Noted in \mask (must be a reg) by a 1 bit +.macro F_CLEAR mask ; 36 cycles, 10 bytes + or.b \mask,flag_valid-flag_storage(a3) + not.b \mask + and.b \mask,flag_byte-flag_storage(a3) +.endm + + ;; Use this when an instruction uses the P/V bit as Parity. + ;; Sets or clears the bit explicitly. + ;; + ;; Byte for which parity is calculated must be in \byte. High + ;; byte of \byte.w must be zero, using d0 is suggested. (a0,d1 + ;; destroyed) + +.macro F_PAR byte + ori.b #%00000100,flag_valid-flag_storage(a3) + move.b flag_byte(pc),d1 + andi.b #%11111011,d1 + lea lut_parity(pc),a0 + or.b 0(a0,\byte.w),d1 + move.b d1,flag_byte-flag_storage(a3) +.endm + + + ;; Use this when an instruction uses the P/V bit as Overflow. + ;; Leaves the bit itself implicit; simply marks it dirty. +.macro F_OVFL ; 20 cycles, 6 bytes + andi.b #%11111011,flag_valid-flag_storage(a3) +.endm + + ;; Save the two operands from ADD \1,\2 +.macro F_ADD_SAVE src dst + move.b \src,f_tmp_src_b-flag_storage(a3) + move.b \dst,f_tmp_dst_b-flag_storage(a3) + move.b #$01,f_tmp_byte-flag_storage(a3) + F_SET #% +.endm + + + +.text + + ;; Normalize and return inverse of emulated Carry bit (loaded + ;; into host zero flag) + + ;; Destroys d1 +f_norm_c: + move.b flag_valid-flag_storage(a3),d1 +; d1 is destroyed in all cases, so you can use lsr and the C bit (same speed, smaller) + lsr.b #1,d1 + bcs.s FNC_ok ; Bit is valid + move.b (f_host_sr+1)-flag_storage(a3),d1 + andi.b #%00000001,d1 + or.b d1,flag_byte-flag_storage(a3) + ori.b #%00000001,flag_valid-flag_storage(a3) +FNC_ok: + move.b flag_byte-flag_storage(a3),d1 + andi.b #%00000001,d1 + rts + + ;; Normalize and return **INVERSE** of emulated Zero bit + ;; (loaded into host's zero flag) + + ;; Destroys d1 +f_norm_z: + move.b flag_valid-flag_storage(a3),d1 + andi.b #%01000000,d1 + bne.s FNZ_ok ; Bit is valid + bsr flags_normalize +FNZ_ok: + move.b flag_byte-flag_storage(a3),d1 + andi.b #%01000000,d1 + rts + + ;; Normalize and return **INVERSE** of emulated Parity/oVerflow + ;; bit (loaded into host zero flag) + + ;; Destroys d1 +f_norm_pv: + move.b flag_valid-flag_storage(a3),d1 + andi.b #%00000100,d1 + bne.s FNPV_ok ; Bit is already valid + bsr flags_normalize +FNPV_ok: + move.b flag_byte-flag_storage(a3),d1 + andi.b #%00000100,d1 + rts + + ;; Calculate the P/V bit as Parity, for the byte in + ;; d1. Destroys d0,d1. +f_calc_parity: + andi.w #$ff,d1 + move.b lut_parity-flag_storage(a3,d1.w),d1 + move.b (flag_byte),d0 + and.b #%11110111,d0 + or.w #%0000100000000000,d0 + or.b d1,d0 + move.w d0,flag_byte-flag_storage(a3) + rts + + ;; Routine to make both the Carry and Half-Carry flags valid. + ;; Trashes d0, d1. +f_calc_carries: + ;; XXX do this + ;; if f_tmp_byte == 0 { + ;; return, shit is valid + ;; } else if f_tmp_byte == 2 { + ;; // it's a word + ;; add f_tmp_src_w to f_tmp_dst_w + ;; low bytes only, create a carry and save + ;; then high bytes, create a carry and output + ;; then 3rd nibble, create a half-carry and output + ;; } else if f_tmp_byte == 3 { + ;; // it's a byte + ;; add f_tmp_src_b to f_tmp_dst_b + ;; create a carry and output + ;; add low nybbles only + ;; create a half-carry and output + ;; } + ;; set f_tmp_byte = 0 + pushm d2-d5 ; how many registers do I need? + move.b f_tmp_byte(pc),d0 + bne f_cc_dirty + rts +f_cc_dirty: + cmpi.b #2,d0 + bne f_cc_byte + ;; it's a word! + move.w f_tmp_src_w(pc),d2 + move.w f_tmp_dst_w(pc),d3 + move.w d3,d4 + add.w d2,d3 + move sr,d5 + andi.w #1,d5 + rol #8,d5 + andi.w #$0fff,d2 + andi.w #$0fff,d4 + add.w d2,d4 + andi.l #$1000,d4 + ori.w #%00010001,d5 + or.w d4,d5 + or.w d5,flag_byte-flag_storage(a3) + clr.b f_tmp_byte-flag_storage(a3) + popm d2-d5 + rts +f_cc_byte: + move.b f_tmp_src_b(pc),d2 + move.b f_tmp_dst_b(pc),d3 + move.b d3,d4 + add.b d2,d3 + move sr,d5 + andi.b #1,d5 + andi.b #$0f,d2 + andi.b #$0f,d4 + add.b d2,d4 + andi.b #$10,d4 + or.b d4,d5 + or.b d5,flag_byte-flag_storage(a3) + clr.b f_tmp_byte-flag_storage(a3) + or.b #%00010001,flag_valid-flag_storage(a3) + popm d2-d5 + rts + + ;; Normalize and return inverse of emulated Sign bit (loaded + ;; into host zero flag). + + ;; Destroys d1 +f_norm_sign: + move.b flag_valid-flag_storage(a3),d1 + andi.b #%01000000,d1 + bne.s FNsign_ok ; Bit is already valid + bsr flags_normalize +FNsign_ok: + move.b flag_byte-flag_storage(a3),d1 + andi.b #%01000000,d1 + rts + + ;; Routine to turn 68k flags into z80 flags. +flags_normalize: + move.b (f_host_sr+1)(pc),d1 ; 8/4 + ;; .w keeps d1 clean + andi.w #%00011111,d1 ; 8/4 + + ;; doesn't this invalidate the previous contents of d1 + ;; entirely? + move.b lut_ccr(pc,d1.w),d1 ; 10/4 + move.b flag_valid(pc),d0 + not.b d0 + and.b d0,d1 ; Mask out all the unwanted bits + not.b d0 + ori.b #%11000101,d0 ; These are the z80 flag register bits that can be derived from the 68k CCR. + move.b d0,flag_valid-flag_storage(a3) + or.b d1,flag_byte-flag_storage(a3) + rts + + ;; Routine to completely fill the flags register +flags_all: + bsr flags_normalize + bsr f_calc_carries + rts + + + +.data +flag_storage: + ;; 0 if the flag is already valid + ;; 2 if tmp_???b is valid + ;; 3 if tmp_???w is valid +f_tmp_byte: .byte 0 + + ;; 2 if P is 0 + ;; 3 if P is 1 + ;; 4 if P is uncalculated Parity + ;; 5 if P is uncalculated oVerflow +f_tmp_p_type: .byte 0 + + ;; byte operands +f_tmp_src_b: .byte 0 +f_tmp_dst_b: .byte 0 +f_tmp_result_b: .byte 0 + +.even +f_tmp_src_w: .word 0 +f_tmp_dst_w: .word 0 +f_tmp_result_w: .word 0 + + ;; 000XNZVC +.even + ;; DO NOT REARRANGE THESE +f_host_sr: .word 0 +f_host_ccr: .byte 0 ;XXX make overlap somehow? + +.even + ;; DO NOT REARRANGE THESE. +flag_byte: .byte 0 ; Byte of all flags +flag_valid: .byte 0 ; Validity mask -- 1 if valid. + + + ;; LUT for the CCR -> F mapping +lut_ccr: + ;; N =S + ;; Z = Z + ;; V ~ P + ;; C= C + ;; + ;; =CCR= == z80== + ;; XNZVC SZ5H3PNC + .byte %00000000 ;; 00000 00000000 + .byte %00000001 ;; 00001 00000001 + .byte %00000100 ;; 00010 00000100 + .byte %00000101 ;; 00011 00000101 + .byte %01000000 ;; 00100 01000000 + .byte %01000001 ;; 00101 01000001 + .byte %01000100 ;; 00110 01000100 + .byte %01000101 ;; 00111 01000101 + .byte %10000000 ;; 01000 10000000 + .byte %10000001 ;; 01001 10000001 + .byte %10000100 ;; 01010 10000100 + .byte %10000101 ;; 01011 10000101 + .byte %11000000 ;; 01100 11000000 + .byte %11000001 ;; 01101 11000001 + .byte %11000100 ;; 01110 11000100 + .byte %11000101 ;; 01111 11000101 + .byte %00000000 ;; 10000 00000000 + .byte %00000001 ;; 10001 00000001 + .byte %00000100 ;; 10010 00000100 + .byte %00000101 ;; 10011 00000101 + .byte %01000000 ;; 10100 01000000 + .byte %01000001 ;; 10101 01000001 + .byte %01000100 ;; 10110 01000100 + .byte %01000101 ;; 10111 01000101 + .byte %10000000 ;; 11000 10000000 + .byte %10000001 ;; 11001 10000001 + .byte %10000100 ;; 11010 10000100 + .byte %10000101 ;; 11011 10000101 + .byte %11000000 ;; 11100 11000000 + .byte %11000001 ;; 11101 11000001 + .byte %11000100 ;; 11110 11000100 + .byte %11000101 ;; 11111 11000101 + + ;; 256-byte LUT for the Parity bit. + ;; Keep this last so all storage references require only one + ;; extension word. + ;; + ;; This table taken from another z80 emulator +lut_parity: + .byte 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4 + .byte 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0 + .byte 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0 + .byte 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4 + .byte 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0 + .byte 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4 + .byte 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4 + .byte 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0 + .byte 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0 + .byte 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4 + .byte 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4 + .byte 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0 + .byte 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4 + .byte 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0 + .byte 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0 + .byte 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4 + + ;; To save space I might be able to overlay the Parity table + ;; with the CCR table, or even interleave it in the opcodes. + + |
