1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
|
;; N =S
;; Z = Z
;; V ~ P
;; C= C
;;
;; =CCR= == z80==
;; XNZVC SZ5H3PNC
;; 00000 00000000
;; 00001 00000001
;; 00010 00000100
;; 00011 00000101
;; 00100 01000000
;; 00101 01000001
;; 00110 01000100
;; 00111 01000101
;; 01000 10000000
;; 01001 10000001
;; 01010 10000100
;; 01011 10000101
;; 01100 11000000
;; 01101 11000001
;; 01110 11000100
;; 01111 11000101
;; 10000 00000000
;; 10001 00000001
;; 10010 00000100
;; 10011 00000101
;; 10100 01000000
;; 10101 01000001
;; 10110 01000100
;; 10111 01000101
;; 11000 10000000
;; 11001 10000001
;; 11010 10000100
;; 11011 10000101
;; 11100 11000000
;; 11101 11000001
;; 11110 11000100
;; 11111 11000101
;; Routine to set the given flags
;; Noted in \1 by a 1 bit
F_SET MACRO
or.b \1,flag_byte
or.b \1,flag_valid
ENDM
;; Clear the given flags
;; Noted in \1 (must be a reg) by a 1 bit
F_CLEAR MACRO
or.b \1,flag_valid
not.b \1
and.b \1,flag_byte
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 \1. (d1
;; destroyed)
;; XXX that's expensive. After making this a subroutine, to speed up parity computation, maybe you could use a 256-byte lookup table accessed by d(pc,ix.w).
;; And if you have a spare address register, since xxx.l addressing mode is expensive speed-wise and size-wise (4 bytes + relocation),
;; you should use lea d(pc) to preload the address of flag_valid into an address register,
;; and then use (an) and d(an) to write to flag_valid and flag_byte.
F_PAR MACRO
move.b \1,d1 ; 4 2
lsr.w #4,d1 ; 14 2
eor.b \1,d1 ; 4 2
lsr.w #2,d1 ; 10 2
eor.b \1,d1 ; 4 2
lsr.w #1,d1 ; 8 2
eor.b \1,d1 ; 4 2
andi.b #$01,d1 ; 8 4
;; odd parity is now in d1
ori.b #%00000100,flag_valid ; 20 8
andi.b #%11111011,flag_byte ; 20 8
rol.b #2,d1 ; 6 2
or.b d1,flag_byte ; 16 4
ENDM ;xxx cycles (!)
; xx bytes (make this a subroutine)
;; Use this when an instruction uses the P/V bit as Overflow.
;; Leaves the bit itself implicit; simply marks it dirty.
F_OVFL MACRO
andi.b #%11111011
ENDM
;; Save the two operands from ADD \1,\2
F_ADD_SAVE MACRO
move.b \1,f_tmp_src_b
move.b \2,f_tmp_dst_b
move.b #$01,f_tmp_byte
F_SET #%
ENDM
;; Normalize and return carry bit (is loaded into Z bit)
;; Destroys d1
f_norm_c:
move.b flag_valid(pc),d1
;; XXX you could use lsr #1 (same number of cycles, smaller) + bcc.s or bcs.s here.
andi.b #%00000001,d1
bne.s FNC_ok ; Bit is valid
move.b f_host_ccr(pc),d1
andi.b #%00000001,d1
;; XXX see above comment for using lea and then d(an) if you have a spare register.
or.b d1,flag_byte
ori.b #%00000001,flag_valid
FNC_ok:
move.b flag_byte(pc),d1
andi.b #%00000001,d1
rts
;; Normalize and return zero bit (loaded into Z bit)
;; Destroys d1
f_norm_z:
move.b flag_valid(pc),d1
andi.b #%01000000,d1
bne.s FNZ_ok ; Bit is valid
move.b f_host_ccr(pc),d1
andi.b #%01000000,d1
;; XXX see above comment for using lea and then d(an) if you have a spare register.
or.b d1,flag_byte
ori.b #%01000000,flag_valid
FNZ_ok:
move.b flag_byte(pc),d1
andi.b #%01000000,d1
rts
;; Routine to turn 68k flags into z80 flags.
;; Preconditions:
;; Flags to change are noted in d0 by a 1 bit
flags_normalize:
move.b f_host_ccr(pc),d1
;; XXX .w because you don't want garbage in bits 8-15 when using d(pc,ix.w) or d(an,ix.w) ea mode.
andi.w #%00011111,d1 ; Maybe TI uses the reserved bits for
; something ...
move.b lut_ccr(pc,d1.w),d1
;; XXX do this
rts
storage:
;; 1 if tmp_???b is valid, 0 if tmp_???w is valid
f_tmp_byte: ds.b 0
;; 2 if P is 0, 3 if P is 1, 4 if P is Parity, 5 if P is oVerflow
f_tmp_p_type: ds.b 0
;; byte operands
f_tmp_src_b: ds.b 0
f_tmp_dst_b: ds.b 0
f_tmp_result_b: ds.b 0
EVEN
f_tmp_src_w: ds.w 0
f_tmp_dst_w: ds.w 0
f_tmp_result_w: ds.w 0
flag_n: ds.w 0
;; 000XNZVC
EVEN ; Compositing a word from two bytes ...
f_host_sr: ds.b 0
f_host_ccr: ds.b 0
EVEN
flag_byte: ds.b 0 ; Byte of all flags
flag_valid: ds.b 0 ; Validity mask -- 1 if valid.
;; LUT for the CCR -> F mapping
lut_ccr:
dc.b %00000000
dc.b %00000001
dc.b %00000100
dc.b %00000101
dc.b %01000000
dc.b %01000001
dc.b %01000100
dc.b %01000101
dc.b %10000000
dc.b %10000001
dc.b %10000100
dc.b %10000101
dc.b %11000000
dc.b %11000001
dc.b %11000100
dc.b %11000101
dc.b %00000000
dc.b %00000001
dc.b %00000100
dc.b %00000101
dc.b %01000000
dc.b %01000001
dc.b %01000100
dc.b %01000101
dc.b %10000000
dc.b %10000001
dc.b %10000100
dc.b %10000101
dc.b %11000000
dc.b %11000001
dc.b %11000100
dc.b %11000101
|