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
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
|
;; Routine to set the given flags
;; Noted in \1 by a 1 bit
F_SET MACRO
or.b \1,flag_byte-flag_storage(a3)
or.b \1,flag_valid-flag_storage(a3)
ENDM
;; Clear the given flags
;; Noted in \1 (must be a reg) by a 1 bit
F_CLEAR MACRO
or.b \1,flag_valid-flag_storage(a3)
not.b \1
and.b \1,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 \1. High
;; byte of \1.w must be zero, using d0 is suggested. (a0,d1
;; destroyed)
F_PAR MACRO
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,\1.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.
F_OVFL MACRO
andi.b #%11111011,flag_valid-flag_storage(a3)
ENDM
;; Save the two operands from ADD \1,\2
F_ADD_SAVE MACRO
move.b \1,f_tmp_src_b-flag_storage(a3)
move.b \2,f_tmp_dst_b-flag_storage(a3)
move.b #$01,f_tmp_byte-flag_storage(a3)
F_SET #%
ENDM
;; Normalize and return carry bit (is loaded into Z bit)
;; 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 zero bit (loaded into Z bit)
;; 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 Parity/oVerflow bit (loaded into Z
;; bit)
;; 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.w flag_byte(pc),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 Sign bit (loaded into Z bit).
;; 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
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
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
EVEN
flag_storage:
;; 0 if the flag is already valid
;; 2 if tmp_???b is valid
;; 3 if tmp_???w is valid
f_tmp_byte: dc.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: dc.b 0
;; byte operands
f_tmp_src_b: dc.b 0
f_tmp_dst_b: dc.b 0
f_tmp_result_b: dc.b 0
EVEN
f_tmp_src_w: dc.w 0
f_tmp_dst_w: dc.w 0
f_tmp_result_w: dc.w 0
;; 000XNZVC
EVEN
;; DO NOT REARRANGE THESE
f_host_sr: dc.w 0
f_host_ccr: dc.b 0 ;XXX make overlap somehow?
EVEN
;; DO NOT REARRANGE THESE.
flag_byte: dc.b 0 ; Byte of all flags
flag_valid: dc.b 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
dc.b %00000000 ;; 00000 00000000
dc.b %00000001 ;; 00001 00000001
dc.b %00000100 ;; 00010 00000100
dc.b %00000101 ;; 00011 00000101
dc.b %01000000 ;; 00100 01000000
dc.b %01000001 ;; 00101 01000001
dc.b %01000100 ;; 00110 01000100
dc.b %01000101 ;; 00111 01000101
dc.b %10000000 ;; 01000 10000000
dc.b %10000001 ;; 01001 10000001
dc.b %10000100 ;; 01010 10000100
dc.b %10000101 ;; 01011 10000101
dc.b %11000000 ;; 01100 11000000
dc.b %11000001 ;; 01101 11000001
dc.b %11000100 ;; 01110 11000100
dc.b %11000101 ;; 01111 11000101
dc.b %00000000 ;; 10000 00000000
dc.b %00000001 ;; 10001 00000001
dc.b %00000100 ;; 10010 00000100
dc.b %00000101 ;; 10011 00000101
dc.b %01000000 ;; 10100 01000000
dc.b %01000001 ;; 10101 01000001
dc.b %01000100 ;; 10110 01000100
dc.b %01000101 ;; 10111 01000101
dc.b %10000000 ;; 11000 10000000
dc.b %10000001 ;; 11001 10000001
dc.b %10000100 ;; 11010 10000100
dc.b %10000101 ;; 11011 10000101
dc.b %11000000 ;; 11100 11000000
dc.b %11000001 ;; 11101 11000001
dc.b %11000100 ;; 11110 11000100
dc.b %11000101 ;; 11111 11000101
;; 256-byte LUT for the Parity bit.
;; Keep this last so all storage references require only one
;; extension word.
lut_parity:
dc.b 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4
dc.b 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0
dc.b 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0
dc.b 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4
dc.b 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0
dc.b 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4
dc.b 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4
dc.b 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0
dc.b 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0
dc.b 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4
dc.b 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4
dc.b 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0
dc.b 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4
dc.b 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0
dc.b 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0
dc.b 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4
|