1 /*
2  * fp_decode.h
3  *
4  * Copyright Roman Zippel, 1997.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, and the entire permission notice in its entirety,
11  *    including the disclaimer of warranties.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote
16  *    products derived from this software without specific prior
17  *    written permission.
18  *
19  * ALTERNATIVELY, this product may be distributed under the terms of
20  * the GNU General Public License, in which case the provisions of the GPL are
21  * required INSTEAD OF the above restrictions.  (This clause is
22  * necessary due to a potential bad interaction between the GPL and
23  * the restrictions contained in a BSD-style copyright.)
24  *
25  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
26  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
28  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
29  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
33  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
35  * OF THE POSSIBILITY OF SUCH DAMAGE.
36  */
37 
38 #ifndef _FP_DECODE_H
39 #define _FP_DECODE_H
40 
41 /* These macros do the dirty work of the instr decoding, several variables
42  * can be defined in the source file to modify the work of these macros,
43  * currently the following variables are used:
44  * ...
45  * The register usage:
46  * d0 - will contain source operand for data direct mode,
47  *	otherwise scratch register
48  * d1 - upper 16bit are reserved for caller
49  *	lower 16bit may contain further arguments,
50  *	is destroyed during decoding
51  * d2 - contains first two instruction words,
52  *	first word will be used for extension word
53  * a0 - will point to source/dest operand for any indirect mode
54  *	otherwise scratch register
55  * a1 - scratch register
56  * a2 - base addr to the task structure
57  *
58  * the current implementation doesn't check for every disallowed
59  * addressing mode (e.g. pc relative modes as destination), as long
60  * as it only means a new addressing mode, which should not appear
61  * in a program and that doesn't crash the emulation, I think it's
62  * not a problem to allow these modes.
63  */
64 
65 do_fmovem=0
66 do_fmovem_cr=0
67 do_no_pc_mode=0
68 do_fscc=0
69 
70 | first decoding of the instr type
71 | this separates the conditional instr
72 .macro	fp_decode_cond_instr_type
73 	bfextu	%d2{#8,#2},%d0
74 	jmp	([0f:w,%pc,%d0*4])
75 
76 	.align	4
77 0:
78 |	.long	"f<op>","fscc/fdbcc"
79 |	.long	"fbccw","fbccl"
80 .endm
81 
82 | second decoding of the instr type
83 | this separates most move instr
84 .macro	fp_decode_move_instr_type
85 	bfextu	%d2{#16,#3},%d0
86 	jmp	([0f:w,%pc,%d0*4])
87 
88 	.align	4
89 0:
90 |	.long	"f<op> fpx,fpx","invalid instr"
91 |	.long	"f<op> <ea>,fpx","fmove fpx,<ea>"
92 |	.long	"fmovem <ea>,fpcr","fmovem <ea>,fpx"
93 |	.long	"fmovem fpcr,<ea>","fmovem fpx,<ea>"
94 .endm
95 
96 | extract the source specifier, specifies
97 | either source fp register or data format
98 .macro	fp_decode_sourcespec
99 	bfextu	%d2{#19,#3},%d0
100 .endm
101 
102 | decode destination format for fmove reg,ea
103 .macro	fp_decode_dest_format
104 	bfextu	%d2{#19,#3},%d0
105 .endm
106 
107 | decode source register for fmove reg,ea
108 .macro	fp_decode_src_reg
109 	bfextu	%d2{#22,#3},%d0
110 .endm
111 
112 | extract the addressing mode
113 | it depends on the instr which of the modes is valid
114 .macro	fp_decode_addr_mode
115 	bfextu	%d2{#10,#3},%d0
116 	jmp	([0f:w,%pc,%d0*4])
117 
118 	.align	4
119 0:
120 |	.long	"data register direct","addr register direct"
121 |	.long	"addr register indirect"
122 |	.long	"addr register indirect postincrement"
123 |	.long	"addr register indirect predecrement"
124 |	.long	"addr register + index16"
125 |	.long	"extension mode1","extension mode2"
126 .endm
127 
128 | extract the register for the addressing mode
129 .macro	fp_decode_addr_reg
130 	bfextu	%d2{#13,#3},%d0
131 .endm
132 
133 | decode the 8bit displacement from the brief extension word
134 .macro	fp_decode_disp8
135 	move.b	%d2,%d0
136 	ext.w	%d0
137 .endm
138 
139 | decode the index of the brief/full extension word
140 .macro	fp_decode_index
141 	bfextu	%d2{#17,#3},%d0		| get the register nr
142 	btst	#15,%d2			| test for data/addr register
143 	jne	1\@f
144 	printf	PDECODE,"d%d",1,%d0
145 	jsr	fp_get_data_reg
146 	jra	2\@f
147 1\@:	printf	PDECODE,"a%d",1,%d0
148 	jsr	fp_get_addr_reg
149 	move.l	%a0,%d0
150 2\@:
151 debug	lea	"'l'.w,%a0"
152 	btst	#11,%d2			| 16/32 bit size?
153 	jne	3\@f
154 debug	lea	"'w'.w,%a0"
155 	ext.l	%d0
156 3\@:	printf	PDECODE,":%c",1,%a0
157 	move.w	%d2,%d1			| scale factor
158 	rol.w	#7,%d1
159 	and.w	#3,%d1
160 debug	move.l	"%d1,-(%sp)"
161 debug	ext.l	"%d1"
162 	printf	PDECODE,":%d",1,%d1
163 debug	move.l	"(%sp)+,%d1"
164 	lsl.l	%d1,%d0
165 .endm
166 
167 | decode the base displacement size
168 .macro	fp_decode_basedisp
169 	bfextu	%d2{#26,#2},%d0
170 	jmp	([0f:w,%pc,%d0*4])
171 
172 	.align	4
173 0:
174 |	.long	"reserved","null displacement"
175 |	.long	"word displacement","long displacement"
176 .endm
177 
178 .macro	fp_decode_outerdisp
179 	bfextu	%d2{#30,#2},%d0
180 	jmp	([0f:w,%pc,%d0*4])
181 
182 	.align	4
183 0:
184 |	.long	"no memory indirect action/reserved","null outer displacement"
185 |	.long	"word outer displacement","long outer displacement"
186 .endm
187 
188 | get the extension word and test for brief or full extension type
189 .macro	fp_get_test_extword label
190 	fp_get_instr_word %d2,fp_err_ua1
191 	btst	#8,%d2
192 	jne	\label
193 .endm
194 
195 
196 | test if %pc is the base register for the indirect addr mode
197 .macro	fp_test_basereg_d16	label
198 	btst	#20,%d2
199 	jeq	\label
200 .endm
201 
202 | test if %pc is the base register for one of the extended modes
203 .macro	fp_test_basereg_ext	label
204 	btst	#19,%d2
205 	jeq	\label
206 .endm
207 
208 .macro	fp_test_suppr_index label
209 	btst	#6,%d2
210 	jne	\label
211 .endm
212 
213 
214 | addressing mode: data register direct
215 .macro	fp_mode_data_direct
216 	fp_decode_addr_reg
217 	printf	PDECODE,"d%d",1,%d0
218 .endm
219 
220 | addressing mode: address register indirect
221 .macro	fp_mode_addr_indirect
222 	fp_decode_addr_reg
223 	printf	PDECODE,"(a%d)",1,%d0
224 	jsr	fp_get_addr_reg
225 .endm
226 
227 | adjust stack for byte moves from/to stack
228 .macro	fp_test_sp_byte_move
229 	.if	!do_fmovem
230 	.if	do_fscc
231 	move.w	#6,%d1
232 	.endif
233 	cmp.w	#7,%d0
234 	jne	1\@f
235 	.if	!do_fscc
236 	cmp.w	#6,%d1
237 	jne	1\@f
238 	.endif
239 	move.w	#4,%d1
240 1\@:
241 	.endif
242 .endm
243 
244 | addressing mode: address register indirect with postincrement
245 .macro	fp_mode_addr_indirect_postinc
246 	fp_decode_addr_reg
247 	printf	PDECODE,"(a%d)+",1,%d0
248 	fp_test_sp_byte_move
249 	jsr	fp_get_addr_reg
250 	move.l	%a0,%a1			| save addr
251 	.if	do_fmovem
252 	lea	(%a0,%d1.w*4),%a0
253 	.if	!do_fmovem_cr
254 	lea	(%a0,%d1.w*8),%a0
255 	.endif
256 	.else
257 	add.w	(fp_datasize,%d1.w*2),%a0
258 	.endif
259 	jsr	fp_put_addr_reg
260 	move.l	%a1,%a0
261 .endm
262 
263 | addressing mode: address register indirect with predecrement
264 .macro	fp_mode_addr_indirect_predec
265 	fp_decode_addr_reg
266 	printf	PDECODE,"-(a%d)",1,%d0
267 	fp_test_sp_byte_move
268 	jsr	fp_get_addr_reg
269 	.if	do_fmovem
270 	.if	!do_fmovem_cr
271 	lea	(-12,%a0),%a1		| setup to addr of 1st reg to move
272 	neg.w	%d1
273 	lea	(%a0,%d1.w*4),%a0
274 	add.w	%d1,%d1
275 	lea	(%a0,%d1.w*4),%a0
276 	jsr	fp_put_addr_reg
277 	move.l	%a1,%a0
278 	.else
279 	neg.w	%d1
280 	lea	(%a0,%d1.w*4),%a0
281 	jsr	fp_put_addr_reg
282 	.endif
283 	.else
284 	sub.w	(fp_datasize,%d1.w*2),%a0
285 	jsr	fp_put_addr_reg
286 	.endif
287 .endm
288 
289 | addressing mode: address register/programm counter indirect
290 |		   with 16bit displacement
291 .macro	fp_mode_addr_indirect_disp16
292 	.if	!do_no_pc_mode
293 	fp_test_basereg_d16 1f
294 	printf	PDECODE,"pc"
295 	fp_get_pc %a0
296 	jra	2f
297 	.endif
298 1:	fp_decode_addr_reg
299 	printf	PDECODE,"a%d",1,%d0
300 	jsr	fp_get_addr_reg
301 2:	fp_get_instr_word %a1,fp_err_ua1
302 	printf	PDECODE,"@(%x)",1,%a1
303 	add.l	%a1,%a0
304 .endm
305 
306 | perform preindex (if I/IS == 0xx and xx != 00)
307 .macro	fp_do_preindex
308 	moveq	#3,%d0
309 	and.w	%d2,%d0
310 	jeq	1f
311 	btst	#2,%d2
312 	jne	1f
313 	printf	PDECODE,")@("
314 	getuser.l (%a1),%a1,fp_err_ua1,%a1
315 debug	jra	"2f"
316 1:	printf	PDECODE,","
317 2:
318 .endm
319 
320 | perform postindex (if I/IS == 1xx)
321 .macro	fp_do_postindex
322 	btst	#2,%d2
323 	jeq	1f
324 	printf	PDECODE,")@("
325 	getuser.l (%a1),%a1,fp_err_ua1,%a1
326 debug	jra	"2f"
327 1:	printf	PDECODE,","
328 2:
329 .endm
330 
331 | all other indirect addressing modes will finally end up here
332 .macro	fp_mode_addr_indirect_extmode0
333 	.if	!do_no_pc_mode
334 	fp_test_basereg_ext 1f
335 	printf	PDECODE,"pc"
336 	fp_get_pc %a0
337 	jra	2f
338 	.endif
339 1:	fp_decode_addr_reg
340 	printf	PDECODE,"a%d",1,%d0
341 	jsr	fp_get_addr_reg
342 2:	move.l	%a0,%a1
343 	swap	%d2
344 	fp_get_test_extword 3f
345 	| addressing mode: address register/programm counter indirect
346 	|		   with index and 8bit displacement
347 	fp_decode_disp8
348 debug	ext.l	"%d0"
349 	printf	PDECODE,"@(%x,",1,%d0
350 	add.w	%d0,%a1
351 	fp_decode_index
352 	add.l	%d0,%a1
353 	printf	PDECODE,")"
354 	jra	9f
355 3:	| addressing mode: address register/programm counter memory indirect
356 	|		   with base and/or outer displacement
357 	btst	#7,%d2			| base register suppressed?
358 	jeq	1f
359 	printf	PDECODE,"!"
360 	sub.l	%a1,%a1
361 1:	printf	PDECODE,"@("
362 	fp_decode_basedisp
363 
364 	.long	fp_ill,1f
365 	.long	2f,3f
366 
367 #ifdef FPU_EMU_DEBUG
368 1:	printf	PDECODE,"0"		| null base displacement
369 	jra	1f
370 #endif
371 2:	fp_get_instr_word %a0,fp_err_ua1 | 16bit base displacement
372 	printf	PDECODE,"%x:w",1,%a0
373 	jra	4f
374 3:	fp_get_instr_long %a0,fp_err_ua1 | 32bit base displacement
375 	printf	PDECODE,"%x:l",1,%a0
376 4:	add.l	%a0,%a1
377 1:
378 	fp_do_postindex
379 	fp_test_suppr_index 1f
380 	fp_decode_index
381 	add.l	%d0,%a1
382 1:	fp_do_preindex
383 
384 	fp_decode_outerdisp
385 
386 	.long	5f,1f
387 	.long	2f,3f
388 
389 #ifdef FPU_EMU_DEBUG
390 1:	printf	PDECODE,"0"		| null outer displacement
391 	jra	1f
392 #endif
393 2:	fp_get_instr_word %a0,fp_err_ua1 | 16bit outer displacement
394 	printf	PDECODE,"%x:w",1,%a0
395 	jra	4f
396 3:	fp_get_instr_long %a0,fp_err_ua1 | 32bit outer displacement
397 	printf	PDECODE,"%x:l",1,%a0
398 4:	add.l	%a0,%a1
399 1:
400 5:	printf	PDECODE,")"
401 9:	move.l	%a1,%a0
402 	swap	%d2
403 .endm
404 
405 | get the absolute short address from user space
406 .macro	fp_mode_abs_short
407 	fp_get_instr_word %a0,fp_err_ua1
408 	printf	PDECODE,"%x.w",1,%a0
409 .endm
410 
411 | get the absolute long address from user space
412 .macro	fp_mode_abs_long
413 	fp_get_instr_long %a0,fp_err_ua1
414 	printf	PDECODE,"%x.l",1,%a0
415 .endm
416 
417 #endif /* _FP_DECODE_H */
418