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
65do_fmovem=0
66do_fmovem_cr=0
67do_no_pc_mode=0
68do_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
770:
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
890:
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
1190:
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 diplacement 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
1471\@:	printf	PDECODE,"a%d",1,%d0
148	jsr	fp_get_addr_reg
149	move.l	%a0,%d0
1502\@:
151debug	lea	"'l'.w,%a0"
152	btst	#11,%d2			| 16/32 bit size?
153	jne	3\@f
154debug	lea	"'w'.w,%a0"
155	ext.l	%d0
1563\@:	printf	PDECODE,":%c",1,%a0
157	move.w	%d2,%d1			| scale factor
158	rol.w	#7,%d1
159	and.w	#3,%d1
160debug	move.l	"%d1,-(%sp)"
161debug	ext.l	"%d1"
162	printf	PDECODE,":%d",1,%d1
163debug	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
1730:
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
1830:
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
2401\@:
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
2981:	fp_decode_addr_reg
299	printf	PDECODE,"a%d",1,%d0
300	jsr	fp_get_addr_reg
3012:	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
315debug	jra	"2f"
3161:	printf	PDECODE,","
3172:
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
326debug	jra	"2f"
3271:	printf	PDECODE,","
3282:
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
3391:	fp_decode_addr_reg
340	printf	PDECODE,"a%d",1,%d0
341	jsr	fp_get_addr_reg
3422:	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
348debug	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
3553:	| 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
3611:	printf	PDECODE,"@("
362	fp_decode_basedisp
363
364	.long	fp_ill,1f
365	.long	2f,3f
366
367#ifdef FPU_EMU_DEBUG
3681:	printf	PDECODE,"0"		| null base displacement
369	jra	1f
370#endif
3712:	fp_get_instr_word %a0,fp_err_ua1 | 16bit base displacement
372	printf	PDECODE,"%x:w",1,%a0
373	jra	4f
3743:	fp_get_instr_long %a0,fp_err_ua1 | 32bit base displacement
375	printf	PDECODE,"%x:l",1,%a0
3764:	add.l	%a0,%a1
3771:
378	fp_do_postindex
379	fp_test_suppr_index 1f
380	fp_decode_index
381	add.l	%d0,%a1
3821:	fp_do_preindex
383
384	fp_decode_outerdisp
385
386	.long	5f,1f
387	.long	2f,3f
388
389#ifdef FPU_EMU_DEBUG
3901:	printf	PDECODE,"0"		| null outer displacement
391	jra	1f
392#endif
3932:	fp_get_instr_word %a0,fp_err_ua1 | 16bit outer displacement
394	printf	PDECODE,"%x:w",1,%a0
395	jra	4f
3963:	fp_get_instr_long %a0,fp_err_ua1 | 32bit outer displacement
397	printf	PDECODE,"%x:l",1,%a0
3984:	add.l	%a0,%a1
3991:
4005:	printf	PDECODE,")"
4019:	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