|
|
1.1 root 1: #! /bin/sh
2:
1.1.1.3 ! root 3: # $Id: m68k-insns-auto.sh,v 1.23 2005/03/10 13:26:23 fredette Exp $
1.1 root 4:
5: # ic/m68k/m68k-insns-auto.sh - automatically generates C code
6: # for many m68k emulation instructions:
7:
8: #
9: # Copyright (c) 2002, 2003 Matt Fredette
10: # All rights reserved.
11: #
12: # Redistribution and use in source and binary forms, with or without
13: # modification, are permitted provided that the following conditions
14: # are met:
15: # 1. Redistributions of source code must retain the above copyright
16: # notice, this list of conditions and the following disclaimer.
17: # 2. Redistributions in binary form must reproduce the above copyright
18: # notice, this list of conditions and the following disclaimer in the
19: # documentation and/or other materials provided with the distribution.
20: # 3. All advertising materials mentioning features or use of this software
21: # must display the following acknowledgement:
22: # This product includes software developed by Matt Fredette.
23: # 4. The name of the author may not be used to endorse or promote products
24: # derived from this software without specific prior written permission.
25: #
26: # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
27: # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
28: # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
29: # DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
30: # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
31: # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
32: # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33: # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
34: # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35: # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36: # POSSIBILITY OF SUCH DAMAGE.
37: #
38:
39: header=false
40:
41: for option
42: do
43: case $option in
44: --header) header=true ;;
45: esac
46: done
47:
48: PROG=`basename $0`
49: cat <<EOF
50: /* automatically generated by $PROG, do not edit! */
1.1.1.3 ! root 51: _TME_RCSID("\$Id: m68k-insns-auto.sh,v 1.23 2005/03/10 13:26:23 fredette Exp $");
1.1 root 52:
53: EOF
54: if $header; then :; else
55: cat <<EOF
56: #include "m68k-impl.h"
57:
58: EOF
59: fi
60:
61: # permute for the three different operand sizes we need to handle:
62: for size in 8 16 32; do
63:
64: # the shifts needed to get register contents of a specific size:
65: case ${size} in
66: 8) reg_size_shift=' << 2' ;;
67: 16) reg_size_shift=' << 1' ;;
68: 32) reg_size_shift='' ;;
69: esac
70:
71: # generate the ALU functions:
72: for name in add sub cmp neg or and eor not tst move moveq clr cmpa negx addx subx cmpm; do
73:
74: # characterize each operation:
75: optype=normal ; src=op0 ; dst=op1 ; res=op1 ; arith=no ; with_x=false ; store_res=true
76: case "$name" in
77: add) op=' + ' ; arith=add ;;
78: sub) op=' - ' ; arith=sub ;;
79: cmp) op=' - ' ; arith=sub ; store_res=false ;;
80: neg) op=' - ' ; arith=sub ; dst=0 ; src=op1 ;;
81: or) op=' | ' ;;
82: and) op=' & ' ;;
83: eor) op=' ^ ' ;;
84: not) op='~ ' ; dst= ; src=op1 ;;
85: tst) op='' ; dst= ; src=op1 ; store_res=false ;;
86: move) op='' ; dst= ; src=op1 ; res=op0 ;;
87: moveq) op='' ; dst= ; src=opc8 ; if test ${size} != 32; then continue; fi ;;
88: clr) op='' ; dst= ; src=0 ;;
89: cmpa) op=' - ' ; arith=sub ; src=op0.16s32 ; store_res=false
90: if test $size != 16; then continue; fi ;;
91: negx) op=' - ' ; arith=sub ; with_x=true ; dst=0 ; src=op1 ;;
92: addx) op=' + ' ; arith=add ; optype=mathx ; with_x=true ;;
93: subx) op=' - ' ; arith=sub ; optype=mathx ; with_x=true ;;
94: cmpm) op=' - ' ; arith=sub ; optype=mathx ; store_res=false ;;
95: *) echo "$0 internal error: unknown ALU function $name" 1>&2 ; exit 1 ;;
96: esac
97:
98: # placeholder for another permutation:
99: :
100:
101: # if we're making the header, just emit a declaration:
102: if $header; then
103: echo "TME_M68K_INSN_DECL(tme_m68k_${name}${size});"
104: continue
105: fi
106:
107: # open the function:
108: echo ""
109: echo -n "/* this does a ${size}-bit \"$name "
110: case "${src}/${dst}" in *op0*) echo -n "SRC, " ;; esac
111: echo "DST\": */"
112: echo "TME_M68K_INSN(tme_m68k_${name}${size})"
113: echo "{"
114:
115: # declare our locals:
116: if test $name = cmpa; then size=32; fi
117: echo -n " tme_uint${size}_t res"
118: case "${src}/${dst}" in *op0*) echo -n ", op0" ;; esac
119: case "${src}/${dst}" in *op1*) echo -n ", op1" ;; esac
120: echo ";"
121: echo " tme_uint8_t flags;"
122:
123: # load the operand(s):
124: echo ""
125: echo " /* load the operand(s): */"
126: case ${optype} in
127: mathx)
128: echo " unsigned int function_code = TME_M68K_FUNCTION_CODE_DATA(ic);"
129:
130: # NB: in my 68000 Programmer's Manual, the description
131: # of subx is a little backwards from addx and cmpm. in
132: # subx, the reg field at bits 0-2 is called the "x"
133: # field, where in addx and cmpm it's called the "y"
134: # field, and similarly for the reg field at bits 9-11.
135: # fortunately, the meanings of the two reg fields is
136: # always the same despite this - the reg field at bits
137: # 0-2 always identifies the source operand, and the
138: # reg field at bits 9-11 always identifies the
139: # destination operand:
140: echo " int ireg_src = TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 0, 3);"
141: echo " int ireg_dst = TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 9, 3);"
142:
143: # the stack pointer must always be adjusted by a multiple of two.
144: # assuming ireg < 8, ((ireg + 1) >> 3) == 1 iff ireg == 7, meaning %a7:
145: echo -n " tme_uint32_t ireg_src_adjust = sizeof(tme_uint${size}_t)";
146: if test ${size} = 8; then
147: echo -n " + ((ireg_src + 1) >> 3)"
148: fi
149: echo ";"
150: echo -n " tme_uint32_t ireg_dst_adjust = sizeof(tme_uint${size}_t)";
151: if test ${size} = 8; then
152: echo -n " + ((ireg_dst + 1) >> 3)"
153: fi
154: echo ";"
155:
156: case ${name} in
157:
158: # cmpm always uses memory and is always postincrement:
159: cmpm)
160: echo ""
161: echo " TME_M68K_INSN_CANFAULT;"
162: echo ""
163: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {"
164: echo " ic->_tme_m68k_ea_function_code = function_code;"
165: echo " ic->_tme_m68k_ea_address = ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ireg_dst);"
166: echo " ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ireg_dst) += ireg_dst_adjust;"
167: echo " }"
168: echo " tme_m68k_read_memx${size}(ic);"
169: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {"
170: echo " ic->_tme_m68k_ea_function_code = function_code;"
171: echo " ic->_tme_m68k_ea_address = ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ireg_src);"
172: echo " ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ireg_src) += ireg_src_adjust;"
173: echo " }"
174: echo " tme_m68k_read_mem${size}(ic, TME_M68K_IREG_MEMY${size});"
175: echo " ${dst} = ic->tme_m68k_ireg_memx${size};"
176: echo " ${src} = ic->tme_m68k_ireg_memy${size};"
177: ;;
178:
179: # addx and subx use either registers or memory. if they use memory,
180: # they always predecrement:
181: addx|subx)
182: echo " tme_uint16_t memory;"
183: echo ""
184: echo " memory = (TME_M68K_INSN_OPCODE & TME_BIT(3));"
185: echo " if (memory) {"
186: echo " TME_M68K_INSN_CANFAULT;"
187: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {"
188: echo " ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ireg_dst) -= ireg_dst_adjust;"
189: echo " ic->_tme_m68k_ea_function_code = function_code;"
190: echo " ic->_tme_m68k_ea_address = ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ireg_dst);"
191: echo " }"
192: echo " tme_m68k_read_memx${size}(ic);"
193: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {"
194: echo " ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ireg_src) -= ireg_src_adjust;"
195: echo " ic->_tme_m68k_ea_function_code = function_code;"
196: echo " ic->_tme_m68k_ea_address = ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ireg_src);"
197: echo " }"
198: echo " tme_m68k_read_mem${size}(ic, TME_M68K_IREG_MEMY${size});"
199: echo " ${dst} = ic->tme_m68k_ireg_memx${size};"
200: echo " ${src} = ic->tme_m68k_ireg_memy${size};"
201: echo " }"
202: echo " else {"
203: echo " ${src} = ic->tme_m68k_ireg_uint${size}((TME_M68K_IREG_D0 + ireg_src)${reg_size_shift});"
204: echo " ${dst} = ic->tme_m68k_ireg_uint${size}((TME_M68K_IREG_D0 + ireg_dst)${reg_size_shift});"
205: echo " }"
206: ;;
207: *) echo "$0 internal error: unknown mathx ${name}" 1>&2 ; exit 1 ;;
208: esac
209: ;;
210: normal)
211: for which in src dst; do
212: eval 'what=$'${which}
213: case "x${what}" in
214: x|x0) ;;
215: xop[01].16s32)
216: what=`echo ${what} | sed -e 's/\..*//'`
217: eval ${which}"=${what}"
218: echo " ${what} = (tme_uint32_t) ((tme_int32_t) *((tme_int16_t *) _${what}));"
219: ;;
220: xop[01])
221: echo " ${what} = *((tme_uint${size}_t *) _${what});"
222: ;;
223: xopc8)
224: eval ${which}"='TME_EXT_S8_U${size}((tme_int8_t) (TME_M68K_INSN_OPCODE & 0xff))'"
225: ;;
226: *) echo "$0 internal error: unknown what ${what}" 1>&2 ; exit 1 ;;
227: esac
228: done
229: ;;
230: *) echo "$0 internal error: unknown optype ${optype}" 1>&2 ; exit 1 ;;
231: esac
232:
233: # perform the operation:
234: echo ""
235: echo " /* perform the operation: */"
236: echo -n " res = ${dst}${op}${src}"
237: if $with_x; then
238: echo -n "${op}((ic->tme_m68k_ireg_ccr / TME_M68K_FLAG_X) & 1)"
239: fi
240: echo ";"
241:
242: # store the result:
243: if $store_res; then
244: echo ""
245: echo " /* store the result: */"
246: case ${optype} in
247: mathx)
248: echo " if (memory) {"
249: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {"
250: echo " ic->tme_m68k_ireg_memx${size} = res;"
251: echo " ic->_tme_m68k_ea_function_code = function_code;"
252: echo " ic->_tme_m68k_ea_address = ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ireg_dst);"
253: echo " }"
254: echo " tme_m68k_write_memx${size}(ic);"
255: echo " }"
256: echo " else {"
257: echo " ic->tme_m68k_ireg_uint${size}((TME_M68K_IREG_D0 + ireg_dst)${reg_size_shift}) = res;"
258: echo " }"
259: ;;
260: normal)
261: echo " *((tme_uint${size}_t *) _${res}) = res;"
262: ;;
263: *) echo "$0 internal error: unknown optype ${optype}" 1>&2 ; exit 1 ;;
264: esac
265: fi
266:
267: # start the status flags, maybe preserving X:
268: echo ""
269: echo " /* set the flags: */"
270: case "${name}:${arith}" in
271: cmp*|*:no)
272: flag_x=
273: ;;
274: *)
275: flag_x=" | TME_M68K_FLAG_X"
276: ;;
277: esac
278:
279: # set N. we cast to tme_uint8_t as soon as we know the
280: # bit we want is within the range of the type, to try
281: # to affect the generated assembly:
282: echo " flags = ((tme_uint8_t) (((tme_uint${size}_t) res) >> (${size} - 1))) * TME_M68K_FLAG_N;"
283:
284: # set Z:
285: if $with_x; then
286: echo " if (res == 0) flags |= (ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_Z);"
287: else
288: echo " if (res == 0) flags |= TME_M68K_FLAG_Z;"
289: fi
290:
291: # set V and C and maybe X:
292: case $arith in
293: add)
294: case $size in
295: 8) ones="0xff" ;;
296: 16) ones="0xffff" ;;
297: 32) ones="0xffffffff" ;;
298: esac
299: # if the operands are the same sign, and the result has
300: # a different sign, set V. we cast to tme_uint8_t as
301: # soon as we know the bit we want is within the range
302: # of the type, to try to affect the generated assembly:
303: echo " flags |= ((tme_uint8_t) (((${src} ^ ${dst} ^ ${ones}) & (${dst} ^ res)) >> (${size} - 1))) * TME_M68K_FLAG_V;"
304: # if src is greater than the logical inverse of dst, set C:
305: echo -n " if (${src} > (${dst} ^ ${ones})"
306: if $with_x; then
307: echo -n " || (${src} == (${dst} ^ ${ones}) && (ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_X))"
308: fi
309: echo ") flags |= TME_M68K_FLAG_C${flag_x};"
310: ;;
311: sub)
312: # if the operands are different signs, and the result has
313: # a different sign from the first operand, set V. we
314: # cast to tme_uint8_t as soon as we know the bit we want
315: # is within the range of the type, to try to affect the
316: # generated assembly:
317: echo " flags |= ((tme_uint8_t) (((${src} ^ ${dst}) & (${dst} ^ res)) >> (${size} - 1))) * TME_M68K_FLAG_V;"
318: # if src is greater than dst, set C:
319: echo -n " if (${src} > ${dst}"
320: if $with_x; then
321: echo -n " || (${src} == ${dst} && (ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_X))"
322: fi
323: echo ") flags |= TME_M68K_FLAG_C${flag_x};"
324: ;;
325: no) ;;
326: esac
327:
328: # preserve X:
329: if test "x${flag_x}" = x; then
330: echo " flags |= (ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_X);"
331: fi
332:
333: # set the flags:
334: echo " ic->tme_m68k_ireg_ccr = flags;"
335:
336: # done:
337: echo ""
338: echo " TME_M68K_INSN_OK;"
339: echo "}"
340:
341: if test $name = cmpa; then size=16; fi
342: done
343:
344: # generate the address math functions:
345: for name in suba adda movea; do
346:
347: # the address math functions don't need an 8-bit version:
348: if test $size = 8; then continue; fi
349:
350: # if we're making the header, just emit a declaration:
351: if $header; then
352: echo "TME_M68K_INSN_DECL(tme_m68k_${name}${size});"
353: continue
354: fi
355:
356: echo ""
357: echo "/* the ${name} function on a ${size}-byte EA: */"
358: echo "TME_M68K_INSN(tme_m68k_${name}${size})"
359: echo "{"
360: case $name in
361: suba) op='-' ; src="_op0" ; dst="_op1" ;;
362: adda) op='+' ; src="_op0" ; dst="_op1" ;;
363: movea) op='' ; src="_op1" ; dst="_op0" ;;
364: esac
365: echo " *((tme_int32_t *) ${dst}) ${op}= *((tme_int${size}_t *) ${src});"
366: echo " TME_M68K_INSN_OK;"
367: echo "}"
368: done
369:
370: # generate the bit functions:
371: for name in btst bchg bclr bset; do
372:
373: # the bit functions don't need a 16-bit version:
374: if test $size = 16; then continue; fi
375:
376: # if we're making the header, just emit a declaration:
377: if $header; then
378: echo "TME_M68K_INSN_DECL(tme_m68k_${name}${size});"
379: continue
380: fi
381:
382: echo ""
383: echo "/* the ${name} function on a ${size}-byte EA: */"
384: echo "TME_M68K_INSN(tme_m68k_${name}${size})"
385: echo "{"
386: echo " tme_uint${size}_t value, bit;"
387: echo " bit = _TME_BIT(tme_uint${size}_t, TME_M68K_INSN_OP0(tme_uint8_t) & (${size} - 1));"
388: echo " value = TME_M68K_INSN_OP1(tme_uint${size}_t);"
389: echo " if (value & bit) {"
390: echo " ic->tme_m68k_ireg_ccr &= ~TME_M68K_FLAG_Z;"
391: echo " }"
392: echo " else {"
393: echo " ic->tme_m68k_ireg_ccr |= TME_M68K_FLAG_Z;"
394: echo " }"
395: case ${name} in
396: btst) ;;
397: bchg) echo " TME_M68K_INSN_OP1(tme_uint${size}_t) = value ^ bit;" ;;
398: bclr) echo " TME_M68K_INSN_OP1(tme_uint${size}_t) = value & ~bit;" ;;
399: bset) echo " TME_M68K_INSN_OP1(tme_uint${size}_t) = value | bit;" ;;
400: esac
401: echo " TME_M68K_INSN_OK;"
402: echo "}"
403: done
404:
405: # generate the shift/rotate functions:
406: for func in as ls ro rox; do
407: for dir in l r; do
408: name="${func}${dir}"
409:
410: # if we're making the header, just emit a declaration:
411: if $header; then
412: echo "TME_M68K_INSN_DECL(tme_m68k_${name}${size});"
413: continue
414: fi
415:
416: echo ""
417: echo "/* the ${name} function on a ${size}-byte EA: */"
418: echo "TME_M68K_INSN(tme_m68k_${name}${size})"
419: echo "{"
420: echo " unsigned int count;"
421: sign=u
422: case "${name}" in
423: asr) sign= ;;
1.1.1.2 root 424: asl) echo " tme_uint${size}_t sign_bits, sign_bits_mask;" ;;
1.1 root 425: rox[lr]) echo " tme_uint8_t xbit;" ;;
426: *) ;;
427: esac
428: echo " tme_${sign}int${size}_t res;"
429: echo " tme_uint8_t flags;"
430: echo ""
431: echo " /* get the count and operand: */"
432: echo " count = TME_M68K_INSN_OP0(tme_uint8_t) & 63;"
433: echo " res = TME_M68K_INSN_OP1(tme_${sign}int${size}_t);"
434:
435: echo ""
436: echo " /* generate the X, V, and C flags assuming the count is zero: */"
437: echo " flags = ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_X;"
438: case "${name}" in
439: rox[lr])
440: echo " xbit = (flags / TME_M68K_FLAG_X);"
441: echo " flags |= (xbit * TME_M68K_FLAG_C);"
442: ;;
443: esac
444:
445: echo ""
446: echo " /* if the count is nonzero, update the result and"
447: echo " generate the X, V, and C flags: */"
448: echo " if (count > 0) {"
449: case "${name}" in
1.1.1.3 ! root 450: lsr)
1.1 root 451: echo " if (63 > SHIFTMAX_INT${size}_T"
452: echo " && count > ${size}) {"
453: echo " res = 0;"
454: echo " }"
455: echo " res >>= (count - 1);"
456: echo " flags = (res & 1);"
457: echo " flags *= TME_M68K_FLAG_C;"
458: echo " flags |= (flags * TME_M68K_FLAG_X);"
459: echo " res >>= 1;"
460: ;;
1.1.1.3 ! root 461: asr)
! 462: echo " if (63 > SHIFTMAX_INT${size}_T"
! 463: echo " && count > ${size}) {"
! 464: echo " res = 0 - (res < 0);"
! 465: echo " }"
! 466: echo "#ifdef SHIFTSIGNED_INT${size}_T"
! 467: echo " res >>= (count - 1);"
! 468: echo "#else /* !SHIFTSIGNED_INT${size}_T */"
! 469: echo " for (; --count > 0; ) {"
! 470: echo " res = (res & ~((tme_${sign}int${size}_t) 1)) / 2;"
! 471: echo " }"
! 472: echo "#endif /* !SHIFTSIGNED_INT${size}_T */"
! 473: echo " flags = (res & 1);"
! 474: echo " flags *= TME_M68K_FLAG_C;"
! 475: echo " flags |= (flags * TME_M68K_FLAG_X);"
! 476: echo "#ifdef SHIFTSIGNED_INT${size}_T"
! 477: echo " res >>= 1;"
! 478: echo "#else /* !SHIFTSIGNED_INT${size}_T */"
! 479: echo " res = (res & ~((tme_${sign}int${size}_t) 1)) / 2;"
! 480: echo "#endif /* !SHIFTSIGNED_INT${size}_T */"
! 481: ;;
1.1 root 482: [al]sl)
483: if test ${name} = asl; then
484: echo ""
485: echo " /* we need to see how the sign of the result will change during"
486: echo " shifting in order to generate V."
487: echo ""
488: echo " in general, the idea is to get all of the bits that will ever"
1.1.1.2 root 489: echo " appear in the sign position into sign_bits, with a mask in"
490: echo " sign_bits_mask. if (sign_bits & sign_bits_mask) is zero or"
491: echo " sign_bits_mask, clear V, else set V."
1.1 root 492: echo ""
1.1.1.2 root 493: echo " start by loading the operand into sign_bits and setting"
494: echo " sign_bits_mask to all-bits-one."
1.1 root 495: echo ""
496: echo " if the shift count is exactly ${size} - 1, then all of the bits"
497: echo " of the operand will appear in the sign position."
498: echo ""
499: echo " if the shift count is less than ${size} - 1, then some of the"
500: echo " less significant bits of the operand will never appear in the"
1.1.1.2 root 501: echo " sign position, so we can shift sign_bits_mask to ignore them."
1.1 root 502: echo ""
503: echo " if the shift count is greater than ${size} - 1, then all of the"
504: echo " bits in the operand, plus at least one zero bit, will appear in"
505: echo " the sign position. the only way that the sign bit will never"
506: echo " change during the shift is if the operand was zero to begin with."
1.1.1.2 root 507: echo " without any changes to sign_bits or sign_bits_mask, the final"
508: echo " test will always work, except when sign_bits is all-bits-one."
509: echo " the magic below clears the least-significant bit of sign_bits"
510: echo " iff sign_bits is all-bits-one: */"
1.1 root 511: echo " sign_bits = res;"
512: fi
513: echo " if (63 > SHIFTMAX_INT${size}_T"
514: echo " && count > ${size}) {"
515: echo " res = 0;"
516: echo " }"
517: echo " res <<= (count - 1);"
518: echo " flags = (res >> (${size} - 1));"
519: echo " flags *= TME_M68K_FLAG_C;"
520: echo " flags |= (flags * TME_M68K_FLAG_X);"
521: echo " res <<= 1;"
522: if test ${name} = asl; then
1.1.1.2 root 523: echo " sign_bits_mask = (tme_uint${size}_t) -1;"
1.1 root 524: echo " if (count != ${size} - 1) {"
525: echo " if (count < ${size}) {"
1.1.1.2 root 526: echo " sign_bits_mask <<= ((${size} - 1) - count);"
1.1 root 527: echo " }"
528: echo " else {"
1.1.1.2 root 529: echo " sign_bits ^= !(sign_bits + 1);"
1.1 root 530: echo " }"
531: echo " }"
1.1.1.2 root 532: echo " sign_bits &= sign_bits_mask;"
533: echo " if (sign_bits != 0 && sign_bits != sign_bits_mask) {"
1.1 root 534: echo " flags |= TME_M68K_FLAG_V;"
535: echo " }"
536: fi
537: ;;
538: ro[lr])
539: echo " count &= (${size} - 1);"
540: if test $dir = l; then
541: echo " res = (res << count) | (res >> (${size} - count));"
542: echo " flags |= ((res & 1) * TME_M68K_FLAG_C);"
543: else
544: echo " res = (res << (${size} - count)) | (res >> count);"
545: echo " flags |= ((res >> (${size} - 1)) * TME_M68K_FLAG_C);"
546: fi
547: ;;
548: rox[lr])
549: echo " count %= (${size} + 1);"
550: echo " flags = xbit;"
551: echo " if (count > 0) {"
552: if test $dir = l; then
553: echo " flags = (res >> (${size} - count)) & 1;"
554: echo " if (${size} > SHIFTMAX_INT${size}_T"
555: echo " && count == ${size}) {"
556: echo " res = 0 | (xbit << (${size} - 1)) | (res >> ((${size} + 1) - ${size}));"
557: echo " }"
558: echo " else if (${size} > SHIFTMAX_INT${size}_T"
559: echo " && count == 1) {"
560: echo " res = (res << 1) | (xbit << (1 - 1)) | 0;"
561: echo " }"
562: echo " else {"
563: echo " res = (res << count) | (xbit << (count - 1)) | (res >> ((${size} + 1) - count));"
564: echo " }"
565: else
566: echo " flags = (res >> (count - 1)) & 1;"
567: echo " if (${size} > SHIFTMAX_INT${size}_T"
568: echo " && count == ${size}) {"
569: echo " res = (res << ((${size} + 1) - ${size})) | (xbit << (${size} - ${size})) | 0;"
570: echo " }"
571: echo " else if (${size} > SHIFTMAX_INT${size}_T"
572: echo " && count == 1) {"
573: echo " res = 0 | (xbit << (${size} - 1)) | (res >> 1);"
574: echo " }"
575: echo " else {"
576: echo " res = (res << ((${size} + 1) - count)) | (xbit << (${size} - count)) | (res >> count);"
577: echo " }"
578: fi
579: echo " }"
580: echo " flags *= TME_M68K_FLAG_C;"
581: echo " flags |= (flags * TME_M68K_FLAG_X);"
582: ;;
583: esac
584: echo " }"
585:
586: echo ""
587: echo " /* store the result: */"
588: echo " TME_M68K_INSN_OP1(tme_${sign}int${size}_t) = res;"
589:
590: echo ""
591: echo " /* generate the N flag. we cast to tme_uint8_t as soon as we"
592: echo " know the bit we want is within the range of the type, to try"
593: echo " to affect the generated assembly: */"
594: echo " flags |= ((tme_uint8_t) (((tme_uint${size}_t) res) >> (${size} - 1))) * TME_M68K_FLAG_N;"
595:
596: echo ""
597: echo " /* generate the Z flag: */"
598: echo " if (res == 0) flags |= TME_M68K_FLAG_Z;"
599:
600: echo ""
601: echo " /* store the flags: */"
602: echo " ic->tme_m68k_ireg_ccr = flags;"
603: echo " TME_M68K_INSN_OK;"
604: echo "}"
605: done
606: done
607:
608: # movep_rm, movep_mr, movem_rm, and movem_mr:
609: for name in rm mr; do
610:
611: # movep and movem don't need 8-bit versions:
612: if test ${size} = 8; then continue; fi
613:
614: # if we're making the header, just emit declarations:
615: if $header; then
616: echo "TME_M68K_INSN_DECL(tme_m68k_movep_${name}${size});"
617: echo "TME_M68K_INSN_DECL(tme_m68k_movem_${name}${size});"
618: continue
619: fi
620:
621: # emit the movep function:
622: echo ""
623: echo "/* the movep_${name} function on a ${size}-bit dreg: */"
624: echo "TME_M68K_INSN(tme_m68k_movep_${name}${size})"
625: echo "{"
626: echo " unsigned int function_code;"
627: echo " tme_uint32_t linear_address;"
628: if test $name = rm; then
629: echo " tme_uint${size}_t value;"
630: fi
631: echo " int dreg;"
632: echo ""
633: echo " TME_M68K_INSN_CANFAULT;"
634: echo ""
635: echo " function_code = TME_M68K_FUNCTION_CODE_DATA(ic);"
636: echo " linear_address = TME_M68K_INSN_OP1(tme_uint32_t);"
637: echo " linear_address += (tme_int32_t) ((tme_int16_t) TME_M68K_INSN_SPECOP);"
638: echo " dreg = TME_M68K_IREG_D0 + TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 9, 3);"
639:
640: # set value:
641: if test $name = rm; then
642: echo " value = ic->tme_m68k_ireg_uint${size}(dreg${reg_size_shift});"
643: value="value"
644: else
645: value="ic->tme_m68k_ireg_uint${size}(dreg${reg_size_shift})"
646: fi
647:
648: # transfer the bytes:
649: pos=${size}
650: while test $pos != 0; do
651: pos=`expr ${pos} - 8`
652: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {"
653: echo " ic->_tme_m68k_ea_function_code = function_code;"
654: echo " ic->_tme_m68k_ea_address = linear_address;"
655: if test $name = rm; then
656: echo " ic->tme_m68k_ireg_memx8 = TME_FIELD_EXTRACTU(${value}, ${pos}, 8);"
657: echo " }"
658: echo " tme_m68k_write_memx8(ic);"
659: else
660: echo " }"
661: echo " tme_m68k_read_memx8(ic);"
662: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {"
663: echo " TME_FIELD_DEPOSIT${size}(${value}, ${pos}, 8, ic->tme_m68k_ireg_memx8);"
664: echo " }"
665: fi
666: echo " linear_address += 2;"
667: done
668:
669: echo " TME_M68K_INSN_OK;"
670: echo "}"
671:
672: # emit the movem function:
673: echo ""
674: echo "/* the movem_${name} function on ${size}-bit registers: */"
675: echo "TME_M68K_INSN(tme_m68k_movem_${name}${size})"
676: echo "{"
677: echo " int ireg, direction;"
678: echo " tme_uint16_t mask, bit;"
679: echo " unsigned int ea_mode;"
680: echo " tme_uint32_t addend;"
681:
682: echo ""
683: echo " /* figure out what direction to move in, and where to start from: */"
684: echo " ea_mode = TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 3, 3);"
685: echo " direction = 1;"
686: echo " ireg = TME_M68K_IREG_D0;"
687: if test $name = rm; then
688: echo " if (ea_mode == 4) {"
689: echo " direction = -1;"
690: echo " ireg = TME_M68K_IREG_A7;"
691: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {"
692: echo " ic->_tme_m68k_ea_address -= sizeof(tme_uint${size}_t);"
693: echo " }"
694: echo " }"
695: fi
696: echo " addend = (tme_uint32_t) (direction * sizeof(tme_uint${size}_t));"
697:
698: echo ""
699: echo " /* do the transfer: */"
700: echo " mask = TME_M68K_INSN_SPECOP;"
1.1.1.2 root 701: echo " if (mask != 0) {"
702: echo " TME_M68K_INSN_CANFAULT;"
703: echo " }"
1.1 root 704: echo " for (bit = 1; bit != 0; bit <<= 1) {"
705: echo " if (mask & bit) {"
706: if test $name = rm; then
707: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {"
708: echo " ic->tme_m68k_ireg_memx${size} = ic->tme_m68k_ireg_uint${size}(ireg${reg_size_shift});"
709: echo " }"
710: echo " tme_m68k_write_memx${size}(ic);"
711: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {"
712: else
713: echo " tme_m68k_read_memx${size}(ic);"
714: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {"
715: echo -n " ic->tme_m68k_ireg_uint32(ireg) = "
716: if test $size = 32; then
717: echo "ic->tme_m68k_ireg_memx${size};"
718: else
719: echo "TME_EXT_S${size}_U32((tme_int${size}_t) ic->tme_m68k_ireg_memx${size});"
720: fi
721: fi
722: echo " ic->_tme_m68k_ea_address += addend;"
723: echo " }"
724: echo " }"
725: echo " ireg += direction;"
726: echo " }"
727: echo ""
728:
729: # for the predecrement and postincrement modes, update the
730: # address register:
731: if test $name = rm; then
732: echo " /* if this is the predecrement mode, update the address register: */"
733: echo " if (ea_mode == 4) {"
734: echo " ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0"
735: echo " + TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 0, 3))"
736: echo " = (ic->_tme_m68k_ea_address + sizeof(tme_uint${size}_t));"
737: echo " }"
738: else
739: echo " /* if this is the postincrement mode, update the address register: */"
740: echo " if (ea_mode == 3) {"
741: echo " ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0"
742: echo " + TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 0, 3))"
743: echo " = ic->_tme_m68k_ea_address;"
744: echo " }"
745: fi
746:
747: echo " TME_M68K_INSN_OK;"
748: echo "}"
749: done
750:
751: # chk32 and chk16:
752: if test $size != 8; then
753:
754: # if we're making the header, just emit a declaration:
755: if $header; then
756: echo "TME_M68K_INSN_DECL(tme_m68k_chk${size});"
757: else
758: echo ""
759: echo "/* chk${size}: */"
760: echo "TME_M68K_INSN(tme_m68k_chk${size})"
761: echo "{"
762: echo " if (*((tme_int${size}_t *) _op0) < 0) {"
763: echo " ic->tme_m68k_ireg_ccr |= TME_M68K_FLAG_N;"
1.1.1.3 ! root 764: echo " ic->tme_m68k_ireg_pc_last = ic->tme_m68k_ireg_pc;"
1.1 root 765: echo " ic->tme_m68k_ireg_pc = ic->tme_m68k_ireg_pc_next;"
1.1.1.3 ! root 766: echo " TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_INST(TME_M68K_VECTOR_CHK));"
1.1 root 767: echo " }"
768: echo " if (*((tme_int${size}_t *) _op0) > *((tme_int${size}_t *) _op1)) {"
769: echo " ic->tme_m68k_ireg_ccr &= ~TME_M68K_FLAG_N;"
1.1.1.3 ! root 770: echo " ic->tme_m68k_ireg_pc_last = ic->tme_m68k_ireg_pc;"
1.1 root 771: echo " ic->tme_m68k_ireg_pc = ic->tme_m68k_ireg_pc_next;"
1.1.1.3 ! root 772: echo " TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_INST(TME_M68K_VECTOR_CHK));"
1.1 root 773: echo " }"
774: echo " TME_M68K_INSN_OK;"
775: echo "}"
776: fi
777: fi
778:
779: # cas and cas2:
780: for name in cas cas2_; do
781:
782: # cas2 doesn't do byte operands:
783: buffers=x
784: if test $name = cas2_; then
785: if test $size = 8; then continue; fi
786: buffers="x y"
787: fi
788:
789: if $header; then
790: echo "TME_M68K_INSN_DECL(tme_m68k_${name}${size});"
791: else
792: echo ""
793: echo "/* ${name}${size}: */"
794: echo "TME_M68K_INSN(tme_m68k_${name}${size})"
795: echo "{"
796: echo " struct tme_m68k_tlb *tlb;"
797: echo " int ireg_dc, ireg_du;"
798: echo " int do_write;"
799: echo " tme_uint16_t specopx = ic->_tme_m68k_insn_specop;"
800: if test $name = cas2_; then
1.1.1.3 ! root 801: echo " tme_uint16_t specopy = TME_M68K_INSN_OP0(tme_uint16_t);"
1.1 root 802: echo " tme_uint32_t addrx;"
803: echo " tme_uint32_t addry;"
804: echo ""
805: echo " /* get the function code and addresses we'll be dealing with: */"
806: echo " ic->_tme_m68k_ea_function_code = TME_M68K_FUNCTION_CODE_DATA(ic);"
807: echo " addrx = ic->tme_m68k_ireg_uint32(TME_M68K_IREG_D0"
808: echo " + TME_FIELD_EXTRACTU(specopx, 12, 4));"
809: echo " addry = ic->tme_m68k_ireg_uint32(TME_M68K_IREG_D0"
810: echo " + TME_FIELD_EXTRACTU(specopy, 12, 4));"
811: fi
812: echo ""
813: echo " /* start the read/modify/write cycle: */"
814: echo " tlb = tme_m68k_rmw_start(ic);"
815: echo " if (tlb == NULL) {"
816: echo " TME_M68K_INSN_OK;"
817: echo " }"
818: echo ""
819: echo " /* read: */"
820: for buffer in $buffers; do
821: if test $name = cas2_; then
822: echo " ic->_tme_m68k_ea_address = addr${buffer};"
823: fi
824: echo " tme_m68k_read${size}(ic, tlb,"
825: echo " &ic->_tme_m68k_ea_function_code,"
826: echo " &ic->_tme_m68k_ea_address,"
827: echo " &ic->tme_m68k_ireg_mem${buffer}${size},"
828: echo " TME_M68K_BUS_CYCLE_RMW);"
829: done
830:
831: echo ""
832: echo " /* modify: */"
833: for buffer in $buffers; do
834: i=
835: if test $buffer = y; then
836: echo " if (ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_Z) {"
837: i=" "
838: fi
839: echo "${i} ireg_dc = TME_M68K_IREG_D0 + TME_FIELD_EXTRACTU(specop${buffer}, 0, 3);"
840: echo "${i} tme_m68k_cmp${size}(ic, &ic->tme_m68k_ireg_uint${size}(ireg_dc), &ic->tme_m68k_ireg_mem${buffer}${size});"
841: if test $buffer = y; then
842: echo " }"
843: fi
844: done
845:
846: echo ""
847: echo " /* write: */"
848: echo " if (ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_Z) {"
849: for buffer in $buffers; do
850: if test $name = cas2_; then
851: echo " ic->_tme_m68k_ea_address = addr${buffer};"
852: fi
853: echo " ireg_du = TME_M68K_IREG_D0 + TME_FIELD_EXTRACTU(specop${buffer}, 6, 3);"
854: echo " ic->tme_m68k_ireg_mem${buffer}${size} = ic->tme_m68k_ireg_uint${size}(ireg_du);"
855: echo " tme_m68k_write${size}(ic, tlb,"
856: echo " &ic->_tme_m68k_ea_function_code,"
857: echo " &ic->_tme_m68k_ea_address,"
858: echo " &ic->tme_m68k_ireg_mem${buffer}${size},"
859: echo " TME_M68K_BUS_CYCLE_RMW);"
860: done
861: echo " }"
862: echo " else {"
863: echo " /* XXX the 68040 always does a write to finish its cycle: */"
864: echo " do_write = FALSE;"
865: for buffer in $buffers; do
866: echo " ireg_dc = TME_M68K_IREG_D0 + TME_FIELD_EXTRACTU(specop${buffer}, 0, 3);"
867: echo -n " if (do_write"
868: if test $name = cas2_; then
869: echo ""
870: echo " && ic->tme_m68k_ireg_mem${buffer}${size} != ic->tme_m68k_ireg_uint${size}(ireg_dc)) {"
871: echo " ic->_tme_m68k_ea_address = addr${buffer};"
872: else
873: echo ") {"
874: fi
875: echo " tme_m68k_write${size}(ic, tlb,"
876: echo " &ic->_tme_m68k_ea_function_code,"
877: echo " &ic->_tme_m68k_ea_address,"
878: echo " &ic->tme_m68k_ireg_mem${buffer}${size},"
879: echo " TME_M68K_BUS_CYCLE_RMW);"
880: echo " do_write = FALSE;"
881: echo " }"
882: echo " ic->tme_m68k_ireg_uint${size}(ireg_dc) = ic->tme_m68k_ireg_mem${buffer}${size};"
883: done
884: echo " }"
885: echo ""
886: echo " /* finish the read/modify/write cycle: */"
887: echo " tme_m68k_rmw_finish(ic, tlb);"
888: echo ""
889: echo " TME_M68K_INSN_OK;"
890: echo "}"
891: fi
892: done
893:
894: # moves:
895: if $header; then
896: echo "TME_M68K_INSN_DECL(tme_m68k_moves${size});"
897: else
898: echo ""
899: echo "/* moves${size}: */"
900: echo "TME_M68K_INSN(tme_m68k_moves${size})"
901: echo "{"
902: echo " int ireg;"
1.1.1.3 ! root 903: echo " unsigned int ea_reg;"
! 904: echo " unsigned int increment;"
! 905: echo " TME_M68K_INSN_PRIV;"
! 906: echo " TME_M68K_INSN_CANFAULT;"
1.1 root 907: echo " ireg = TME_M68K_IREG_D0 + TME_FIELD_EXTRACTU(TME_M68K_INSN_SPECOP, 12, 4);"
1.1.1.3 ! root 908: echo ""
! 909: echo " /* we have to handle postincrement and predecrement ourselves: */"
! 910: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {"
! 911: echo " ea_reg = TME_M68K_IREG_A0 + TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 0, 3);"
! 912: echo " increment = TME_M68K_SIZE_${size};"
! 913: echo " if (increment == TME_M68K_SIZE_8 && ea_reg == TME_M68K_IREG_A7) {"
! 914: echo " increment = TME_M68K_SIZE_16;"
! 915: echo " }"
! 916: echo " switch (TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 3, 3)) {"
! 917: echo " case 3: ic->tme_m68k_ireg_uint32(ea_reg) += increment; break;"
! 918: echo " case 4: ic->_tme_m68k_ea_address = (ic->tme_m68k_ireg_uint32(ea_reg) -= increment); break;"
! 919: echo " default: break;"
! 920: echo " }"
! 921: echo " }"
! 922: echo ""
1.1 root 923: echo " if (TME_M68K_INSN_SPECOP & TME_BIT(11)) {"
1.1.1.3 ! root 924: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {"
! 925: echo " ic->tme_m68k_ireg_memx${size} = ic->tme_m68k_ireg_uint${size}(ireg${reg_size_shift});"
! 926: echo " ic->_tme_m68k_ea_function_code = ic->tme_m68k_ireg_dfc;"
! 927: echo " }"
! 928: echo " tme_m68k_write_memx${size}(ic);"
1.1 root 929: echo " }"
930: echo " else {"
1.1.1.3 ! root 931: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {"
! 932: echo " ic->_tme_m68k_ea_function_code = ic->tme_m68k_ireg_sfc;"
! 933: echo " }"
! 934: echo " tme_m68k_read_memx${size}(ic);"
1.1 root 935: if test ${size} != 32; then
936: echo " if (ireg >= TME_M68K_IREG_A0) {"
937: echo " ic->tme_m68k_ireg_uint32(ireg) = "
938: echo " TME_EXT_S${size}_U32((tme_int${size}_t) ic->tme_m68k_ireg_memx${size});"
939: echo " }"
940: echo " else"
941: echo -n " "
942: fi
943: echo " ic->tme_m68k_ireg_uint${size}(ireg${reg_size_shift}) = ic->tme_m68k_ireg_memx${size};"
944: echo " }"
945: echo " TME_M68K_INSN_OK;"
946: echo "}"
947: fi
948: done
949:
950: # generate the memory read and write functions:
951:
952: # permute on size:
953: for size in 8 16 32 any; do
954:
955: # permute on read or write:
956: for name in read write; do
957: capname=`echo $name | tr a-z A-Z`
958: if test $name = read; then
959: lockname="rd"
960: from="from"
961: else
962: lockname="wr"
963: from="to"
964: fi
965:
966: # permute on the special-purpose what:
967: for what in memx mem inst stack; do
968:
969: # placeholder for another permutation:
970: :
971:
972: # dispatch on the size:
973: _first=_first ; _last=_last
974: case "$size" in
975: 8) _first= ; _last= ;;
976: esac
977:
978: # set up the details of each special purpose:
979: rval="void"
980: args=""
981: args_proto=""
982: fc=""
983: addr=""
984: count=""
985: tlb="TME_M68K_TLB_ENTRY(ic, function_code, linear_address${_first})"
986: flags="TME_M68K_BUS_CYCLE_NORMAL"
987: case "${name}-${what}-${size}" in
988: *-memx-8 | *-memx-16 | *-memx-32)
989: action="${name}_${what}${size}"
990: fcptr="&ic->_tme_m68k_ea_function_code"
991: addrptr="&ic->_tme_m68k_ea_address"
992: reg="ic->tme_m68k_ireg_memx${size}"
993: regptr="&${reg}"
994: ;;
995: *-mem-any)
996: action="${name}_${what}"
997: args_proto=", tme_uint8_t *, unsigned int"
998: args=", tme_uint8_t *buffer, unsigned int count"
999: fcptr="&ic->_tme_m68k_ea_function_code"
1000: addrptr="&ic->_tme_m68k_ea_address"
1001: reg=
1002: regptr="buffer"
1003: ;;
1004: *-mem-8 | *-mem-16 | *-mem-32)
1005: action="${name}_${what}${size}"
1006: args_proto=", int"
1007: args="${args_proto} ireg"
1008: fcptr="&ic->_tme_m68k_ea_function_code"
1009: addrptr="&ic->_tme_m68k_ea_address"
1010: reg="ic->tme_m68k_ireg_uint${size}(ireg)"
1011: regptr="&${reg}"
1012: ;;
1013: read-stack-16 | read-stack-32)
1014: action="pop${size}"
1015: args_proto=", tme_uint${size}_t *"
1016: args="${args_proto}_value"
1017: fc="TME_M68K_FUNCTION_CODE_DATA(ic)"
1018: addrptr="&ic->tme_m68k_ireg_a7"
1019: regptr="_value"
1020: reg="*${regptr}"
1021: ;;
1022: write-stack-16 | write-stack-32)
1023: action="push${size}"
1024: args_proto=", tme_uint${size}_t "
1025: args="${args_proto}value"
1026: fc="TME_M68K_FUNCTION_CODE_DATA(ic)"
1027: addr="ic->tme_m68k_ireg_a7 - sizeof(tme_uint${size}_t)"
1028: reg="value"
1029: regptr="&${reg}"
1030: ;;
1031: read-inst-16 | read-inst-32)
1032: rval="tme_uint${size}_t"
1033: action="fetch${size}"
1034: args_proto=", tme_uint32_t"
1035: args="${args_proto} pc"
1036: fc="TME_M68K_FUNCTION_CODE_PROGRAM(ic)"
1037: addrptr="&pc"
1038: tlb="TME_ATOMIC_READ(struct tme_m68k_tlb *, ic->_tme_m68k_itlb)";
1039: flags="TME_M68K_BUS_CYCLE_FETCH"
1040: ;;
1041: *)
1042: continue
1043: ;;
1044: esac
1045:
1046: # if we're making the header, just emit a declaration:
1047: if $header; then
1048: echo "${rval} tme_m68k_${action} _TME_P((struct tme_m68k *${args_proto}));"
1049: continue
1050: fi
1051:
1052: # start the function:
1053: echo ""
1054: echo "/* this ${name}s a ${size}-bit ${what} value: */"
1055: echo "${rval}"
1056: echo "tme_m68k_${action}(struct tme_m68k *ic${args}) "
1057: echo "{"
1058:
1059: # our locals:
1060: echo -n " unsigned int function_code = "
1061: if test "x${fc}" != x; then
1062: echo "${fc};"
1063: fc="function_code"
1064: fcptr="&function_code"
1065: else
1066: fc=`echo ${fcptr} | sed -e 's,^&,,'`
1067: echo "${fc};"
1068: fi
1069: echo -n " tme_uint32_t linear_address${_first} = "
1070: if test "x${addr}" != x; then
1071: echo "${addr};"
1072: addr="linear_address${_first}"
1073: addrptr="&linear_address${_first}"
1074: else
1075: addr=`echo ${addrptr} | sed -e 's,^&,,'`
1076: echo "${addr};"
1077: fi
1078: if test "x${count}" = x; then
1079: if test $size = any; then count=count; else count="sizeof(tme_uint${size}_t)"; fi
1080: fi
1081: if test x$_last != x; then
1082: echo " tme_uint32_t linear_address${_last} = linear_address_first + ${count} - 1;";
1083: fi
1084: echo " struct tme_m68k_tlb *tlb = ${tlb};"
1085: case "$what" in
1086: inst)
1087: echo " unsigned int insn_buffer_off = TME_ALIGN(ic->_tme_m68k_insn_buffer_off, sizeof(tme_uint${size}_t));"
1088: regptr="((tme_uint${size}_t *) &ic->_tme_m68k_insn_buffer[insn_buffer_off])"
1089: reg="*${regptr}"
1090: ;;
1091: esac
1092:
1.1.1.3 ! root 1093: # track statistics:
! 1094: echo ""
! 1095: echo "#ifdef _TME_M68K_STATS"
! 1096: echo " ic->tme_m68k_stats.tme_m68k_stats_memory_total++;"
! 1097: echo "#endif /* _TME_M68K_STATS */"
! 1098:
1.1 root 1099: # if this is a write, log the value written:
1100: if test $name = write; then
1101: echo ""
1102: echo " /* log the value written: */"
1103: if test $size != any; then
1104: echo " tme_m68k_verify_mem${size}(ic, ${fc}, ${addr}, ${reg}, TME_BUS_CYCLE_WRITE);"
1105: echo " tme_m68k_log(ic, 1000, TME_OK, "
1106: echo " (TME_M68K_LOG_HANDLE(ic),"
1107: echo " _(\"${action}\t%d:0x%08x:\t0x%0"`expr ${size} / 4`"x\"),"
1108: echo " ${fc},"
1109: echo " ${addr},"
1110: echo " ${reg}));"
1111: else
1112: echo " tme_m68k_verify_mem_any(ic, ${fc}, ${addr}, ${regptr}, ${count}, TME_BUS_CYCLE_WRITE);"
1113: echo " tme_m68k_log_start(ic, 1000, TME_OK) {"
1114: echo " unsigned int byte_i;"
1115: echo " tme_log_part(TME_M68K_LOG_HANDLE(ic),"
1116: echo " _(\"${action} %d:0x%08x count %d:\"),"
1117: echo " ${fc},"
1118: echo " ${addr},"
1119: echo " ${count});"
1120: echo " for (byte_i = 0; byte_i < count ; byte_i++) {"
1121: echo " tme_log_part(TME_M68K_LOG_HANDLE(ic), \" 0x%02x\", (${regptr})[byte_i]);"
1122: echo " }"
1123: echo " } tme_m68k_log_finish(ic);"
1124: fi
1125: fi
1126:
1127: echo ""
1128: echo " /* do the bus cycle(s) ourselves from emulator memory if we can."
1129: echo " the emulator memory allocator and TLB filler must guarantee"
1130: echo " that all tme_m68k_tlb_emulator_off_${name} pointers be 32-bit"
1131: echo " aligned, so that a 16-bit-aligned linear address gets a"
1132: echo " 16-bit-aligned emulator address: */"
1133: echo " if (__tme_predict_true(!TME_M68K_SEQUENCE_RESTARTING"
1134: if test $size != 8; then
1135: echo " && !(linear_address${_first} & 1)"
1136: fi
1137: echo " && TME_M68K_TLB_OK_FAST_${capname}(tlb,"
1138: echo " function_code,"
1139: echo " linear_address${_first},"
1140: echo " linear_address${_last}))) {"
1141:
1142: memptr="(tlb->tme_m68k_tlb_emulator_off_${name} + linear_address${_first})"
1143: mem="*((tme_uint${size}_t *) ${memptr})"
1144: if test $name = read; then
1145: simple="${reg} = tme_betoh_u${size}(${mem});"
1146: else
1147: simple="${mem} = tme_htobe_u${size}(${reg});"
1148: fi
1149:
1150: echo ""
1151:
1152: # if this is an 8-bit transfer:
1153: if test $size = 8; then
1154: echo " /* for an 8-bit transfer we can always do a simple "
1155: echo " assignment. the ${lockname}lock is unnecessary, since we assume"
1156: echo " that 8-bit accesses are always atomic: */"
1157: if test $name = read; then
1158: echo " ${reg} = ${mem};"
1159: else
1160: echo " ${mem} = ${reg};"
1161: fi
1162:
1163: # if this is a 16-bit transfer:
1164: elif test $size = 16; then
1165: echo " /* for a 16-bit transfer we can always do a simple"
1166: echo " assignment - we tested that the linear address"
1167: echo " is 16-bit aligned, which, since the TLB emulator"
1168: echo " offset is guaranteed to be 32-bit aligned, guarantees"
1169: echo " that the final emulator address is 16-bit aligned."
1170: echo ""
1171: echo " we need the ${lockname}lock if we're on an architecture"
1172: echo " where an aligned access may not be atomic: */"
1173: echo " tme_memory_aligned_${lockname}lock(tlb->tme_m68k_tlb_bus_rwlock);"
1174: echo " ${simple}"
1175: echo " tme_memory_aligned_unlock(tlb->tme_m68k_tlb_bus_rwlock);"
1176:
1177: # if this is a 32-bit transfer:
1178: elif test $size = 32; then
1179:
1180: echo " /* if the emulator host allows ${size}-bit quantities to be"
1181: echo " transferred ${from} 16-bit aligned addresses, or if this"
1182: echo " address is ${size}-bit aligned, do the transfer as a simple"
1183: echo " assignment, otherwise transfer two 16-bit words."
1184: echo ""
1185: echo " we need the ${lockname}lock if we're on an architecture where"
1186: echo " an aligned access may not be atomic, or if we're doing"
1187: echo " an unaligned access on an architecture where they may"
1188: echo " not be atomic: */"
1189: misaligned="(linear_address${_first} & (sizeof(tme_uint${size}_t) - 1))"
1190: echo "#if ALIGNOF_INT${size}_T <= ALIGNOF_INT16_T"
1191: echo "#ifdef TME_UNALIGNED_ACCESS_ATOMIC"
1192: echo " ${simple}"
1193: echo "#else /* !TME_UNALIGNED_ACCESS_ATOMIC */"
1194: echo " if (${misaligned}) {"
1195: echo " tme_memory_unaligned_${lockname}lock(tlb->tme_m68k_tlb_bus_rwlock);"
1196: echo " ${simple}"
1197: echo " tme_memory_unaligned_unlock(tlb->tme_m68k_tlb_bus_rwlock);"
1198: echo " }"
1199: echo " else {"
1200: echo " tme_memory_aligned_${lockname}lock(tlb->tme_m68k_tlb_bus_rwlock);"
1201: echo " ${simple}"
1202: echo " tme_memory_aligned_unlock(tlb->tme_m68k_tlb_bus_rwlock);"
1203: echo " }"
1204: echo "#endif /* !TME_UNALIGNED_ACCESS_ATOMIC */"
1205: echo "#else /* ALIGNOF_INT${size}_T > ALIGNOF_INT16_T */"
1206: echo " if (TME_SEQUENCE_ACCESS_NOT_COSTLIER || ${misaligned}) {"
1207: echo " tme_memory_sequence_${lockname}lock(tlb->tme_m68k_tlb_bus_rwlock); "
1208: if test $name = read; then
1209: echo "#ifdef WORDS_BIGENDIAN"
1210: echo " ${reg} = (((tme_uint${size}_t) ((tme_uint16_t *) ${memptr})[0]) << 16) | ((tme_uint16_t *) ${memptr})[1];"
1211: echo "#else /* !WORDS_BIGENDIAN */"
1212: echo " ${reg} = tme_betoh_u32((((tme_uint${size}_t) ((tme_uint16_t *) ${memptr})[1]) << 16) | ((tme_uint16_t *) ${memptr})[0]);"
1213: echo "#endif /* !WORDS_BIGENDIAN */"
1214: else
1215: echo " ((tme_uint16_t *) ${memptr})[0] = tme_htobe_u16(${reg} >> 16);"
1216: echo " ((tme_uint16_t *) ${memptr})[1] = tme_htobe_u16(${reg} & 0xffff);"
1217: fi
1218: echo " tme_memory_sequence_unlock(tlb->tme_m68k_tlb_bus_rwlock); "
1219: echo " }"
1220: echo " else {"
1221: echo " tme_memory_aligned_${lockname}lock(tlb->tme_m68k_tlb_bus_rwlock); "
1222: echo " ${simple}"
1223: echo " tme_memory_aligned_unlock(tlb->tme_m68k_tlb_bus_rwlock); "
1224: echo " }"
1225: echo "#endif /* ALIGNOF_INT${size}_T != 1 */"
1226:
1227: # if this is an any-transfer:
1228: elif test $size = any; then
1229: echo " tme_memory_sequence_${lockname}lock(tlb->tme_m68k_tlb_bus_rwlock);"
1230: if test $name = read; then
1231: echo " memcpy(${regptr}, ${memptr}, ${count});"
1232: else
1233: echo " memcpy(${memptr}, ${regptr}, ${count});"
1234: fi
1235: echo " tme_memory_sequence_unlock(tlb->tme_m68k_tlb_bus_rwlock);"
1236:
1237: fi
1238: echo " TME_M68K_SEQUENCE_TRANSFER_STEP;"
1239: echo " }"
1240:
1241: echo ""
1242: echo " /* otherwise, do the bus cycles the slow way: */"
1243: echo " else {"
1244: if test $size != any; then
1245: echo " tme_m68k_${name}${size}(ic, tlb,"
1246: echo " ${fcptr},"
1247: echo " ${addrptr},"
1248: echo " ${regptr},"
1249: echo " ${flags});"
1250: else
1251: echo " tme_m68k_${name}(ic, tlb, ${fcptr}, ${addrptr}, ${regptr}, ${count}, TME_M68K_BUS_CYCLE_RAW);"
1252: fi
1253: echo " }"
1254:
1255: # if this is a read, log the value read:
1256: if test $name = read; then
1257: echo ""
1258: echo " /* log the value read: */"
1259: if test $size != any; then
1260: echo " tme_m68k_verify_mem${size}(ic, ${fc}, ${addr}, ${reg}, TME_BUS_CYCLE_READ);"
1261: echo " tme_m68k_log(ic, 1000, TME_OK,"
1262: echo " (TME_M68K_LOG_HANDLE(ic),"
1263: echo " _(\"${action}\t%d:0x%08x:\t0x%0"`expr ${size} / 4`"x\"),"
1264: echo " ${fc},"
1265: echo " ${addr},"
1266: echo " ${reg}));"
1267: else
1268: echo " tme_m68k_verify_mem_any(ic, ${fc}, ${addr}, ${regptr}, ${count}, TME_BUS_CYCLE_READ);"
1269: echo " tme_m68k_log_start(ic, 1000, TME_OK) {"
1270: echo " unsigned int byte_i;"
1271: echo " tme_log_part(TME_M68K_LOG_HANDLE(ic),"
1272: echo " _(\"${action} %d:0x%08x count %d:\"),"
1273: echo " ${fc},"
1274: echo " ${addr},"
1275: echo " ${count});"
1276: echo " for (byte_i = 0; byte_i < count ; byte_i++) {"
1277: echo " tme_log_part(TME_M68K_LOG_HANDLE(ic), \" 0x%02x\", (${regptr})[byte_i]);"
1278: echo " }"
1279: echo " } tme_m68k_log_finish(ic);"
1280: fi
1281: fi
1282:
1283: # perform any updating and value returning:
1284: case "$what" in
1285: stack)
1286: if test $name = read; then dir="+"; else dir="-"; fi
1287: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {"
1288: echo " ic->tme_m68k_ireg_a7 ${dir}= sizeof(tme_uint${size}_t);"
1289: echo " }"
1290: ;;
1291: inst)
1292: echo " ic->_tme_m68k_insn_buffer_off = insn_buffer_off + sizeof(tme_uint${size}_t);"
1293: echo " return(${reg});"
1294: ;;
1295: esac
1296:
1297: echo "}"
1298: :
1299: done
1300:
1301: # the general-purpose cycle-making read and write macros:
1302: if test ${size} != any; then
1303:
1304: # if we're making the header, emit a macro:
1305: if $header; then
1306: echo "#define tme_m68k_${name}${size}(ic, t, fc, la, _v, f) \\"
1307: echo " tme_m68k_${name}(ic, t, fc, la, (tme_uint8_t *) (_v), sizeof(tme_uint${size}_t), f)"
1308: fi
1309: else
1310:
1311: # if we're making the header, just emit a declaration:
1312: if $header; then
1313: echo "void tme_m68k_${name} _TME_P((struct tme_m68k *, struct tme_m68k_tlb *, unsigned int *, tme_uint32_t *, tme_uint8_t *, unsigned int, unsigned int));"
1314: continue
1315: fi
1316:
1317: echo ""
1318: echo "/* this ${name}s a region of address space using actual bus cycles: */"
1319: echo "void"
1320: echo "tme_m68k_${name}(struct tme_m68k *ic, "
1321: echo " struct tme_m68k_tlb *tlb,"
1322: echo " unsigned int *_function_code, "
1323: echo " tme_uint32_t *_linear_address, "
1324: echo " tme_uint8_t *reg,"
1325: echo " unsigned int reg_size,"
1326: echo " unsigned int flags)"
1327: echo "{"
1328:
1329: # our locals:
1330: echo " unsigned int function_code;"
1331: echo " tme_uint32_t linear_address;"
1332: echo " tme_bus_addr_t physical_address;"
1333: echo " int shift;"
1334: echo " struct tme_bus_cycle cycle;"
1335: echo " unsigned int transferred, resid, cycle_size;"
1336: echo " int exception;"
1337: echo " tme_rwlock_t *rmw_rwlock;"
1338: echo " int err;"
1339: echo "#ifndef WORDS_BIGENDIAN"
1340: echo " tme_uint8_t *reg_p;"
1341: echo " unsigned int buffer_i;"
1342: echo "#endif /* !WORDS_BIGENDIAN */"
1343:
1344: echo ""
1345: echo " /* if we're not restarting, everything is fresh: */"
1346: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {"
1347: echo " function_code = *_function_code;"
1348: echo " linear_address = *_linear_address;"
1349: echo " transferred = 0;"
1350: echo " }"
1351:
1352: echo ""
1353: echo " /* otherwise, if this is the transfer that faulted, restore"
1354: echo " our state to the cycle that faulted, then take into account"
1355: echo " any data provided by a software rerun of the faulted cycle: */"
1356: echo " else if (ic->_tme_m68k_sequence._tme_m68k_sequence_transfer_faulted"
1357: echo " == ic->_tme_m68k_sequence._tme_m68k_sequence_transfer_next) {"
1358: echo " function_code = *_function_code = ic->_tme_m68k_group0_function_code;"
1359: echo " linear_address = ic->_tme_m68k_group0_address;"
1360: echo " transferred = ic->_tme_m68k_sequence._tme_m68k_sequence_transfer_faulted_after;"
1361: echo " if (transferred >= reg_size) abort();"
1362: echo " *_linear_address = linear_address - transferred;"
1363: echo " resid = reg_size - transferred;"
1364: echo " if (ic->_tme_m68k_group0_buffer_${name}_size > resid) abort();"
1365: echo " if (ic->_tme_m68k_group0_buffer_${name}_softrr > resid) abort();"
1366: if test $name = read; then cmp=">"; else cmp="=="; fi
1367: echo " if (ic->_tme_m68k_group0_buffer_${name}_softrr ${cmp} 0) {"
1368: echo "#ifdef WORDS_BIGENDIAN"
1369: echo " memcpy(reg + transferred, "
1370: echo " ic->_tme_m68k_group0_buffer_${name},"
1371: echo " ic->_tme_m68k_group0_buffer_${name}_size);"
1372: echo "#else /* !WORDS_BIGENDIAN */"
1373: echo " reg_p = (reg + reg_size - 1) - transferred;"
1374: echo " for (buffer_i = 0;"
1375: echo " buffer_i < ic->_tme_m68k_group0_buffer_${name}_size;"
1376: echo " buffer_i++) {"
1377: echo " *(reg_p--) = ic->_tme_m68k_group0_buffer_${name}[buffer_i];"
1378: echo " }"
1379: echo "#endif /* !WORDS_BIGENDIAN */"
1380: echo " }"
1381: echo " transferred += ic->_tme_m68k_group0_buffer_${name}_softrr;"
1382: echo " }"
1383:
1384: echo ""
1385: echo " /* otherwise, a later transfer has faulted. just step the"
1386: echo " transfer number and return: */"
1387: echo " else {"
1388: echo " TME_M68K_SEQUENCE_TRANSFER_STEP;"
1389: echo " return;"
1390: echo " }"
1391:
1392: echo ""
1393: echo " /* do as many bus cycles as needed to complete the transfer: */"
1394: echo " rmw_rwlock = tlb->tme_m68k_tlb_bus_rwlock;"
1395: echo " exception = TME_M68K_EXCEPTION_NONE;"
1396: echo " cycle_size = 0;"
1397: echo " for(; transferred < reg_size; ) {"
1398: echo " resid = reg_size - transferred;"
1399:
1400: echo ""
1401: echo " /* start the bus cycle structure: */"
1402: echo " cycle.tme_bus_cycle_type = TME_BUS_CYCLE_${capname};"
1403: echo " if (TME_ENDIAN_NATIVE == TME_ENDIAN_BIG"
1404: echo " || (flags & TME_M68K_BUS_CYCLE_RAW)) {"
1405: echo " cycle.tme_bus_cycle_buffer = reg + transferred;"
1406: echo " cycle.tme_bus_cycle_buffer_increment = 1;"
1407: echo " }"
1408: echo " else {"
1409: echo " cycle.tme_bus_cycle_buffer = reg + reg_size - (1 + transferred);"
1410: echo " cycle.tme_bus_cycle_buffer_increment = -1;"
1411: echo " }"
1412:
1413: echo ""
1414: echo " /* if we're emulating a CPU with a 16-bit bus interface: */"
1415: echo " if (ic->_tme_m68k_bus_16bit) {"
1416: echo ""
1417: echo " /* if we're trying to transfer a non-power-of-two"
1418: echo " number of bytes, either the CPU is broken (no"
1419: echo " instructions ever transfer a non-power-of-two"
1420: echo " number of bytes), or this function allowed an"
1421: echo " unaligned transfer: */"
1422: echo " assert((resid & (resid - 1)) == 0"
1423: echo " || (flags & TME_M68K_BUS_CYCLE_RAW));"
1424: echo ""
1425: echo " /* only byte transfers can be unaligned: */"
1426: echo " if (resid > sizeof(tme_uint8_t)"
1427: echo " && (linear_address & 1)) {"
1.1.1.3 ! root 1428: echo " exception = TME_M68K_EXCEPTION_AERR;"
1.1 root 1429: echo " break;"
1430: echo " }"
1431: echo ""
1432: echo " /* set the bus-size specific parts of the bus cycle structure: */"
1433: echo " cycle_size = TME_MIN(resid, sizeof(tme_uint16_t));"
1434: echo " cycle.tme_bus_cycle_size = cycle_size;"
1435: echo " cycle.tme_bus_cycle_port = TME_BUS_CYCLE_PORT(0, TME_BUS16_LOG2);"
1436: echo " cycle.tme_bus_cycle_lane_routing = "
1437: echo " &tme_m68k_router_16[TME_M68K_BUS_ROUTER_INDEX(TME_BUS16_LOG2, cycle_size, linear_address)];"
1438: echo " }"
1439: echo ""
1440: echo " /* otherwise we're emulating a CPU with a 32-bit bus interface: */"
1441: echo " else {"
1442: if test $name = read; then
1443: echo ""
1444: echo " /* an instruction fetch must be aligned: */"
1445: echo " if (flags & TME_M68K_BUS_CYCLE_FETCH) {"
1446: echo " if (linear_address & 1) {"
1.1.1.3 ! root 1447: echo " exception = TME_M68K_EXCEPTION_AERR;"
1.1 root 1448: echo " break;"
1449: echo " }"
1450: echo " assert(!(resid & 1));"
1451: echo " }"
1452: fi
1453: echo ""
1454: echo " /* set the bus-size specific parts of the bus cycle structure: */"
1455: echo " cycle_size = TME_MIN(resid, sizeof(tme_uint32_t) - (linear_address & (sizeof(tme_uint32_t) - 1)));"
1456: echo " cycle.tme_bus_cycle_size = cycle_size;"
1457: echo " cycle.tme_bus_cycle_port = TME_BUS_CYCLE_PORT(0, TME_BUS32_LOG2);"
1458: echo " cycle.tme_bus_cycle_lane_routing = "
1459: echo " &tme_m68k_router_32[TME_M68K_BUS_ROUTER_INDEX(TME_BUS32_LOG2, cycle_size, linear_address)];"
1460: echo " }"
1461:
1462: echo ""
1463: echo " /* reload the TLB entry: */"
1464: echo " if (!TME_M68K_TLB_OK_SLOW_${capname}(tlb, function_code, linear_address)) {"
1465: echo " tme_m68k_tlb_fill(ic, tlb,"
1466: echo " function_code,"
1467: echo " linear_address,"
1468: echo " TME_BUS_CYCLE_${capname});"
1469: echo " }"
1470: echo ""
1471: echo " /* if this is a part of a read/modify/write cycle: */"
1472: echo " if (flags & TME_M68K_BUS_CYCLE_RMW) {"
1473: echo ""
1474: echo " /* if this TLB entry doesn't support fast ${name}s, or"
1475: echo " if the TLB lock has changed, that's a bus error."
1476: echo " see the discussion in tme_m68k_rmw_start: */"
1477: echo " if (!TME_M68K_TLB_OK_FAST_${capname}(tlb, function_code, linear_address, linear_address)"
1478: echo " || (rmw_rwlock != NULL"
1479: echo " && rmw_rwlock != tlb->tme_m68k_tlb_bus_rwlock)) {"
1.1.1.3 ! root 1480: echo " exception = TME_M68K_EXCEPTION_BERR;"
1.1 root 1481: echo " break;"
1482: echo " }"
1483: echo ""
1484: echo " /* if we haven't locked this memory yet, do so: */"
1485: echo " if (rmw_rwlock == NULL) {"
1486: echo " rmw_rwlock = tlb->tme_m68k_tlb_bus_rwlock;"
1487: echo " tme_rwlock_wrlock(rmw_rwlock);"
1488: echo " }"
1489: echo " }"
1490:
1491: echo ""
1492: echo " /* form the physical address for the bus cycle handler: */"
1493: echo " physical_address = tlb->tme_m68k_tlb_addr_offset + linear_address;"
1494: echo " shift = tlb->tme_m68k_tlb_addr_shift;"
1495: echo " if (shift < 0) {"
1496: echo " physical_address <<= (0 - shift);"
1497: echo " }"
1498: echo " else if (shift > 0) {"
1499: echo " physical_address >>= shift;"
1500: echo " }"
1501: echo " cycle.tme_bus_cycle_address = physical_address;"
1502:
1503: echo ""
1504: echo " /* run the bus cycle: */"
1505: echo " err = (*tlb->tme_m68k_tlb_bus_tlb.tme_bus_tlb_cycle)"
1506: echo " (tlb->tme_m68k_tlb_bus_tlb.tme_bus_tlb_cycle_private, &cycle);"
1507: echo ""
1508: echo " /* if we deadlocked, we have no locks to release"
1509: echo " ourselves, so sleep a while waiting for things"
1510: echo " to clear up, then try again: */"
1511: echo " if (err == TME_EDEADLK) {"
1512: echo " TME_THREAD_DEADLOCK_SLEEP();"
1513: echo " cycle.tme_bus_cycle_address = physical_address;"
1514: echo " }"
1515: echo ""
1.1.1.3 ! root 1516: echo " /* otherwise, if we didn't get a bus error, but some"
! 1517: echo " synchronous event has happened: */"
! 1518: echo " else if (err == TME_BUS_CYCLE_SYNCHRONOUS_EVENT) {"
! 1519: echo ""
! 1520: echo " /* after the currently executing instruction finishes, check"
! 1521: echo " for external resets, halts, or interrupts: */"
! 1522: echo " ic->_tme_m68k_instruction_burst_remaining = 0;"
! 1523: echo " }"
! 1524: echo ""
1.1 root 1525: echo " /* otherwise, any other error might be a bus error: */"
1526: echo " else if (err != TME_OK) {"
1527: echo " err = tme_bus_tlb_fault(&tlb->tme_m68k_tlb_bus_tlb, &cycle, err);"
1528: echo " if (err != TME_OK) {"
1.1.1.3 ! root 1529: echo " exception = TME_M68K_EXCEPTION_BERR;"
1.1 root 1530: echo " break;"
1531: echo " }"
1532: echo " }"
1533: echo ""
1534: echo " /* update: */"
1535: echo " linear_address += cycle.tme_bus_cycle_size;"
1536: echo " transferred += cycle.tme_bus_cycle_size;"
1537: echo " }"
1538:
1539: echo ""
1540: echo " /* if we got an exception and there is a locked"
1541: echo " read/modify/write rwlock, unlock it: */"
1542: echo " if (exception != TME_M68K_EXCEPTION_NONE"
1543: echo " && (flags & TME_M68K_BUS_CYCLE_RMW)"
1544: echo " && rmw_rwlock != NULL) {"
1545: echo " tme_rwlock_unlock(rmw_rwlock);"
1546: echo " }"
1547:
1548: echo ""
1549: echo " /* if we faulted, stash the information the fault stacker"
1550: echo " will need and start exception processing: */"
1551: echo " if (exception != TME_M68K_EXCEPTION_NONE) {"
1552: echo -n " ic->_tme_m68k_group0_flags = flags"
1553: if test $name = read; then
1554: echo -n " | TME_M68K_BUS_CYCLE_READ"
1555: fi
1556: echo ";"
1557: echo " ic->_tme_m68k_group0_function_code = function_code;"
1558: echo " ic->_tme_m68k_group0_address = linear_address;"
1559: echo " ic->_tme_m68k_group0_sequence = ic->_tme_m68k_sequence;"
1560: echo " ic->_tme_m68k_group0_sequence._tme_m68k_sequence_transfer_faulted_after = transferred;"
1561: echo " ic->_tme_m68k_group0_buffer_${name}_size = cycle_size;"
1562: if test $name = write; then
1563: echo "#ifdef WORDS_BIGENDIAN"
1564: echo " memcpy(ic->_tme_m68k_group0_buffer_${name},"
1565: echo " reg + transferred,"
1566: echo " ic->_tme_m68k_group0_buffer_${name}_size);"
1567: echo "#else /* !WORDS_BIGENDIAN */"
1568: echo " reg_p = (reg + reg_size - 1) - transferred;"
1569: echo " for (buffer_i = 0;"
1570: echo " buffer_i < ic->_tme_m68k_group0_buffer_${name}_size;"
1571: echo " buffer_i++) {"
1572: echo " ic->_tme_m68k_group0_buffer_${name}[buffer_i] = *(reg_p--);"
1573: echo " }"
1574: echo "#endif /* !WORDS_BIGENDIAN */"
1575: fi
1576: echo " if (ic->_tme_m68k_group0_hook != NULL) {"
1577: echo " (*ic->_tme_m68k_group0_hook)(ic);"
1578: echo " }"
1579: echo " ic->_tme_m68k_group0_sequence._tme_m68k_sequence_transfer_faulted = ";
1580: echo " ic->_tme_m68k_group0_sequence._tme_m68k_sequence_transfer_next;"
1581: echo " tme_m68k_exception(ic, exception);"
1582: echo " }"
1583:
1584: echo ""
1585: echo " /* otherwise, this transfer has now completed: */"
1586: echo " TME_M68K_SEQUENCE_TRANSFER_STEP;"
1587:
1588: echo "}"
1589: fi
1590: done
1591:
1592: done
1593:
1594: # generate the BCD math functions:
1595: for name in abcd sbcd nbcd; do
1596:
1597: # if we're making the header, just emit a declaration:
1598: if $header; then
1599: echo "TME_M68K_INSN_DECL(tme_m68k_${name});"
1600: continue
1601: fi
1602:
1603: # emit the function:
1604: echo ""
1605: echo "TME_M68K_INSN(tme_m68k_${name})"
1606: echo "{"
1607: echo " tme_uint8_t dst, dst_msd, dst_lsd;"
1608: echo " tme_uint8_t src, src_msd, src_lsd;"
1609: echo " tme_uint8_t res, res_msd, res_lsd;"
1610: echo " tme_uint8_t flags;"
1611:
1612: # get the operands:
1613: if test $name != nbcd; then
1614: echo " int memory;"
1615: echo " int rx, ry, function_code;"
1616: echo ""
1617: echo " TME_M68K_INSN_CANFAULT;"
1618: echo ""
1619: echo " /* load the operands: */"
1620: echo " rx = TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 0, 3);"
1621: echo " ry = TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 9, 3);"
1622: echo " memory = (TME_M68K_INSN_OPCODE & TME_BIT(3)) != 0;"
1623: echo " function_code = TME_M68K_FUNCTION_CODE_DATA(ic);"
1624: echo " if (memory) {"
1625: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {"
1626: echo " ic->_tme_m68k_ea_function_code = function_code;"
1627: echo " ic->_tme_m68k_ea_address = ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + rx);"
1628: echo " }"
1629: echo " tme_m68k_read_memx8(ic);"
1630: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {"
1631: echo " ic->_tme_m68k_ea_function_code = function_code;"
1632: echo " ic->_tme_m68k_ea_address = ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ry);"
1633: echo " }"
1634: echo " tme_m68k_read_mem8(ic, TME_M68K_IREG_MEMY32);"
1635: echo " src = ic->tme_m68k_ireg_memx8;"
1636: echo " dst = ic->tme_m68k_ireg_memy8;"
1637: echo " }"
1638: echo " else {"
1639: echo " src = ic->tme_m68k_ireg_uint8(rx << 2);"
1640: echo " dst = ic->tme_m68k_ireg_uint8(ry << 2);"
1641: echo " }"
1642: else
1643: echo ""
1644: echo " dst = 0x00;"
1645: echo " src = TME_M68K_INSN_OP1(tme_uint8_t);"
1646: fi
1647: echo " dst_lsd = TME_FIELD_EXTRACTU(dst, 0, 4);"
1648: echo " dst_msd = TME_FIELD_EXTRACTU(dst, 4, 4);"
1649: echo " src_lsd = TME_FIELD_EXTRACTU(src, 0, 4);"
1650: echo " src_msd = TME_FIELD_EXTRACTU(src, 4, 4);"
1651:
1652: # perform the operation:
1653: echo ""
1654: echo " /* perform the operation: */"
1655: if test $name = abcd; then op='+' ; opc='-' ; else op='-' ; opc='+' ; fi
1656: echo " res_lsd = dst_lsd ${op} src_lsd ${op} ((ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_X) != 0);"
1657: echo " res_msd = dst_msd ${op} src_msd;"
1658: echo " flags = 0;"
1659: echo " if (res_lsd > 9) {"
1660: echo " res_lsd ${opc}= 10;"
1661: echo " res_msd ${op}= 1;"
1662: echo " }"
1663: echo " if (res_msd > 9) {"
1664: echo " res_msd ${opc}= 10;"
1665: echo " flags |= TME_M68K_FLAG_C | TME_M68K_FLAG_X;"
1666: echo " }"
1667: echo " res = (res_msd << 4) + (res_lsd & 0xf);"
1668: echo " if (res == 0) flags |= TME_M68K_FLAG_N;"
1669: echo ""
1670:
1671: # store the result
1672: echo " /* store the result and set the flags: */"
1673: if test $name != nbcd; then
1674: echo " if (memory) {"
1675: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {"
1676: echo " ic->tme_m68k_ireg_memx8 = res;"
1677: echo " ic->_tme_m68k_ea_function_code = function_code;"
1678: echo " ic->_tme_m68k_ea_address = ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ry);"
1679: # the stack pointer must always be incremented by a multiple of two.
1680: # assuming rx < 8, ((rx + 1) >> 3) == 1 iff rx == 7, meaning %a7:
1681: echo " ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + rx) += sizeof(tme_uint8_t) + ((rx + 1) >> 3);"
1682: echo " ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ry) += sizeof(tme_uint8_t) + ((ry + 1) >> 3);"
1683: echo " ic->tme_m68k_ireg_ccr = flags;"
1684: echo " }"
1685: echo " tme_m68k_write_memx8(ic);"
1686: echo " }"
1687: echo " else {"
1688: echo " ic->tme_m68k_ireg_uint8(ry << 2) = res;"
1689: echo " ic->tme_m68k_ireg_ccr = flags;"
1690: echo " }"
1691: else
1692: echo " TME_M68K_INSN_OP1(tme_uint8_t) = res;"
1693: echo " ic->tme_m68k_ireg_ccr = flags;"
1694: fi
1695: echo ""
1696: echo " TME_M68K_INSN_OK;"
1697: echo "}"
1698: done
1699:
1700: # generate the ccr and sr functions:
1701: for reg in ccr sr; do
1702: for name in ori andi eori move_to; do
1703: if test $reg = ccr; then size=8 ; else size=16 ; fi
1704:
1705: # if we're making the header, just emit a declaration:
1706: if $header; then
1707: echo "TME_M68K_INSN_DECL(tme_m68k_${name}_${reg});"
1708: continue
1709: fi
1710:
1711: # emit the function:
1712: echo ""
1713: echo "TME_M68K_INSN(tme_m68k_${name}_${reg})"
1714: echo "{"
1715: echo " tme_uint${size}_t reg;"
1716:
1717: # form the new register value:
1718: src=0
1719: echo -n " reg = "
1720: case $name in
1721: ori) echo -n "ic->tme_m68k_ireg_${reg} | " ;;
1722: andi) echo -n "ic->tme_m68k_ireg_${reg} & " ;;
1723: eori) echo -n "ic->tme_m68k_ireg_${reg} ^ " ;;
1724: move_to) size=16 ; src=1 ;;
1725: esac
1726: echo "(TME_M68K_INSN_OP${src}(tme_uint${size}_t) & TME_M68K_FLAG_"`echo $reg | tr a-z A-Z`");"
1727:
1728: # sr changes are special:
1729: if test $reg = sr; then
1730: echo " TME_M68K_INSN_PRIV;"
1731: echo " TME_M68K_INSN_CHANGE_SR(reg);"
1732: else
1733: echo " ic->tme_m68k_ireg_${reg} = reg;"
1734: fi
1735:
1736: echo " TME_M68K_INSN_OK;"
1737: echo "}"
1738: done
1739: done
1740:
1741: # generate the multiply and divide instructions:
1742:
1743: # permute on signed vs. unsigned:
1744: for _sign in u s; do
1745: if test $_sign = u; then sign=u; else sign=; fi
1746:
1747: # permute on short vs. long:
1748: for size in s l; do
1749: if test $size = s; then
1750: _size=
1751: small=16
1752: large=32
1753: reg_size_shift=' << 1'
1754: else
1755: _size=l
1756: small=32
1757: large=64
1758: reg_size_shift=
1759: fi
1760:
1761: # if we're making the header, just emit declarations:
1762: if $header; then
1763: echo "TME_M68K_INSN_DECL(tme_m68k_mul${_sign}${_size});"
1764: echo "TME_M68K_INSN_DECL(tme_m68k_div${_sign}${_size});"
1765: continue
1766: fi
1767:
1768: # emit the multiply function:
1769: echo ""
1770: echo "TME_M68K_INSN(tme_m68k_mul${_sign}${_size})"
1771: echo "{"
1772: if test $large = 64; then
1.1.1.2 root 1773: echo "#ifndef TME_HAVE_INT${large}_T"
1.1 root 1774: echo " abort();"
1.1.1.2 root 1775: echo "#else /* TME_HAVE_INT${large}_T */"
1.1 root 1776: echo " unsigned int flag_v;"
1777: echo " int ireg_dh;"
1778: fi
1779: echo " int ireg_dl;"
1780: echo " tme_${sign}int${large}_t res;"
1781: echo " tme_uint8_t flags;"
1782:
1783: echo ""
1784: echo " /* get the register containing the factor: */"
1785: echo -n " ireg_dl = TME_M68K_IREG_D0 + "
1786: if test $size = s; then
1787: echo "TME_M68K_INSN_OP0(tme_uint32_t);"
1788: else
1789: echo "TME_FIELD_EXTRACTU(TME_M68K_INSN_SPECOP, 12, 3);"
1790: fi
1791:
1792: echo ""
1793: echo " /* perform the multiplication: */"
1794: echo " res = (((tme_${sign}int${large}_t) ic->tme_m68k_ireg_${sign}int${small}(ireg_dl${reg_size_shift}))"
1795: echo " * TME_M68K_INSN_OP1(tme_${sign}int${small}_t));"
1796:
1797: echo ""
1798: echo " /* store the result: */"
1799: echo " ic->tme_m68k_ireg_${sign}int32(ireg_dl) = (tme_${sign}int32_t) res;"
1800: if test $large = 64; then
1801: echo " flag_v = TME_M68K_FLAG_V;"
1802: echo " if (TME_M68K_INSN_SPECOP & TME_BIT(10)) {"
1803: echo " flag_v = 0;"
1804: echo " ireg_dh = TME_M68K_IREG_D0 + TME_FIELD_EXTRACTU(TME_M68K_INSN_SPECOP, 0, 3);"
1805: echo " ic->tme_m68k_ireg_${sign}int32(ireg_dh) = (tme_${sign}int32_t) (res >> 32);"
1806: echo " }"
1807: fi
1808:
1809: echo ""
1810: echo " /* set the flags: */"
1811: echo " flags = ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_X;"
1812: echo " if (((tme_int${large}_t) res) < 0) flags |= TME_M68K_FLAG_N;"
1813: echo " if (res == 0) flags |= TME_M68K_FLAG_Z;"
1814: if test $large = 64; then
1.1.1.2 root 1815: if test $_sign = s; then
1816: echo -n " if (res > 0x7fffffffL || res < ((0L - 0x7fffffffL) - 1L)"
1817: else
1818: echo -n " if (res > 0xffffffffUL"
1819: fi
1.1 root 1820: echo ") flags |= flag_v;"
1821: fi
1822: echo " ic->tme_m68k_ireg_ccr = flags;"
1823:
1824: echo ""
1825: echo " TME_M68K_INSN_OK;"
1826: if test $large = 64; then
1.1.1.2 root 1827: echo "#endif /* TME_HAVE_INT${large}_T */"
1.1 root 1828: fi
1829: echo "}"
1830:
1831: # emit the divide function:
1832: echo ""
1833: echo "TME_M68K_INSN(tme_m68k_div${_sign}${_size})"
1834: echo "{"
1835: if test $large = 64; then
1.1.1.2 root 1836: echo "#ifndef TME_HAVE_INT${large}_T"
1.1 root 1837: echo " abort();"
1.1.1.2 root 1838: echo "#else /* TME_HAVE_INT${large}_T */"
1.1 root 1839: echo " int ireg_dr;"
1840: fi
1841: echo " int ireg_dq;"
1842: echo " tme_${sign}int${large}_t dividend, quotient;"
1843: echo " tme_${sign}int${small}_t divisor, remainder;"
1844: echo " tme_uint8_t flags;"
1845:
1846: echo ""
1847: echo " /* get the register(s): */"
1848: echo -n " ireg_dq = TME_M68K_IREG_D0 + "
1849: if test $size = s; then
1850: echo "TME_M68K_INSN_OP0(tme_uint32_t);"
1851: else
1852: echo "TME_FIELD_EXTRACTU(TME_M68K_INSN_SPECOP, 12, 3);"
1853: echo " ireg_dr = TME_M68K_IREG_D0 + TME_FIELD_EXTRACTU(TME_M68K_INSN_SPECOP, 0, 3);"
1854: fi
1855:
1856: echo ""
1857: echo " /* form the dividend and the divisor: */"
1858: if test $large = 64; then
1859: echo " if (TME_M68K_INSN_SPECOP & TME_BIT(10)) {"
1860: echo " dividend = (tme_${sign}int${large}_t)"
1861: echo " ((((tme_uint${large}_t) ic->tme_m68k_ireg_uint32(ireg_dr)) << 32)"
1862: echo " | ic->tme_m68k_ireg_uint32(ireg_dq));"
1863: echo " }"
1864: echo " else"
1865: echo -n " "
1866: fi
1867: echo " dividend = (tme_${sign}int${large}_t) ic->tme_m68k_ireg_${sign}int32(ireg_dq);"
1868: echo " divisor = TME_M68K_INSN_OP1(tme_${sign}int${small}_t);"
1869: echo " if (divisor == 0) {"
1.1.1.3 ! root 1870: echo " ic->tme_m68k_ireg_pc_last = ic->tme_m68k_ireg_pc;"
1.1 root 1871: echo " ic->tme_m68k_ireg_pc = ic->tme_m68k_ireg_pc_next;"
1.1.1.3 ! root 1872: echo " TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_INST(TME_M68K_VECTOR_DIV0));"
1.1 root 1873: echo " }"
1874:
1875: echo ""
1876: echo " /* do the division: */"
1877: echo " quotient = dividend / divisor;"
1878: echo " remainder = dividend % divisor;"
1879:
1880: echo ""
1881: echo " /* set the flags and return the quotient and remainder: */"
1882: echo " flags = ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_X;"
1.1.1.2 root 1883: echo -n " if ("
1884: case "${small}${_sign}" in
1885: 16s) echo -n "quotient > 0x7fff || quotient < -32768" ;;
1886: 16u) echo -n "quotient > 0xffff" ;;
1887: 32s) echo -n "quotient > 0x7fffffffL || quotient < ((0L - 0x7fffffffL) - 1L)" ;;
1888: 32u) echo -n "quotient > 0xffffffffUL" ;;
1889: esac
1.1 root 1890: echo ") {"
1891: echo " flags |= TME_M68K_FLAG_V;"
1892: echo " }"
1893: echo " else {"
1894: echo " if (((tme_int${small}_t) quotient) < 0) flags |= TME_M68K_FLAG_N;"
1895: echo " if (quotient == 0) flags |= TME_M68K_FLAG_Z;"
1896: echo " ic->tme_m68k_ireg_${sign}int${small}(ireg_dq${reg_size_shift}) = (tme_${sign}int${small}_t) quotient;"
1897: if test $small = 16; then
1898: echo " ic->tme_m68k_ireg_${sign}int${small}((ireg_dq${reg_size_shift}) + 1) = remainder;"
1899: else
1900: echo " if (ireg_dr != ireg_dq) {"
1901: echo " ic->tme_m68k_ireg_${sign}int${small}(ireg_dr) = remainder;"
1902: echo " }"
1903: fi
1904: echo " }"
1905: echo " ic->tme_m68k_ireg_ccr = flags;"
1906:
1907: echo ""
1908: echo " TME_M68K_INSN_OK;"
1909: if test $large = 64; then
1.1.1.2 root 1910: echo "#endif /* TME_HAVE_INT${large}_T */"
1.1 root 1911: fi
1912: echo "}"
1913:
1914: done
1915: done
1916:
1917: # done:
1918: exit 0
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.