|
|
1.1 root 1: #! /bin/sh
2:
1.1.1.4 ! root 3: # $Id: m68k-insns-auto.sh,v 1.25 2007/08/25 21:47:00 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.4 ! root 51: _TME_RCSID("\$Id: m68k-insns-auto.sh,v 1.25 2007/08/25 21:47:00 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_src);"
166: echo " ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ireg_src) += ireg_src_adjust;"
167: echo " }"
168: echo " tme_m68k_read_mem${size}(ic, TME_M68K_IREG_MEMY${size});"
1.1.1.4 ! root 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_dst);"
! 172: echo " ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ireg_dst) += ireg_dst_adjust;"
! 173: echo " }"
! 174: echo " tme_m68k_read_memx${size}(ic);"
1.1 root 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_src) -= ireg_src_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_src);"
191: echo " }"
192: echo " tme_m68k_read_mem${size}(ic, TME_M68K_IREG_MEMY${size});"
1.1.1.4 ! root 193: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {"
! 194: echo " ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ireg_dst) -= ireg_dst_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_dst);"
! 197: echo " }"
! 198: echo " tme_m68k_read_memx${size}(ic);"
1.1 root 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:
1.1.1.4 ! root 344: # generate the wrapper functions for a move of an address register
! 345: # to a predecrement or postincrement EA with that same address
! 346: # register:
! 347: for name in pd pi; do
! 348:
! 349: # a move of an address registers are only word and long:
! 350: if test $size = 8; then continue; fi
! 351:
! 352: # if we're making the header, just emit a declaration:
! 353: if $header; then
! 354: echo "TME_M68K_INSN_DECL(tme_m68k_move_sr${name}${size});"
! 355: continue
! 356: fi
! 357:
! 358: echo ""
! 359: echo "/* a move of an address register to a predecrement or"
! 360: echo " postincrement EA with that same address register, must"
! 361: echo " store the original value of the address register. since the"
! 362: echo " predecrement and postincrement code in the executer updates"
! 363: echo " the address register before the move has happened, we wrap"
! 364: echo " the normal move function in this one, that gives an op1"
! 365: echo " argument that is the original value of the address register: */"
! 366: echo "TME_M68K_INSN(tme_m68k_move_sr${name}${size})"
! 367: echo "{"
! 368: if test ${name} = pd; then op='+'; else op='-'; fi
! 369: echo " /* NB: both this function and tme_m68k_move${size}()"
! 370: echo " get the source operand as _op1, and the destination"
! 371: echo " operand as _op0: */"
! 372: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {"
! 373: echo " *((tme_uint${size}_t *) _op0)"
! 374: echo " = (*((tme_uint${size}_t *) _op1)"
! 375: echo " ${op} sizeof(tme_uint${size}_t));"
! 376: echo " }"
! 377: echo " tme_m68k_move${size}(ic, _op0, _op0);"
! 378: echo "}"
! 379: done
! 380:
1.1 root 381: # generate the address math functions:
382: for name in suba adda movea; do
383:
384: # the address math functions don't need an 8-bit version:
385: if test $size = 8; then continue; fi
386:
387: # if we're making the header, just emit a declaration:
388: if $header; then
389: echo "TME_M68K_INSN_DECL(tme_m68k_${name}${size});"
390: continue
391: fi
392:
393: echo ""
394: echo "/* the ${name} function on a ${size}-byte EA: */"
395: echo "TME_M68K_INSN(tme_m68k_${name}${size})"
396: echo "{"
397: case $name in
398: suba) op='-' ; src="_op0" ; dst="_op1" ;;
399: adda) op='+' ; src="_op0" ; dst="_op1" ;;
400: movea) op='' ; src="_op1" ; dst="_op0" ;;
401: esac
402: echo " *((tme_int32_t *) ${dst}) ${op}= *((tme_int${size}_t *) ${src});"
403: echo " TME_M68K_INSN_OK;"
404: echo "}"
405: done
406:
407: # generate the bit functions:
408: for name in btst bchg bclr bset; do
409:
410: # the bit functions don't need a 16-bit version:
411: if test $size = 16; then continue; fi
412:
413: # if we're making the header, just emit a declaration:
414: if $header; then
415: echo "TME_M68K_INSN_DECL(tme_m68k_${name}${size});"
416: continue
417: fi
418:
419: echo ""
420: echo "/* the ${name} function on a ${size}-byte EA: */"
421: echo "TME_M68K_INSN(tme_m68k_${name}${size})"
422: echo "{"
423: echo " tme_uint${size}_t value, bit;"
424: echo " bit = _TME_BIT(tme_uint${size}_t, TME_M68K_INSN_OP0(tme_uint8_t) & (${size} - 1));"
425: echo " value = TME_M68K_INSN_OP1(tme_uint${size}_t);"
426: echo " if (value & bit) {"
427: echo " ic->tme_m68k_ireg_ccr &= ~TME_M68K_FLAG_Z;"
428: echo " }"
429: echo " else {"
430: echo " ic->tme_m68k_ireg_ccr |= TME_M68K_FLAG_Z;"
431: echo " }"
432: case ${name} in
433: btst) ;;
434: bchg) echo " TME_M68K_INSN_OP1(tme_uint${size}_t) = value ^ bit;" ;;
435: bclr) echo " TME_M68K_INSN_OP1(tme_uint${size}_t) = value & ~bit;" ;;
436: bset) echo " TME_M68K_INSN_OP1(tme_uint${size}_t) = value | bit;" ;;
437: esac
438: echo " TME_M68K_INSN_OK;"
439: echo "}"
440: done
441:
442: # generate the shift/rotate functions:
443: for func in as ls ro rox; do
444: for dir in l r; do
445: name="${func}${dir}"
446:
447: # if we're making the header, just emit a declaration:
448: if $header; then
449: echo "TME_M68K_INSN_DECL(tme_m68k_${name}${size});"
450: continue
451: fi
452:
453: echo ""
454: echo "/* the ${name} function on a ${size}-byte EA: */"
455: echo "TME_M68K_INSN(tme_m68k_${name}${size})"
456: echo "{"
457: echo " unsigned int count;"
458: sign=u
459: case "${name}" in
460: asr) sign= ;;
1.1.1.2 root 461: asl) echo " tme_uint${size}_t sign_bits, sign_bits_mask;" ;;
1.1 root 462: rox[lr]) echo " tme_uint8_t xbit;" ;;
463: *) ;;
464: esac
465: echo " tme_${sign}int${size}_t res;"
466: echo " tme_uint8_t flags;"
467: echo ""
468: echo " /* get the count and operand: */"
469: echo " count = TME_M68K_INSN_OP0(tme_uint8_t) & 63;"
470: echo " res = TME_M68K_INSN_OP1(tme_${sign}int${size}_t);"
471:
472: echo ""
473: echo " /* generate the X, V, and C flags assuming the count is zero: */"
474: echo " flags = ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_X;"
475: case "${name}" in
476: rox[lr])
477: echo " xbit = (flags / TME_M68K_FLAG_X);"
478: echo " flags |= (xbit * TME_M68K_FLAG_C);"
479: ;;
480: esac
481:
482: echo ""
483: echo " /* if the count is nonzero, update the result and"
484: echo " generate the X, V, and C flags: */"
485: echo " if (count > 0) {"
486: case "${name}" in
1.1.1.3 root 487: lsr)
1.1 root 488: echo " if (63 > SHIFTMAX_INT${size}_T"
489: echo " && count > ${size}) {"
490: echo " res = 0;"
491: echo " }"
492: echo " res >>= (count - 1);"
493: echo " flags = (res & 1);"
494: echo " flags *= TME_M68K_FLAG_C;"
495: echo " flags |= (flags * TME_M68K_FLAG_X);"
496: echo " res >>= 1;"
497: ;;
1.1.1.3 root 498: asr)
499: echo " if (63 > SHIFTMAX_INT${size}_T"
500: echo " && count > ${size}) {"
501: echo " res = 0 - (res < 0);"
502: echo " }"
503: echo "#ifdef SHIFTSIGNED_INT${size}_T"
504: echo " res >>= (count - 1);"
505: echo "#else /* !SHIFTSIGNED_INT${size}_T */"
506: echo " for (; --count > 0; ) {"
507: echo " res = (res & ~((tme_${sign}int${size}_t) 1)) / 2;"
508: echo " }"
509: echo "#endif /* !SHIFTSIGNED_INT${size}_T */"
510: echo " flags = (res & 1);"
511: echo " flags *= TME_M68K_FLAG_C;"
512: echo " flags |= (flags * TME_M68K_FLAG_X);"
513: echo "#ifdef SHIFTSIGNED_INT${size}_T"
514: echo " res >>= 1;"
515: echo "#else /* !SHIFTSIGNED_INT${size}_T */"
516: echo " res = (res & ~((tme_${sign}int${size}_t) 1)) / 2;"
517: echo "#endif /* !SHIFTSIGNED_INT${size}_T */"
518: ;;
1.1 root 519: [al]sl)
520: if test ${name} = asl; then
521: echo ""
522: echo " /* we need to see how the sign of the result will change during"
523: echo " shifting in order to generate V."
524: echo ""
525: echo " in general, the idea is to get all of the bits that will ever"
1.1.1.2 root 526: echo " appear in the sign position into sign_bits, with a mask in"
527: echo " sign_bits_mask. if (sign_bits & sign_bits_mask) is zero or"
528: echo " sign_bits_mask, clear V, else set V."
1.1 root 529: echo ""
1.1.1.2 root 530: echo " start by loading the operand into sign_bits and setting"
531: echo " sign_bits_mask to all-bits-one."
1.1 root 532: echo ""
533: echo " if the shift count is exactly ${size} - 1, then all of the bits"
534: echo " of the operand will appear in the sign position."
535: echo ""
536: echo " if the shift count is less than ${size} - 1, then some of the"
537: echo " less significant bits of the operand will never appear in the"
1.1.1.2 root 538: echo " sign position, so we can shift sign_bits_mask to ignore them."
1.1 root 539: echo ""
540: echo " if the shift count is greater than ${size} - 1, then all of the"
541: echo " bits in the operand, plus at least one zero bit, will appear in"
542: echo " the sign position. the only way that the sign bit will never"
543: echo " change during the shift is if the operand was zero to begin with."
1.1.1.2 root 544: echo " without any changes to sign_bits or sign_bits_mask, the final"
545: echo " test will always work, except when sign_bits is all-bits-one."
546: echo " the magic below clears the least-significant bit of sign_bits"
547: echo " iff sign_bits is all-bits-one: */"
1.1 root 548: echo " sign_bits = res;"
549: fi
550: echo " if (63 > SHIFTMAX_INT${size}_T"
551: echo " && count > ${size}) {"
552: echo " res = 0;"
553: echo " }"
554: echo " res <<= (count - 1);"
555: echo " flags = (res >> (${size} - 1));"
556: echo " flags *= TME_M68K_FLAG_C;"
557: echo " flags |= (flags * TME_M68K_FLAG_X);"
558: echo " res <<= 1;"
559: if test ${name} = asl; then
1.1.1.2 root 560: echo " sign_bits_mask = (tme_uint${size}_t) -1;"
1.1 root 561: echo " if (count != ${size} - 1) {"
562: echo " if (count < ${size}) {"
1.1.1.2 root 563: echo " sign_bits_mask <<= ((${size} - 1) - count);"
1.1 root 564: echo " }"
565: echo " else {"
1.1.1.2 root 566: echo " sign_bits ^= !(sign_bits + 1);"
1.1 root 567: echo " }"
568: echo " }"
1.1.1.2 root 569: echo " sign_bits &= sign_bits_mask;"
570: echo " if (sign_bits != 0 && sign_bits != sign_bits_mask) {"
1.1 root 571: echo " flags |= TME_M68K_FLAG_V;"
572: echo " }"
573: fi
574: ;;
575: ro[lr])
576: echo " count &= (${size} - 1);"
577: if test $dir = l; then
578: echo " res = (res << count) | (res >> (${size} - count));"
579: echo " flags |= ((res & 1) * TME_M68K_FLAG_C);"
580: else
581: echo " res = (res << (${size} - count)) | (res >> count);"
582: echo " flags |= ((res >> (${size} - 1)) * TME_M68K_FLAG_C);"
583: fi
584: ;;
585: rox[lr])
586: echo " count %= (${size} + 1);"
587: echo " flags = xbit;"
588: echo " if (count > 0) {"
589: if test $dir = l; then
590: echo " flags = (res >> (${size} - count)) & 1;"
591: echo " if (${size} > SHIFTMAX_INT${size}_T"
592: echo " && count == ${size}) {"
593: echo " res = 0 | (xbit << (${size} - 1)) | (res >> ((${size} + 1) - ${size}));"
594: echo " }"
595: echo " else if (${size} > SHIFTMAX_INT${size}_T"
596: echo " && count == 1) {"
597: echo " res = (res << 1) | (xbit << (1 - 1)) | 0;"
598: echo " }"
599: echo " else {"
600: echo " res = (res << count) | (xbit << (count - 1)) | (res >> ((${size} + 1) - count));"
601: echo " }"
602: else
603: echo " flags = (res >> (count - 1)) & 1;"
604: echo " if (${size} > SHIFTMAX_INT${size}_T"
605: echo " && count == ${size}) {"
606: echo " res = (res << ((${size} + 1) - ${size})) | (xbit << (${size} - ${size})) | 0;"
607: echo " }"
608: echo " else if (${size} > SHIFTMAX_INT${size}_T"
609: echo " && count == 1) {"
610: echo " res = 0 | (xbit << (${size} - 1)) | (res >> 1);"
611: echo " }"
612: echo " else {"
613: echo " res = (res << ((${size} + 1) - count)) | (xbit << (${size} - count)) | (res >> count);"
614: echo " }"
615: fi
616: echo " }"
617: echo " flags *= TME_M68K_FLAG_C;"
618: echo " flags |= (flags * TME_M68K_FLAG_X);"
619: ;;
620: esac
621: echo " }"
622:
623: echo ""
624: echo " /* store the result: */"
625: echo " TME_M68K_INSN_OP1(tme_${sign}int${size}_t) = res;"
626:
627: echo ""
628: echo " /* generate the N flag. we cast to tme_uint8_t as soon as we"
629: echo " know the bit we want is within the range of the type, to try"
630: echo " to affect the generated assembly: */"
631: echo " flags |= ((tme_uint8_t) (((tme_uint${size}_t) res) >> (${size} - 1))) * TME_M68K_FLAG_N;"
632:
633: echo ""
634: echo " /* generate the Z flag: */"
635: echo " if (res == 0) flags |= TME_M68K_FLAG_Z;"
636:
637: echo ""
638: echo " /* store the flags: */"
639: echo " ic->tme_m68k_ireg_ccr = flags;"
640: echo " TME_M68K_INSN_OK;"
641: echo "}"
642: done
643: done
644:
645: # movep_rm, movep_mr, movem_rm, and movem_mr:
646: for name in rm mr; do
647:
648: # movep and movem don't need 8-bit versions:
649: if test ${size} = 8; then continue; fi
650:
651: # if we're making the header, just emit declarations:
652: if $header; then
653: echo "TME_M68K_INSN_DECL(tme_m68k_movep_${name}${size});"
654: echo "TME_M68K_INSN_DECL(tme_m68k_movem_${name}${size});"
655: continue
656: fi
657:
658: # emit the movep function:
659: echo ""
660: echo "/* the movep_${name} function on a ${size}-bit dreg: */"
661: echo "TME_M68K_INSN(tme_m68k_movep_${name}${size})"
662: echo "{"
663: echo " unsigned int function_code;"
664: echo " tme_uint32_t linear_address;"
665: if test $name = rm; then
666: echo " tme_uint${size}_t value;"
667: fi
668: echo " int dreg;"
669: echo ""
670: echo " TME_M68K_INSN_CANFAULT;"
671: echo ""
672: echo " function_code = TME_M68K_FUNCTION_CODE_DATA(ic);"
673: echo " linear_address = TME_M68K_INSN_OP1(tme_uint32_t);"
674: echo " linear_address += (tme_int32_t) ((tme_int16_t) TME_M68K_INSN_SPECOP);"
675: echo " dreg = TME_M68K_IREG_D0 + TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 9, 3);"
676:
677: # set value:
678: if test $name = rm; then
679: echo " value = ic->tme_m68k_ireg_uint${size}(dreg${reg_size_shift});"
680: value="value"
681: else
682: value="ic->tme_m68k_ireg_uint${size}(dreg${reg_size_shift})"
683: fi
684:
685: # transfer the bytes:
686: pos=${size}
687: while test $pos != 0; do
688: pos=`expr ${pos} - 8`
689: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {"
690: echo " ic->_tme_m68k_ea_function_code = function_code;"
691: echo " ic->_tme_m68k_ea_address = linear_address;"
692: if test $name = rm; then
693: echo " ic->tme_m68k_ireg_memx8 = TME_FIELD_EXTRACTU(${value}, ${pos}, 8);"
694: echo " }"
695: echo " tme_m68k_write_memx8(ic);"
696: else
697: echo " }"
698: echo " tme_m68k_read_memx8(ic);"
699: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {"
700: echo " TME_FIELD_DEPOSIT${size}(${value}, ${pos}, 8, ic->tme_m68k_ireg_memx8);"
701: echo " }"
702: fi
703: echo " linear_address += 2;"
704: done
705:
706: echo " TME_M68K_INSN_OK;"
707: echo "}"
708:
709: # emit the movem function:
710: echo ""
711: echo "/* the movem_${name} function on ${size}-bit registers: */"
712: echo "TME_M68K_INSN(tme_m68k_movem_${name}${size})"
713: echo "{"
714: echo " int ireg, direction;"
715: echo " tme_uint16_t mask, bit;"
716: echo " unsigned int ea_mode;"
717: echo " tme_uint32_t addend;"
1.1.1.4 ! root 718: echo " tme_uint32_t total_size;"
! 719:
! 720: echo " /* get the register mask, and figure out the total size"
! 721: echo " of the transfer: */"
! 722: echo " mask = TME_M68K_INSN_SPECOP;"
! 723: echo " total_size = 0;"
! 724: echo " if (mask != 0) {"
! 725: echo " TME_M68K_INSN_CANFAULT;"
! 726: echo " bit = mask;"
! 727: echo " do {"
! 728: echo " total_size += sizeof(tme_uint${size}_t);"
! 729: echo " bit &= (bit - 1);"
! 730: echo " } while (bit != 0);"
! 731: echo " }"
1.1 root 732:
733: echo ""
734: echo " /* figure out what direction to move in, and where to start from: */"
735: echo " ea_mode = TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 3, 3);"
736: echo " direction = 1;"
737: echo " ireg = TME_M68K_IREG_D0;"
738: if test $name = rm; then
739: echo " if (ea_mode == 4) {"
740: echo " direction = -1;"
741: echo " ireg = TME_M68K_IREG_A7;"
742: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {"
1.1.1.4 ! root 743: echo ""
! 744: echo " /* \"For the MC68020, MC68030, MC68040, and CPU32, if"
! 745: echo " the addressing register is also moved to memory, the"
! 746: echo " value written is the initial register value decremented "
! 747: echo " by the size of the operation. The MC68000 and MC68010 "
! 748: echo " write the initial register value (not decremented).\" */"
! 749: echo " if (ic->tme_m68k_type >= TME_M68K_M68020) {"
! 750: echo " ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0"
! 751: echo " + TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 0, 3))"
! 752: echo " = (ic->_tme_m68k_ea_address - total_size);"
! 753: echo " }"
! 754: echo ""
! 755: echo " /* predecrement the effective address for the first transfer: */"
1.1 root 756: echo " ic->_tme_m68k_ea_address -= sizeof(tme_uint${size}_t);"
757: echo " }"
758: echo " }"
759: fi
760: echo " addend = (tme_uint32_t) (direction * sizeof(tme_uint${size}_t));"
761:
762: echo ""
763: echo " /* do the transfer: */"
764: echo " for (bit = 1; bit != 0; bit <<= 1) {"
765: echo " if (mask & bit) {"
766: if test $name = rm; then
767: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {"
768: echo " ic->tme_m68k_ireg_memx${size} = ic->tme_m68k_ireg_uint${size}(ireg${reg_size_shift});"
769: echo " }"
770: echo " tme_m68k_write_memx${size}(ic);"
771: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {"
772: else
773: echo " tme_m68k_read_memx${size}(ic);"
774: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {"
775: echo -n " ic->tme_m68k_ireg_uint32(ireg) = "
776: if test $size = 32; then
777: echo "ic->tme_m68k_ireg_memx${size};"
778: else
779: echo "TME_EXT_S${size}_U32((tme_int${size}_t) ic->tme_m68k_ireg_memx${size});"
780: fi
781: fi
782: echo " ic->_tme_m68k_ea_address += addend;"
783: echo " }"
784: echo " }"
785: echo " ireg += direction;"
786: echo " }"
787: echo ""
788:
789: # for the predecrement and postincrement modes, update the
790: # address register:
791: if test $name = rm; then
792: echo " /* if this is the predecrement mode, update the address register: */"
1.1.1.4 ! root 793: echo " /* \"For the MC68020, MC68030, MC68040, and CPU32, if"
! 794: echo " the addressing register is also moved to memory, the"
! 795: echo " value written is the initial register value decremented "
! 796: echo " by the size of the operation. The MC68000 and MC68010 "
! 797: echo " write the initial register value (not decremented).\" */"
! 798: echo " if (ea_mode == 4"
! 799: echo " && ic->tme_m68k_type < TME_M68K_M68020) {"
1.1 root 800: echo " ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0"
801: echo " + TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 0, 3))"
802: echo " = (ic->_tme_m68k_ea_address + sizeof(tme_uint${size}_t));"
803: echo " }"
804: else
805: echo " /* if this is the postincrement mode, update the address register: */"
806: echo " if (ea_mode == 3) {"
807: echo " ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0"
808: echo " + TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 0, 3))"
809: echo " = ic->_tme_m68k_ea_address;"
810: echo " }"
811: fi
812:
813: echo " TME_M68K_INSN_OK;"
814: echo "}"
815: done
816:
817: # chk32 and chk16:
818: if test $size != 8; then
819:
820: # if we're making the header, just emit a declaration:
821: if $header; then
822: echo "TME_M68K_INSN_DECL(tme_m68k_chk${size});"
823: else
824: echo ""
825: echo "/* chk${size}: */"
826: echo "TME_M68K_INSN(tme_m68k_chk${size})"
827: echo "{"
828: echo " if (*((tme_int${size}_t *) _op0) < 0) {"
829: echo " ic->tme_m68k_ireg_ccr |= TME_M68K_FLAG_N;"
1.1.1.3 root 830: echo " ic->tme_m68k_ireg_pc_last = ic->tme_m68k_ireg_pc;"
1.1 root 831: echo " ic->tme_m68k_ireg_pc = ic->tme_m68k_ireg_pc_next;"
1.1.1.3 root 832: echo " TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_INST(TME_M68K_VECTOR_CHK));"
1.1 root 833: echo " }"
834: echo " if (*((tme_int${size}_t *) _op0) > *((tme_int${size}_t *) _op1)) {"
835: echo " ic->tme_m68k_ireg_ccr &= ~TME_M68K_FLAG_N;"
1.1.1.3 root 836: echo " ic->tme_m68k_ireg_pc_last = ic->tme_m68k_ireg_pc;"
1.1 root 837: echo " ic->tme_m68k_ireg_pc = ic->tme_m68k_ireg_pc_next;"
1.1.1.3 root 838: echo " TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_INST(TME_M68K_VECTOR_CHK));"
1.1 root 839: echo " }"
840: echo " TME_M68K_INSN_OK;"
841: echo "}"
842: fi
843: fi
844:
1.1.1.4 ! root 845: # cas:
! 846: name=cas
! 847: if $header; then
! 848: echo "TME_M68K_INSN_DECL(tme_m68k_${name}${size});"
! 849: else
! 850: echo ""
! 851: echo "/* ${name}${size}: */"
! 852: echo "TME_M68K_INSN(tme_m68k_${name}${size})"
! 853: echo "{"
! 854: echo " struct tme_m68k_rmw rmw;"
! 855: echo " struct tme_m68k_tlb *tlb;"
! 856: echo " int ireg_dc, ireg_du;"
! 857: echo " tme_uint${size}_t value_dc, value_du, value_mem;"
! 858: echo ""
! 859: echo " /* start the read/modify/write cycle: */"
! 860: echo " rmw.tme_m68k_rmw_addresses[0] = ic->_tme_m68k_ea_address;"
! 861: echo " rmw.tme_m68k_rmw_address_count = 1;"
! 862: echo " rmw.tme_m68k_rmw_size = sizeof(tme_uint${size}_t);"
! 863: echo " if (tme_m68k_rmw_start(ic,"
! 864: echo " &rmw)) {"
! 865: echo " TME_M68K_INSN_OK;"
! 866: echo " }"
! 867: echo ""
! 868: echo " /* get the compare and update registers: */"
! 869: echo " ireg_dc = TME_M68K_IREG_D0 + TME_FIELD_EXTRACTU(TME_M68K_INSN_SPECOP, 0, 3);"
! 870: echo " ireg_du = TME_M68K_IREG_D0 + TME_FIELD_EXTRACTU(TME_M68K_INSN_SPECOP, 6, 3);"
! 871: echo ""
! 872: echo " /* if we can do the fast compare-and-exchange: */"
! 873: echo " if (!rmw.tme_m68k_rmw_slow_reads[0]) {"
! 874: echo ""
! 875: echo " /* get the compare and update values in big-endian byte order: */"
! 876: echo " value_dc = ic->tme_m68k_ireg_uint${size}(ireg_dc${reg_size_shift});"
! 877: echo " value_du = ic->tme_m68k_ireg_uint${size}(ireg_du${reg_size_shift});"
! 878: if test ${size} != 8; then
! 879: echo " value_dc = tme_htobe_u${size}(value_dc);"
! 880: echo " value_du = tme_htobe_u${size}(value_du);"
! 881: fi
! 882: echo ""
! 883: echo " /* get this TLB entry: */"
! 884: echo " tlb = rmw.tme_m68k_rmw_tlbs[0];"
! 885: echo ""
! 886: echo " /* this TLB entry must allow fast reading and fast writing"
! 887: echo " to the same memory: */"
! 888: echo " assert (tlb->tme_m68k_tlb_emulator_off_read != TME_EMULATOR_OFF_UNDEF"
! 889: echo " && tlb->tme_m68k_tlb_emulator_off_write == tlb->tme_m68k_tlb_emulator_off_read);"
! 890: echo ""
! 891: echo " /* do the compare-and-exchange: */"
! 892: echo " value_mem ="
! 893: echo " tme_memory_atomic_cx${size}(((tme_shared tme_uint${size}_t *)"
! 894: echo " (tlb->tme_m68k_tlb_emulator_off_read"
! 895: echo " + ic->_tme_m68k_ea_address)),"
! 896: echo " value_dc,"
! 897: echo " value_du,"
! 898: echo " tlb->tme_m68k_tlb_bus_rwlock,"
! 899: echo " sizeof(tme_uint8_t));"
! 900: echo -n " ic->tme_m68k_ireg_memx${size} = "
! 901: if test ${size} != 8; then echo -n "tme_betoh_u${size}"; fi
! 902: echo "(value_mem);"
! 903: echo " }"
! 904: echo ""
! 905: echo " /* compare the compare operand to the effective address operand: */"
! 906: echo " tme_m68k_cmp${size}(ic, &ic->tme_m68k_ireg_uint${size}(ireg_dc${reg_size_shift}), &ic->tme_m68k_ireg_memx${size});"
! 907: echo ""
! 908: echo " /* if the comparison succeeded: */"
! 909: echo " if (ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_Z) {"
! 910: echo ""
! 911: echo " /* write the update operand to the effective address operand: */"
! 912: echo " ic->tme_m68k_ireg_memx${size} = ic->tme_m68k_ireg_uint${size}(ireg_du${reg_size_shift});"
! 913: echo " }"
! 914: echo ""
! 915: echo " /* otherwise, the comparison failed: */"
! 916: echo " else {"
! 917: echo ""
! 918: echo " /* write the effective address operand to the compare operand: */"
! 919: echo " ic->tme_m68k_ireg_uint${size}(ireg_dc${reg_size_shift}) = ic->tme_m68k_ireg_memx${size};"
! 920: echo " }"
! 921: echo ""
! 922: echo " /* finish the read/modify/write cycle: */"
! 923: echo " tme_m68k_rmw_finish(ic,"
! 924: echo " &rmw,"
! 925: echo " (ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_Z) != 0);"
! 926: echo " TME_M68K_INSN_OK;"
! 927: echo "}"
! 928: fi
! 929:
! 930: # cas2:
! 931: name=cas2_
! 932: if test $size != 8; then
1.1 root 933:
934: if $header; then
935: echo "TME_M68K_INSN_DECL(tme_m68k_${name}${size});"
936: else
937: echo ""
938: echo "/* ${name}${size}: */"
939: echo "TME_M68K_INSN(tme_m68k_${name}${size})"
940: echo "{"
1.1.1.4 ! root 941: echo " struct tme_m68k_rmw rmw;"
! 942: echo " int ireg_dcx, ireg_dux;"
! 943: echo " int ireg_dcy, ireg_duy;"
! 944: echo " const tme_uint16_t specopx = TME_M68K_INSN_SPECOP;"
! 945: echo " const tme_uint16_t specopy = TME_M68K_INSN_OP0(tme_uint16_t);"
1.1 root 946: echo ""
947: echo " /* start the read/modify/write cycle: */"
1.1.1.4 ! root 948: echo " ic->_tme_m68k_ea_function_code = TME_M68K_FUNCTION_CODE_DATA(ic);"
! 949: echo " rmw.tme_m68k_rmw_addresses[0] = ic->tme_m68k_ireg_uint32(TME_M68K_IREG_D0"
! 950: echo " + TME_FIELD_EXTRACTU(specopx, 12, 4));"
! 951: echo " rmw.tme_m68k_rmw_addresses[1] = ic->tme_m68k_ireg_uint32(TME_M68K_IREG_D0"
! 952: echo " + TME_FIELD_EXTRACTU(specopy, 12, 4));"
! 953: echo " rmw.tme_m68k_rmw_address_count = 2;"
! 954: echo " rmw.tme_m68k_rmw_size = sizeof(tme_uint${size}_t);"
! 955: echo " if (tme_m68k_rmw_start(ic,"
! 956: echo " &rmw)) {"
1.1 root 957: echo " TME_M68K_INSN_OK;"
958: echo " }"
959: echo ""
1.1.1.4 ! root 960: echo " /* do the comparisons: */"
! 961: echo " ireg_dcx = TME_M68K_IREG_D0 + TME_FIELD_EXTRACTU(specopx, 0, 3);"
! 962: echo " ireg_dcy = TME_M68K_IREG_D0 + TME_FIELD_EXTRACTU(specopy, 0, 3);"
! 963: echo " tme_m68k_cmp${size}(ic,"
! 964: echo " &ic->tme_m68k_ireg_uint${size}(ireg_dcx${reg_size_shift}),"
! 965: echo " &ic->tme_m68k_ireg_memx${size});"
! 966: echo " if (ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_Z) {"
! 967: echo " tme_m68k_cmp${size}(ic,"
! 968: echo " &ic->tme_m68k_ireg_uint${size}(ireg_dcy${reg_size_shift}),"
! 969: echo " &ic->tme_m68k_ireg_memy${size});"
! 970: echo " }"
1.1 root 971: echo ""
1.1.1.4 ! root 972: echo " /* if the comparisons succeeded: */"
1.1 root 973: echo " if (ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_Z) {"
1.1.1.4 ! root 974: echo ""
! 975: echo " /* write the update operands to the effective address operands: */"
! 976: echo " ireg_dux = TME_M68K_IREG_D0 + TME_FIELD_EXTRACTU(specopx, 6, 3);"
! 977: echo " ireg_duy = TME_M68K_IREG_D0 + TME_FIELD_EXTRACTU(specopy, 6, 3);"
! 978: echo " ic->tme_m68k_ireg_memx${size} = ic->tme_m68k_ireg_uint${size}(ireg_dux${reg_size_shift});"
! 979: echo " ic->tme_m68k_ireg_memy${size} = ic->tme_m68k_ireg_uint${size}(ireg_duy${reg_size_shift});"
1.1 root 980: echo " }"
1.1.1.4 ! root 981: echo ""
! 982: echo " /* otherwise, the comparisons failed: */"
1.1 root 983: echo " else {"
1.1.1.4 ! root 984: echo ""
! 985: echo " /* write the effective address operands to the compare operands."
! 986: echo " \"If Dc1 and Dc2 specify the same data register and the comparison"
! 987: echo " fails, memory operand 1 is stored in the data register.\" */"
! 988: echo " ic->tme_m68k_ireg_uint${size}(ireg_dcy${reg_size_shift}) = ic->tme_m68k_ireg_memy${size};"
! 989: echo " ic->tme_m68k_ireg_uint${size}(ireg_dcx${reg_size_shift}) = ic->tme_m68k_ireg_memx${size};"
1.1 root 990: echo " }"
991: echo ""
992: echo " /* finish the read/modify/write cycle: */"
1.1.1.4 ! root 993: echo " tme_m68k_rmw_finish(ic,"
! 994: echo " &rmw,"
! 995: echo " (ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_Z) != 0);"
1.1 root 996: echo " TME_M68K_INSN_OK;"
997: echo "}"
998: fi
1.1.1.4 ! root 999: fi
1.1 root 1000:
1001: # moves:
1002: if $header; then
1003: echo "TME_M68K_INSN_DECL(tme_m68k_moves${size});"
1004: else
1005: echo ""
1006: echo "/* moves${size}: */"
1007: echo "TME_M68K_INSN(tme_m68k_moves${size})"
1008: echo "{"
1009: echo " int ireg;"
1.1.1.4 ! root 1010: echo " tme_uint${size}_t ireg_value;"
1.1.1.3 root 1011: echo " unsigned int ea_reg;"
1012: echo " unsigned int increment;"
1013: echo " TME_M68K_INSN_PRIV;"
1014: echo " TME_M68K_INSN_CANFAULT;"
1.1 root 1015: echo " ireg = TME_M68K_IREG_D0 + TME_FIELD_EXTRACTU(TME_M68K_INSN_SPECOP, 12, 4);"
1.1.1.3 root 1016: echo ""
1.1.1.4 ! root 1017: echo " /* in case we're storing the same address register used in a"
! 1018: echo " postincrement or predecrement EA, save the current value"
! 1019: echo " of the register now: */"
! 1020: echo " ireg_value = ic->tme_m68k_ireg_uint${size}(ireg${reg_size_shift});"
! 1021: echo ""
1.1.1.3 root 1022: echo " /* we have to handle postincrement and predecrement ourselves: */"
1023: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {"
1024: echo " ea_reg = TME_M68K_IREG_A0 + TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 0, 3);"
1025: echo " increment = TME_M68K_SIZE_${size};"
1026: echo " if (increment == TME_M68K_SIZE_8 && ea_reg == TME_M68K_IREG_A7) {"
1027: echo " increment = TME_M68K_SIZE_16;"
1028: echo " }"
1029: echo " switch (TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 3, 3)) {"
1030: echo " case 3: ic->tme_m68k_ireg_uint32(ea_reg) += increment; break;"
1031: echo " case 4: ic->_tme_m68k_ea_address = (ic->tme_m68k_ireg_uint32(ea_reg) -= increment); break;"
1032: echo " default: break;"
1033: echo " }"
1034: echo " }"
1035: echo ""
1.1 root 1036: echo " if (TME_M68K_INSN_SPECOP & TME_BIT(11)) {"
1.1.1.3 root 1037: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {"
1.1.1.4 ! root 1038: echo " ic->tme_m68k_ireg_memx${size} = ireg_value;"
1.1.1.3 root 1039: echo " ic->_tme_m68k_ea_function_code = ic->tme_m68k_ireg_dfc;"
1040: echo " }"
1041: echo " tme_m68k_write_memx${size}(ic);"
1.1 root 1042: echo " }"
1043: echo " else {"
1.1.1.3 root 1044: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {"
1045: echo " ic->_tme_m68k_ea_function_code = ic->tme_m68k_ireg_sfc;"
1046: echo " }"
1047: echo " tme_m68k_read_memx${size}(ic);"
1.1 root 1048: if test ${size} != 32; then
1049: echo " if (ireg >= TME_M68K_IREG_A0) {"
1050: echo " ic->tme_m68k_ireg_uint32(ireg) = "
1051: echo " TME_EXT_S${size}_U32((tme_int${size}_t) ic->tme_m68k_ireg_memx${size});"
1052: echo " }"
1053: echo " else"
1054: echo -n " "
1055: fi
1056: echo " ic->tme_m68k_ireg_uint${size}(ireg${reg_size_shift}) = ic->tme_m68k_ireg_memx${size};"
1057: echo " }"
1058: echo " TME_M68K_INSN_OK;"
1059: echo "}"
1060: fi
1061: done
1062:
1063: # generate the memory read and write functions:
1064:
1065: # permute on size:
1066: for size in 8 16 32 any; do
1067:
1068: # permute on read or write:
1069: for name in read write; do
1070: capname=`echo $name | tr a-z A-Z`
1071: if test $name = read; then
1072: from="from"
1073: else
1074: from="to"
1075: fi
1076:
1077: # permute on the special-purpose what:
1078: for what in memx mem inst stack; do
1079:
1080: # placeholder for another permutation:
1081: :
1082:
1083: # dispatch on the size:
1084: _first=_first ; _last=_last
1085: case "$size" in
1086: 8) _first= ; _last= ;;
1087: esac
1088:
1089: # set up the details of each special purpose:
1090: rval="void"
1091: args=""
1092: args_proto=""
1093: fc=""
1094: addr=""
1095: count=""
1096: tlb="TME_M68K_TLB_ENTRY(ic, function_code, linear_address${_first})"
1097: flags="TME_M68K_BUS_CYCLE_NORMAL"
1098: case "${name}-${what}-${size}" in
1099: *-memx-8 | *-memx-16 | *-memx-32)
1100: action="${name}_${what}${size}"
1101: fcptr="&ic->_tme_m68k_ea_function_code"
1102: addrptr="&ic->_tme_m68k_ea_address"
1103: reg="ic->tme_m68k_ireg_memx${size}"
1104: regptr="&${reg}"
1105: ;;
1106: *-mem-any)
1107: action="${name}_${what}"
1108: args_proto=", tme_uint8_t *, unsigned int"
1109: args=", tme_uint8_t *buffer, unsigned int count"
1110: fcptr="&ic->_tme_m68k_ea_function_code"
1111: addrptr="&ic->_tme_m68k_ea_address"
1.1.1.4 ! root 1112: _last=
1.1 root 1113: reg=
1114: regptr="buffer"
1115: ;;
1116: *-mem-8 | *-mem-16 | *-mem-32)
1117: action="${name}_${what}${size}"
1118: args_proto=", int"
1119: args="${args_proto} ireg"
1120: fcptr="&ic->_tme_m68k_ea_function_code"
1121: addrptr="&ic->_tme_m68k_ea_address"
1122: reg="ic->tme_m68k_ireg_uint${size}(ireg)"
1123: regptr="&${reg}"
1124: ;;
1125: read-stack-16 | read-stack-32)
1126: action="pop${size}"
1127: args_proto=", tme_uint${size}_t *"
1128: args="${args_proto}_value"
1129: fc="TME_M68K_FUNCTION_CODE_DATA(ic)"
1130: addrptr="&ic->tme_m68k_ireg_a7"
1131: regptr="_value"
1132: reg="*${regptr}"
1133: ;;
1134: write-stack-16 | write-stack-32)
1135: action="push${size}"
1136: args_proto=", tme_uint${size}_t "
1137: args="${args_proto}value"
1138: fc="TME_M68K_FUNCTION_CODE_DATA(ic)"
1139: addr="ic->tme_m68k_ireg_a7 - sizeof(tme_uint${size}_t)"
1140: reg="value"
1141: regptr="&${reg}"
1142: ;;
1143: read-inst-16 | read-inst-32)
1144: rval="tme_uint${size}_t"
1145: action="fetch${size}"
1146: args_proto=", tme_uint32_t"
1147: args="${args_proto} pc"
1148: fc="TME_M68K_FUNCTION_CODE_PROGRAM(ic)"
1149: addrptr="&pc"
1.1.1.4 ! root 1150: tlb="tme_memory_atomic_pointer_read(struct tme_m68k_tlb *, ic->_tme_m68k_itlb, &ic->_tme_m68k_tlbs_rwlock)";
1.1 root 1151: flags="TME_M68K_BUS_CYCLE_FETCH"
1152: ;;
1153: *)
1154: continue
1155: ;;
1156: esac
1157:
1158: # if we're making the header, just emit a declaration:
1159: if $header; then
1160: echo "${rval} tme_m68k_${action} _TME_P((struct tme_m68k *${args_proto}));"
1161: continue
1162: fi
1163:
1164: # start the function:
1165: echo ""
1166: echo "/* this ${name}s a ${size}-bit ${what} value: */"
1167: echo "${rval}"
1168: echo "tme_m68k_${action}(struct tme_m68k *ic${args}) "
1169: echo "{"
1170:
1171: # our locals:
1172: echo -n " unsigned int function_code = "
1173: if test "x${fc}" != x; then
1174: echo "${fc};"
1175: fc="function_code"
1176: fcptr="&function_code"
1177: else
1178: fc=`echo ${fcptr} | sed -e 's,^&,,'`
1179: echo "${fc};"
1180: fi
1181: echo -n " tme_uint32_t linear_address${_first} = "
1182: if test "x${addr}" != x; then
1183: echo "${addr};"
1184: addr="linear_address${_first}"
1185: addrptr="&linear_address${_first}"
1186: else
1187: addr=`echo ${addrptr} | sed -e 's,^&,,'`
1188: echo "${addr};"
1189: fi
1190: if test "x${count}" = x; then
1191: if test $size = any; then count=count; else count="sizeof(tme_uint${size}_t)"; fi
1192: fi
1193: if test x$_last != x; then
1194: echo " tme_uint32_t linear_address${_last} = linear_address_first + ${count} - 1;";
1195: fi
1196: echo " struct tme_m68k_tlb *tlb = ${tlb};"
1.1.1.4 ! root 1197: if test $size != any; then
! 1198: memtype="tme_uint${size}_t"
! 1199: echo " ${memtype} mem_value;"
! 1200: memtype="tme_shared ${memtype} *"
! 1201: if test $name = read; then memtype="const ${memtype}"; fi
! 1202: echo " ${memtype}mem;"
! 1203: fi
1.1 root 1204: case "$what" in
1205: inst)
1.1.1.4 ! root 1206: echo " unsigned int fetch_slow_next = ic->_tme_m68k_insn_fetch_slow_next;"
! 1207: regptr="((tme_uint${size}_t *) (((tme_uint8_t *) &ic->_tme_m68k_insn_fetch_buffer[0]) + fetch_slow_next))"
1.1 root 1208: reg="*${regptr}"
1209: ;;
1210: esac
1211:
1.1.1.3 root 1212: # track statistics:
1213: echo ""
1214: echo "#ifdef _TME_M68K_STATS"
1215: echo " ic->tme_m68k_stats.tme_m68k_stats_memory_total++;"
1216: echo "#endif /* _TME_M68K_STATS */"
1217:
1.1 root 1218: # if this is a write, log the value written:
1219: if test $name = write; then
1220: echo ""
1221: echo " /* log the value written: */"
1222: if test $size != any; then
1223: echo " tme_m68k_verify_mem${size}(ic, ${fc}, ${addr}, ${reg}, TME_BUS_CYCLE_WRITE);"
1224: echo " tme_m68k_log(ic, 1000, TME_OK, "
1225: echo " (TME_M68K_LOG_HANDLE(ic),"
1226: echo " _(\"${action}\t%d:0x%08x:\t0x%0"`expr ${size} / 4`"x\"),"
1227: echo " ${fc},"
1228: echo " ${addr},"
1229: echo " ${reg}));"
1230: else
1231: echo " tme_m68k_verify_mem_any(ic, ${fc}, ${addr}, ${regptr}, ${count}, TME_BUS_CYCLE_WRITE);"
1232: echo " tme_m68k_log_start(ic, 1000, TME_OK) {"
1233: echo " unsigned int byte_i;"
1234: echo " tme_log_part(TME_M68K_LOG_HANDLE(ic),"
1235: echo " _(\"${action} %d:0x%08x count %d:\"),"
1236: echo " ${fc},"
1237: echo " ${addr},"
1238: echo " ${count});"
1239: echo " for (byte_i = 0; byte_i < count ; byte_i++) {"
1240: echo " tme_log_part(TME_M68K_LOG_HANDLE(ic), \" 0x%02x\", (${regptr})[byte_i]);"
1241: echo " }"
1242: echo " } tme_m68k_log_finish(ic);"
1243: fi
1244: fi
1245:
1246: echo ""
1.1.1.4 ! root 1247: echo " /* busy this TLB entry: */"
! 1248: echo " tme_m68k_tlb_busy(tlb);"
1.1 root 1249:
1.1.1.4 ! root 1250: # if this is an any-transfer:
! 1251: #
! 1252: if test $size = any; then
! 1253: echo ""
! 1254: echo " /* call the full ${name} function: */"
! 1255: echo " tme_m68k_${name}(ic, tlb, ${fcptr}, ${addrptr}, ${regptr}, ${count}, TME_M68K_BUS_CYCLE_RAW);"
! 1256:
! 1257: # otherwise, this is not an any-transfer:
! 1258: #
1.1 root 1259: else
1260:
1.1.1.4 ! root 1261: # dispatch on the what:
! 1262: #
! 1263: i=
! 1264: case "$what" in
! 1265: inst)
! 1266: echo ""
! 1267: echo " /* if this fetch was done by the fast executor: */"
! 1268: echo " if (__tme_predict_true(fetch_slow_next < ic->_tme_m68k_insn_fetch_slow_count_fast)) {"
! 1269: echo ""
! 1270: echo " /* the entire fetch must be in the instruction buffer, and"
! 1271: echo " we must be restarting: */"
! 1272: echo " assert ((fetch_slow_next + sizeof(tme_uint${size}_t))"
! 1273: echo " <= ic->_tme_m68k_insn_fetch_slow_count_fast);"
! 1274: echo " assert (TME_M68K_SEQUENCE_RESTARTING);"
! 1275: echo " mem_value = tme_memory_read${size}(${regptr}, sizeof(tme_uint16_t));"
! 1276: echo " }"
! 1277: echo ""
! 1278: echo " /* otherwise, this fetch was not done by the fast executor: */"
! 1279: echo " else {"
! 1280: echo ""
! 1281: echo " /* if we're restarting, but the offset in the instruction buffer"
! 1282: echo " to fetch into is at the instruction buffer total, this must be"
! 1283: echo " a fake fault caused by the fast executor. we confirm this by"
! 1284: echo " checking that this transfer \"caused\" the fault, and that this"
! 1285: echo " transfer will be the first slow one after any fast fetches."
! 1286: echo " in this case, we can cancel the restart for now: */"
! 1287: echo " if (TME_M68K_SEQUENCE_RESTARTING"
! 1288: echo " && (fetch_slow_next"
! 1289: echo " == ic->_tme_m68k_insn_fetch_slow_count_total)) {"
! 1290: echo " assert ((ic->_tme_m68k_sequence._tme_m68k_sequence_transfer_next"
! 1291: echo " == ic->_tme_m68k_sequence._tme_m68k_sequence_transfer_faulted)"
! 1292: echo " && (fetch_slow_next"
! 1293: echo " == ic->_tme_m68k_insn_fetch_slow_count_fast));"
! 1294: echo " ic->_tme_m68k_sequence._tme_m68k_sequence_transfer_faulted--;"
! 1295: echo " }"
! 1296: echo ""
! 1297: echo " /* if we're not restarting: */"
! 1298: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {"
! 1299: echo ""
! 1300: echo " /* we advance the instruction buffer total *before* we do"
! 1301: echo " what may be a slow fetch, because we may transfer a few"
! 1302: echo " bytes and then fault. without this, those few bytes"
! 1303: echo " would not get saved in the exception stack frame and"
! 1304: echo " restored later before the continuation of the fetch: */"
! 1305: echo " ic->_tme_m68k_insn_fetch_slow_count_total += sizeof(tme_uint${size}_t);"
! 1306: echo " }"
! 1307: echo ""
! 1308: echo " /* make sure that if this is a new transfer or if this"
! 1309: echo " transfer faulted, that we're fetching for the current"
! 1310: echo " last positions in the instruction buffer: */"
! 1311: echo " assert ((ic->_tme_m68k_sequence._tme_m68k_sequence_transfer_next"
! 1312: echo " < ic->_tme_m68k_sequence._tme_m68k_sequence_transfer_faulted)"
! 1313: echo " || ((fetch_slow_next + sizeof(tme_uint${size}_t))"
! 1314: echo " == ic->_tme_m68k_insn_fetch_slow_count_total));"
! 1315: i=" "
! 1316: ;;
! 1317: esac
! 1318:
! 1319: echo ""
! 1320: echo "${i} /* if we aren't restarting, and this address is properly aligned,"
! 1321: echo "${i} and this TLB entry covers the operand and allows fast ${name}s: */"
! 1322: echo "${i} if (__tme_predict_true(!TME_M68K_SEQUENCE_RESTARTING"
! 1323: align_min="sizeof(tme_uint8_t)"
! 1324: if test $size != 8; then
! 1325: echo -n "${i} && ("
! 1326: if test $what = inst; then
! 1327: align_min="sizeof(tme_uint16_t)"
! 1328: echo -n "(${align_min} - 1)"
! 1329: else
! 1330: echo -n "ic->_tme_m68k_bus_16bit"
! 1331: fi
! 1332: echo " & linear_address${_first}) == 0"
1.1 root 1333: fi
1.1.1.4 ! root 1334: echo "${i} && TME_M68K_TLB_OK_FAST_${capname}(tlb,"
! 1335: echo "${i} function_code,"
! 1336: echo "${i} linear_address${_first},"
! 1337: echo "${i} linear_address${_last}))) {"
! 1338:
1.1 root 1339: echo ""
1.1.1.4 ! root 1340: echo "${i} /* make the emulator memory pointer: */"
! 1341: echo "${i} mem = (${memtype}) (tlb->tme_m68k_tlb_emulator_off_${name} + linear_address${_first});"
! 1342:
! 1343: if test $name = write; then
! 1344: if test $size = 8; then
! 1345: echo ""
! 1346: echo "${i} /* get the value to write: */"
! 1347: echo "${i} mem_value = ${reg};"
! 1348: else
! 1349: echo ""
! 1350: echo "${i} /* get the value to write, in big-endian byte order: */"
! 1351: echo "${i} mem_value = tme_htobe_u${size}(${reg});"
! 1352: fi
! 1353: fi
! 1354:
1.1 root 1355: echo ""
1.1.1.4 ! root 1356: echo "${i} /* do the ${size}-bit bus ${name}: */"
1.1 root 1357: if test $name = read; then
1.1.1.4 ! root 1358: echo -n "${i} mem_value = tme_memory_bus_${name}${size}(mem"
1.1 root 1359: else
1.1.1.4 ! root 1360: echo -n "${i} tme_memory_bus_${name}${size}(mem, mem_value"
1.1 root 1361: fi
1.1.1.4 ! root 1362: echo ", tlb->tme_m68k_tlb_bus_rwlock, ${align_min}, sizeof(tme_uint32_t));"
! 1363:
1.1 root 1364: if test $name = read; then
1.1.1.4 ! root 1365: if test $what = inst; then
! 1366: echo ""
! 1367: echo "${i} /* put the value read, in host byte order: */"
! 1368: echo "${i} mem_value = tme_betoh_u${size}(mem_value);"
! 1369: echo "${i} tme_memory_write${size}(${regptr}, mem_value, sizeof(tme_uint16_t));"
! 1370: elif test $size = 8; then
! 1371: echo ""
! 1372: echo "${i} /* put the value read: */"
! 1373: echo "${i} ${reg} = mem_value;"
! 1374: else
! 1375: echo ""
! 1376: echo "${i} /* put the value read, in host byte order: */"
! 1377: echo "${i} ${reg} = tme_betoh_u${size}(mem_value);"
! 1378: fi
1.1 root 1379: fi
1380:
1.1.1.4 ! root 1381: echo ""
! 1382: echo "${i} /* step the transfer count: */"
! 1383: echo "${i} TME_M68K_SEQUENCE_TRANSFER_STEP;"
! 1384: echo "${i} }"
! 1385:
! 1386: echo ""
! 1387: echo "${i} /* otherwise, do the bus cycles the slow way: */"
! 1388: echo "${i} else {"
! 1389: echo "${i} tme_m68k_${name}${size}(ic, tlb,"
! 1390: echo "${i} ${fcptr},"
! 1391: echo "${i} ${addrptr},"
! 1392: echo "${i} ${regptr},"
! 1393: echo "${i} ${flags});"
! 1394: if test ${what} = inst; then
! 1395: echo "${i} mem_value = tme_memory_read${size}(${regptr}, sizeof(tme_uint16_t));"
! 1396: fi
! 1397: echo "${i} }"
! 1398: fi
! 1399: if test "x${i}" != x; then
! 1400: echo " }"
1.1 root 1401: fi
1402:
1403: echo ""
1.1.1.4 ! root 1404: echo " /* unbusy this TLB entry: */"
! 1405: echo " tme_m68k_tlb_unbusy(tlb);"
1.1 root 1406:
1407: # if this is a read, log the value read:
1408: if test $name = read; then
1409: echo ""
1410: echo " /* log the value read: */"
1411: if test $size != any; then
1412: echo " tme_m68k_verify_mem${size}(ic, ${fc}, ${addr}, ${reg}, TME_BUS_CYCLE_READ);"
1413: echo " tme_m68k_log(ic, 1000, TME_OK,"
1414: echo " (TME_M68K_LOG_HANDLE(ic),"
1415: echo " _(\"${action}\t%d:0x%08x:\t0x%0"`expr ${size} / 4`"x\"),"
1416: echo " ${fc},"
1417: echo " ${addr},"
1418: echo " ${reg}));"
1419: else
1420: echo " tme_m68k_verify_mem_any(ic, ${fc}, ${addr}, ${regptr}, ${count}, TME_BUS_CYCLE_READ);"
1421: echo " tme_m68k_log_start(ic, 1000, TME_OK) {"
1422: echo " unsigned int byte_i;"
1423: echo " tme_log_part(TME_M68K_LOG_HANDLE(ic),"
1424: echo " _(\"${action} %d:0x%08x count %d:\"),"
1425: echo " ${fc},"
1426: echo " ${addr},"
1427: echo " ${count});"
1428: echo " for (byte_i = 0; byte_i < count ; byte_i++) {"
1429: echo " tme_log_part(TME_M68K_LOG_HANDLE(ic), \" 0x%02x\", (${regptr})[byte_i]);"
1430: echo " }"
1431: echo " } tme_m68k_log_finish(ic);"
1432: fi
1433: fi
1434:
1435: # perform any updating and value returning:
1436: case "$what" in
1437: stack)
1438: if test $name = read; then dir="+"; else dir="-"; fi
1439: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {"
1440: echo " ic->tme_m68k_ireg_a7 ${dir}= sizeof(tme_uint${size}_t);"
1441: echo " }"
1442: ;;
1443: inst)
1.1.1.4 ! root 1444: echo ""
! 1445: echo " /* advance the offset in the instruction buffer for the next slow fetch: */"
! 1446: echo " fetch_slow_next += sizeof(tme_uint${size}_t);"
! 1447: echo " ic->_tme_m68k_insn_fetch_slow_next = fetch_slow_next;"
! 1448: echo ""
! 1449: echo " /* return the fetched value: */"
! 1450: echo " return(mem_value);"
1.1 root 1451: ;;
1452: esac
1453:
1454: echo "}"
1455: :
1456: done
1457:
1458: # the general-purpose cycle-making read and write macros:
1459: if test ${size} != any; then
1460:
1461: # if we're making the header, emit a macro:
1462: if $header; then
1463: echo "#define tme_m68k_${name}${size}(ic, t, fc, la, _v, f) \\"
1464: echo " tme_m68k_${name}(ic, t, fc, la, (tme_uint8_t *) (_v), sizeof(tme_uint${size}_t), f)"
1465: fi
1466: else
1467:
1468: # if we're making the header, just emit a declaration:
1469: if $header; then
1470: 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));"
1471: continue
1472: fi
1473:
1474: echo ""
1475: echo "/* this ${name}s a region of address space using actual bus cycles: */"
1476: echo "void"
1477: echo "tme_m68k_${name}(struct tme_m68k *ic, "
1478: echo " struct tme_m68k_tlb *tlb,"
1479: echo " unsigned int *_function_code, "
1480: echo " tme_uint32_t *_linear_address, "
1481: echo " tme_uint8_t *reg,"
1482: echo " unsigned int reg_size,"
1483: echo " unsigned int flags)"
1484: echo "{"
1485:
1486: # our locals:
1487: echo " unsigned int function_code;"
1488: echo " tme_uint32_t linear_address;"
1489: echo " tme_bus_addr_t physical_address;"
1490: echo " int shift;"
1491: echo " struct tme_bus_cycle cycle;"
1492: echo " unsigned int transferred, resid, cycle_size;"
1493: echo " int exception;"
1494: echo " int err;"
1495: echo " tme_uint8_t *reg_p;"
1496: echo " unsigned int buffer_i;"
1.1.1.4 ! root 1497: echo " tme_uint8_t reg_buffer[sizeof(tme_uint32_t) * 2];"
! 1498: if test ${name} = read; then name_const_mem="const "; else name_const_mem= ; fi
! 1499: echo " ${name_const_mem}tme_shared tme_uint8_t *mem;"
1.1 root 1500:
1501: echo ""
1502: echo " /* if we're not restarting, everything is fresh: */"
1503: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {"
1504: echo " function_code = *_function_code;"
1505: echo " linear_address = *_linear_address;"
1506: echo " transferred = 0;"
1507: echo " }"
1508:
1509: echo ""
1510: echo " /* otherwise, if this is the transfer that faulted, restore"
1511: echo " our state to the cycle that faulted, then take into account"
1512: echo " any data provided by a software rerun of the faulted cycle: */"
1513: echo " else if (ic->_tme_m68k_sequence._tme_m68k_sequence_transfer_faulted"
1514: echo " == ic->_tme_m68k_sequence._tme_m68k_sequence_transfer_next) {"
1515: echo " function_code = *_function_code = ic->_tme_m68k_group0_function_code;"
1516: echo " linear_address = ic->_tme_m68k_group0_address;"
1517: echo " transferred = ic->_tme_m68k_sequence._tme_m68k_sequence_transfer_faulted_after;"
1518: echo " if (transferred >= reg_size) abort();"
1519: echo " *_linear_address = linear_address - transferred;"
1520: echo " resid = reg_size - transferred;"
1521: echo " if (ic->_tme_m68k_group0_buffer_${name}_size > resid) abort();"
1522: echo " if (ic->_tme_m68k_group0_buffer_${name}_softrr > resid) abort();"
1523: if test $name = read; then cmp=">"; else cmp="=="; fi
1524: echo " if (ic->_tme_m68k_group0_buffer_${name}_softrr ${cmp} 0) {"
1525: echo "#ifdef WORDS_BIGENDIAN"
1526: echo " memcpy(reg + transferred, "
1527: echo " ic->_tme_m68k_group0_buffer_${name},"
1528: echo " ic->_tme_m68k_group0_buffer_${name}_size);"
1529: echo "#else /* !WORDS_BIGENDIAN */"
1530: echo " reg_p = (reg + reg_size - 1) - transferred;"
1531: echo " for (buffer_i = 0;"
1532: echo " buffer_i < ic->_tme_m68k_group0_buffer_${name}_size;"
1533: echo " buffer_i++) {"
1534: echo " *(reg_p--) = ic->_tme_m68k_group0_buffer_${name}[buffer_i];"
1535: echo " }"
1536: echo "#endif /* !WORDS_BIGENDIAN */"
1537: echo " }"
1538: echo " transferred += ic->_tme_m68k_group0_buffer_${name}_softrr;"
1539: echo " }"
1540:
1541: echo ""
1542: echo " /* otherwise, a later transfer has faulted. just step the"
1543: echo " transfer number and return: */"
1544: echo " else {"
1545: echo " TME_M68K_SEQUENCE_TRANSFER_STEP;"
1546: echo " return;"
1547: echo " }"
1548:
1549: echo ""
1550: echo " /* do as many bus cycles as needed to complete the transfer: */"
1551: echo " exception = TME_M68K_EXCEPTION_NONE;"
1552: echo " cycle_size = 0;"
1553: echo " for(; transferred < reg_size; ) {"
1554: echo " resid = reg_size - transferred;"
1555:
1556: echo ""
1557: echo " /* start the bus cycle structure: */"
1558: echo " cycle.tme_bus_cycle_type = TME_BUS_CYCLE_${capname};"
1559: echo " if (TME_ENDIAN_NATIVE == TME_ENDIAN_BIG"
1560: echo " || (flags & TME_M68K_BUS_CYCLE_RAW)) {"
1561: echo " cycle.tme_bus_cycle_buffer = reg + transferred;"
1562: echo " cycle.tme_bus_cycle_buffer_increment = 1;"
1563: echo " }"
1564: echo " else {"
1565: echo " cycle.tme_bus_cycle_buffer = reg + reg_size - (1 + transferred);"
1566: echo " cycle.tme_bus_cycle_buffer_increment = -1;"
1567: echo " }"
1568:
1569: echo ""
1570: echo " /* if we're emulating a CPU with a 16-bit bus interface: */"
1571: echo " if (ic->_tme_m68k_bus_16bit) {"
1572: echo ""
1573: echo " /* if we're trying to transfer a non-power-of-two"
1574: echo " number of bytes, either the CPU is broken (no"
1575: echo " instructions ever transfer a non-power-of-two"
1576: echo " number of bytes), or this function allowed an"
1577: echo " unaligned transfer: */"
1578: echo " assert((resid & (resid - 1)) == 0"
1579: echo " || (flags & TME_M68K_BUS_CYCLE_RAW));"
1580: echo ""
1581: echo " /* only byte transfers can be unaligned: */"
1582: echo " if (resid > sizeof(tme_uint8_t)"
1583: echo " && (linear_address & 1)) {"
1.1.1.3 root 1584: echo " exception = TME_M68K_EXCEPTION_AERR;"
1.1 root 1585: echo " break;"
1586: echo " }"
1587: echo ""
1588: echo " /* set the bus-size specific parts of the bus cycle structure: */"
1589: echo " cycle_size = TME_MIN(resid, sizeof(tme_uint16_t));"
1590: echo " cycle.tme_bus_cycle_size = cycle_size;"
1591: echo " cycle.tme_bus_cycle_port = TME_BUS_CYCLE_PORT(0, TME_BUS16_LOG2);"
1592: echo " cycle.tme_bus_cycle_lane_routing = "
1593: echo " &tme_m68k_router_16[TME_M68K_BUS_ROUTER_INDEX(TME_BUS16_LOG2, cycle_size, linear_address)];"
1594: echo " }"
1595: echo ""
1596: echo " /* otherwise we're emulating a CPU with a 32-bit bus interface: */"
1597: echo " else {"
1598: if test $name = read; then
1599: echo ""
1600: echo " /* an instruction fetch must be aligned: */"
1601: echo " if (flags & TME_M68K_BUS_CYCLE_FETCH) {"
1602: echo " if (linear_address & 1) {"
1.1.1.3 root 1603: echo " exception = TME_M68K_EXCEPTION_AERR;"
1.1 root 1604: echo " break;"
1605: echo " }"
1606: echo " assert(!(resid & 1));"
1607: echo " }"
1608: fi
1609: echo ""
1610: echo " /* set the bus-size specific parts of the bus cycle structure: */"
1611: echo " cycle_size = TME_MIN(resid, sizeof(tme_uint32_t) - (linear_address & (sizeof(tme_uint32_t) - 1)));"
1612: echo " cycle.tme_bus_cycle_size = cycle_size;"
1613: echo " cycle.tme_bus_cycle_port = TME_BUS_CYCLE_PORT(0, TME_BUS32_LOG2);"
1614: echo " cycle.tme_bus_cycle_lane_routing = "
1615: echo " &tme_m68k_router_32[TME_M68K_BUS_ROUTER_INDEX(TME_BUS32_LOG2, cycle_size, linear_address)];"
1616: echo " }"
1617:
1618: echo ""
1.1.1.4 ! root 1619: echo " /* loop while this TLB entry is invalid or does not apply: */"
! 1620: echo " for (; __tme_predict_false(tme_bus_tlb_is_invalid(&tlb->tme_m68k_tlb_bus_tlb)"
! 1621: echo " || (tlb->tme_m68k_tlb_function_codes_mask & TME_BIT(function_code)) == 0"
! 1622: echo " || linear_address < tlb->tme_m68k_tlb_linear_first"
! 1623: echo " || linear_address > tlb->tme_m68k_tlb_linear_last"
! 1624: echo " || (tlb->tme_m68k_tlb_emulator_off_${name} == TME_EMULATOR_OFF_UNDEF"
! 1625: echo " && (tlb->tme_m68k_tlb_cycles_ok & TME_BUS_CYCLE_${capname}) == 0)); ) {"
! 1626: echo ""
! 1627: echo " /* this must not be part of a read/modify/write cycle: */"
! 1628: echo " assert(!(flags & TME_M68K_BUS_CYCLE_RMW));"
! 1629: echo ""
! 1630: echo " /* fill this TLB entry: */"
1.1 root 1631: echo " tme_m68k_tlb_fill(ic, tlb,"
1632: echo " function_code,"
1633: echo " linear_address,"
1634: echo " TME_BUS_CYCLE_${capname});"
1635: echo " }"
1636: echo ""
1.1.1.4 ! root 1637: echo " /* if this TLB entry allows for fast ${name}s: */"
! 1638: echo " mem = tlb->tme_m68k_tlb_emulator_off_${name};"
! 1639: echo " if (__tme_predict_true(mem != TME_EMULATOR_OFF_UNDEF)) {"
! 1640: echo ""
! 1641: echo " /* make the emulator memory pointer: */"
! 1642: echo " mem += linear_address;"
! 1643: echo ""
! 1644: echo " /* limit the cycle size to addresses covered by the TLB entry: */"
! 1645: echo " if (__tme_predict_false((cycle_size - 1)"
! 1646: echo " > (tlb->tme_m68k_tlb_linear_last - linear_address))) {"
! 1647: echo " cycle_size = (tlb->tme_m68k_tlb_linear_last - linear_address) + 1;"
1.1 root 1648: echo " }"
1649: echo ""
1.1.1.4 ! root 1650: echo " /* if this is a little-endian host, and this isn't a raw ${name}: */"
! 1651: echo " if (TME_ENDIAN_NATIVE == TME_ENDIAN_LITTLE"
! 1652: echo " && (flags & TME_M68K_BUS_CYCLE_RAW) == 0) {"
! 1653: if test ${name} = write; then
! 1654: echo ""
! 1655: echo " /* byteswap the data to write in the intermediate buffer: */"
! 1656: echo " reg_p = cycle.tme_bus_cycle_buffer;"
! 1657: echo " buffer_i = 0;"
! 1658: echo " do {"
! 1659: echo " reg_buffer[buffer_i] = *(reg_p--);"
! 1660: echo " } while (++buffer_i != cycle_size);"
! 1661: fi
! 1662: echo ""
! 1663: echo " /* use the intermediate buffer for the ${name}: */"
! 1664: echo " cycle.tme_bus_cycle_buffer = ®_buffer[0];"
1.1 root 1665: echo " }"
1.1.1.4 ! root 1666: echo ""
! 1667: echo " /* do the bus ${name}: */"
! 1668: echo " tme_memory_bus_${name}_buffer(mem,"
! 1669: echo " cycle.tme_bus_cycle_buffer,"
! 1670: echo " cycle_size,"
! 1671: echo " tlb->tme_m68k_tlb_bus_rwlock,"
! 1672: echo " sizeof(tme_uint8_t),"
! 1673: echo " sizeof(tme_uint32_t));"
! 1674: if test ${name} = read; then
! 1675: echo ""
! 1676: echo " /* if this is a little-endian host, and this isn't a raw ${name}: */"
! 1677: echo " if (TME_ENDIAN_NATIVE == TME_ENDIAN_LITTLE"
! 1678: echo " && (flags & TME_M68K_BUS_CYCLE_RAW) == 0) {"
! 1679: echo ""
! 1680: echo " /* byteswap the read data in the intermediate buffer: */"
! 1681: echo " reg_p = reg + reg_size - (1 + transferred);"
! 1682: echo " buffer_i = 0;"
! 1683: echo " do {"
! 1684: echo " *(reg_p--) = reg_buffer[buffer_i];"
! 1685: echo " } while (++buffer_i != cycle_size);"
! 1686: echo " }"
! 1687: fi
! 1688: echo ""
! 1689: echo " /* update: */"
! 1690: echo " linear_address += cycle_size;"
! 1691: echo " transferred += cycle_size;"
! 1692: echo " continue;"
! 1693: echo " }"
! 1694: echo ""
! 1695: echo " /* otherwise, this TLB entry does not allow for fast ${name}s: */"
! 1696: echo ""
! 1697: echo " /* if this is a part of a read/modify/write cycle: */"
! 1698: echo " if (flags & TME_M68K_BUS_CYCLE_RMW) {"
! 1699: echo ""
! 1700: if test ${name} = read; then
! 1701: echo " /* if this is the first cycle in this read,"
! 1702: echo " we will establish the new lock, otherwise"
! 1703: echo " we will continue using the existing lock: */"
! 1704: else
! 1705: echo " /* we will continue using the existing lock."
! 1706: echo " the device will automatically unlock after"
! 1707: echo " the last cycle of this write: */"
! 1708: fi
! 1709: echo " cycle.tme_bus_cycle_type"
! 1710: echo " |= (TME_BUS_CYCLE_LOCK"
! 1711: echo -n " | ("
! 1712: if test ${name} = read; then
! 1713: echo -n "transferred == 0 ? 0 : "
! 1714: fi
! 1715: echo "TME_BUS_CYCLE_UNLOCK));"
1.1 root 1716: echo " }"
1717:
1718: echo ""
1719: echo " /* form the physical address for the bus cycle handler: */"
1720: echo " physical_address = tlb->tme_m68k_tlb_addr_offset + linear_address;"
1721: echo " shift = tlb->tme_m68k_tlb_addr_shift;"
1722: echo " if (shift < 0) {"
1723: echo " physical_address <<= (0 - shift);"
1724: echo " }"
1725: echo " else if (shift > 0) {"
1726: echo " physical_address >>= shift;"
1727: echo " }"
1728: echo " cycle.tme_bus_cycle_address = physical_address;"
1729:
1730: echo ""
1731: echo " /* run the bus cycle: */"
1.1.1.4 ! root 1732: echo " tme_m68k_tlb_unbusy(tlb);"
! 1733: echo " tme_m68k_callout_unlock(ic);"
1.1 root 1734: echo " err = (*tlb->tme_m68k_tlb_bus_tlb.tme_bus_tlb_cycle)"
1735: echo " (tlb->tme_m68k_tlb_bus_tlb.tme_bus_tlb_cycle_private, &cycle);"
1.1.1.4 ! root 1736: echo " tme_m68k_callout_relock(ic);"
! 1737: echo " tme_m68k_tlb_busy(tlb);"
1.1 root 1738: echo ""
1.1.1.4 ! root 1739: echo " /* if the TLB entry was invalidated before the ${name}: */"
! 1740: echo " if (err == EBADF"
! 1741: echo " && tme_bus_tlb_is_invalid(&tlb->tme_m68k_tlb_bus_tlb)) {"
! 1742: echo " cycle.tme_bus_cycle_size = 0;"
1.1 root 1743: echo " }"
1744: echo ""
1.1.1.3 root 1745: echo " /* otherwise, if we didn't get a bus error, but some"
1746: echo " synchronous event has happened: */"
1747: echo " else if (err == TME_BUS_CYCLE_SYNCHRONOUS_EVENT) {"
1748: echo ""
1749: echo " /* after the currently executing instruction finishes, check"
1750: echo " for external resets, halts, or interrupts: */"
1751: echo " ic->_tme_m68k_instruction_burst_remaining = 0;"
1752: echo " }"
1753: echo ""
1.1 root 1754: echo " /* otherwise, any other error might be a bus error: */"
1755: echo " else if (err != TME_OK) {"
1756: echo " err = tme_bus_tlb_fault(&tlb->tme_m68k_tlb_bus_tlb, &cycle, err);"
1757: echo " if (err != TME_OK) {"
1.1.1.3 root 1758: echo " exception = TME_M68K_EXCEPTION_BERR;"
1.1 root 1759: echo " break;"
1760: echo " }"
1761: echo " }"
1762: echo ""
1763: echo " /* update: */"
1764: echo " linear_address += cycle.tme_bus_cycle_size;"
1765: echo " transferred += cycle.tme_bus_cycle_size;"
1766: echo " }"
1767:
1768: echo ""
1.1.1.4 ! root 1769: echo " /* NB: there is no need to explicitly unlock"
! 1770: echo " a device. if a locked bus cycle to a device"
! 1771: echo " faults, the lock must be automatically unlocked: */"
1.1 root 1772:
1773: echo ""
1774: echo " /* if we faulted, stash the information the fault stacker"
1775: echo " will need and start exception processing: */"
1776: echo " if (exception != TME_M68K_EXCEPTION_NONE) {"
1777: echo -n " ic->_tme_m68k_group0_flags = flags"
1778: if test $name = read; then
1779: echo -n " | TME_M68K_BUS_CYCLE_READ"
1780: fi
1781: echo ";"
1782: echo " ic->_tme_m68k_group0_function_code = function_code;"
1783: echo " ic->_tme_m68k_group0_address = linear_address;"
1784: echo " ic->_tme_m68k_group0_sequence = ic->_tme_m68k_sequence;"
1785: echo " ic->_tme_m68k_group0_sequence._tme_m68k_sequence_transfer_faulted_after = transferred;"
1786: echo " ic->_tme_m68k_group0_buffer_${name}_size = cycle_size;"
1787: if test $name = write; then
1788: echo "#ifdef WORDS_BIGENDIAN"
1789: echo " memcpy(ic->_tme_m68k_group0_buffer_${name},"
1790: echo " reg + transferred,"
1791: echo " ic->_tme_m68k_group0_buffer_${name}_size);"
1792: echo "#else /* !WORDS_BIGENDIAN */"
1793: echo " reg_p = (reg + reg_size - 1) - transferred;"
1794: echo " for (buffer_i = 0;"
1795: echo " buffer_i < ic->_tme_m68k_group0_buffer_${name}_size;"
1796: echo " buffer_i++) {"
1797: echo " ic->_tme_m68k_group0_buffer_${name}[buffer_i] = *(reg_p--);"
1798: echo " }"
1799: echo "#endif /* !WORDS_BIGENDIAN */"
1800: fi
1801: echo " if (ic->_tme_m68k_group0_hook != NULL) {"
1802: echo " (*ic->_tme_m68k_group0_hook)(ic);"
1803: echo " }"
1804: echo " ic->_tme_m68k_group0_sequence._tme_m68k_sequence_transfer_faulted = ";
1805: echo " ic->_tme_m68k_group0_sequence._tme_m68k_sequence_transfer_next;"
1.1.1.4 ! root 1806: echo " tme_m68k_tlb_unbusy(tlb);"
1.1 root 1807: echo " tme_m68k_exception(ic, exception);"
1808: echo " }"
1809:
1810: echo ""
1811: echo " /* otherwise, this transfer has now completed: */"
1812: echo " TME_M68K_SEQUENCE_TRANSFER_STEP;"
1813:
1814: echo "}"
1815: fi
1816: done
1817:
1818: done
1819:
1820: # generate the BCD math functions:
1821: for name in abcd sbcd nbcd; do
1822:
1823: # if we're making the header, just emit a declaration:
1824: if $header; then
1825: echo "TME_M68K_INSN_DECL(tme_m68k_${name});"
1826: continue
1827: fi
1828:
1829: # emit the function:
1830: echo ""
1831: echo "TME_M68K_INSN(tme_m68k_${name})"
1832: echo "{"
1833: echo " tme_uint8_t dst, dst_msd, dst_lsd;"
1834: echo " tme_uint8_t src, src_msd, src_lsd;"
1835: echo " tme_uint8_t res, res_msd, res_lsd;"
1836: echo " tme_uint8_t flags;"
1837:
1838: # get the operands:
1839: if test $name != nbcd; then
1840: echo " int memory;"
1841: echo " int rx, ry, function_code;"
1842: echo ""
1843: echo " /* load the operands: */"
1844: echo " rx = TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 0, 3);"
1845: echo " ry = TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 9, 3);"
1846: echo " memory = (TME_M68K_INSN_OPCODE & TME_BIT(3)) != 0;"
1847: echo " function_code = TME_M68K_FUNCTION_CODE_DATA(ic);"
1848: echo " if (memory) {"
1.1.1.4 ! root 1849: echo " TME_M68K_INSN_CANFAULT;"
1.1 root 1850: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {"
1.1.1.4 ! root 1851: # the stack pointer must always be decremented by a multiple of two.
! 1852: # assuming rx < 8, ((rx + 1) >> 3) == 1 iff rx == 7, meaning %a7:
! 1853: echo " ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + rx) -= sizeof(tme_uint8_t) + ((rx + 1) >> 3);"
1.1 root 1854: echo " ic->_tme_m68k_ea_function_code = function_code;"
1855: echo " ic->_tme_m68k_ea_address = ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + rx);"
1856: echo " }"
1857: echo " tme_m68k_read_memx8(ic);"
1858: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {"
1.1.1.4 ! root 1859: # the stack pointer must always be incremented by a multiple of two.
! 1860: # assuming rx < 8, ((rx + 1) >> 3) == 1 iff rx == 7, meaning %a7:
! 1861: echo " ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ry) -= sizeof(tme_uint8_t) + ((ry + 1) >> 3);"
1.1 root 1862: echo " ic->_tme_m68k_ea_function_code = function_code;"
1863: echo " ic->_tme_m68k_ea_address = ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ry);"
1864: echo " }"
1865: echo " tme_m68k_read_mem8(ic, TME_M68K_IREG_MEMY32);"
1866: echo " src = ic->tme_m68k_ireg_memx8;"
1867: echo " dst = ic->tme_m68k_ireg_memy8;"
1868: echo " }"
1869: echo " else {"
1870: echo " src = ic->tme_m68k_ireg_uint8(rx << 2);"
1871: echo " dst = ic->tme_m68k_ireg_uint8(ry << 2);"
1872: echo " }"
1873: else
1874: echo ""
1875: echo " dst = 0x00;"
1876: echo " src = TME_M68K_INSN_OP1(tme_uint8_t);"
1877: fi
1878: echo " dst_lsd = TME_FIELD_EXTRACTU(dst, 0, 4);"
1879: echo " dst_msd = TME_FIELD_EXTRACTU(dst, 4, 4);"
1880: echo " src_lsd = TME_FIELD_EXTRACTU(src, 0, 4);"
1881: echo " src_msd = TME_FIELD_EXTRACTU(src, 4, 4);"
1882:
1883: # perform the operation:
1884: echo ""
1885: echo " /* perform the operation: */"
1886: if test $name = abcd; then op='+' ; opc='-' ; else op='-' ; opc='+' ; fi
1887: echo " res_lsd = dst_lsd ${op} src_lsd ${op} ((ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_X) != 0);"
1888: echo " res_msd = dst_msd ${op} src_msd;"
1889: echo " flags = 0;"
1890: echo " if (res_lsd > 9) {"
1891: echo " res_lsd ${opc}= 10;"
1892: echo " res_msd ${op}= 1;"
1893: echo " }"
1894: echo " if (res_msd > 9) {"
1895: echo " res_msd ${opc}= 10;"
1896: echo " flags |= TME_M68K_FLAG_C | TME_M68K_FLAG_X;"
1897: echo " }"
1898: echo " res = (res_msd << 4) + (res_lsd & 0xf);"
1899: echo " if (res == 0) flags |= TME_M68K_FLAG_N;"
1900: echo ""
1901:
1902: # store the result
1903: echo " /* store the result and set the flags: */"
1904: if test $name != nbcd; then
1905: echo " if (memory) {"
1906: echo " if (!TME_M68K_SEQUENCE_RESTARTING) {"
1907: echo " ic->tme_m68k_ireg_memx8 = res;"
1908: echo " ic->_tme_m68k_ea_function_code = function_code;"
1909: echo " ic->_tme_m68k_ea_address = ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ry);"
1910: echo " ic->tme_m68k_ireg_ccr = flags;"
1911: echo " }"
1912: echo " tme_m68k_write_memx8(ic);"
1913: echo " }"
1914: echo " else {"
1915: echo " ic->tme_m68k_ireg_uint8(ry << 2) = res;"
1916: echo " ic->tme_m68k_ireg_ccr = flags;"
1917: echo " }"
1918: else
1919: echo " TME_M68K_INSN_OP1(tme_uint8_t) = res;"
1920: echo " ic->tme_m68k_ireg_ccr = flags;"
1921: fi
1922: echo ""
1923: echo " TME_M68K_INSN_OK;"
1924: echo "}"
1925: done
1926:
1927: # generate the ccr and sr functions:
1928: for reg in ccr sr; do
1929: for name in ori andi eori move_to; do
1930: if test $reg = ccr; then size=8 ; else size=16 ; fi
1931:
1932: # if we're making the header, just emit a declaration:
1933: if $header; then
1934: echo "TME_M68K_INSN_DECL(tme_m68k_${name}_${reg});"
1935: continue
1936: fi
1937:
1938: # emit the function:
1939: echo ""
1940: echo "TME_M68K_INSN(tme_m68k_${name}_${reg})"
1941: echo "{"
1942: echo " tme_uint${size}_t reg;"
1943:
1944: # form the new register value:
1945: src=0
1946: echo -n " reg = "
1947: case $name in
1948: ori) echo -n "ic->tme_m68k_ireg_${reg} | " ;;
1949: andi) echo -n "ic->tme_m68k_ireg_${reg} & " ;;
1950: eori) echo -n "ic->tme_m68k_ireg_${reg} ^ " ;;
1951: move_to) size=16 ; src=1 ;;
1952: esac
1953: echo "(TME_M68K_INSN_OP${src}(tme_uint${size}_t) & TME_M68K_FLAG_"`echo $reg | tr a-z A-Z`");"
1954:
1955: # sr changes are special:
1956: if test $reg = sr; then
1957: echo " TME_M68K_INSN_PRIV;"
1958: echo " TME_M68K_INSN_CHANGE_SR(reg);"
1959: else
1960: echo " ic->tme_m68k_ireg_${reg} = reg;"
1961: fi
1962:
1963: echo " TME_M68K_INSN_OK;"
1964: echo "}"
1965: done
1966: done
1967:
1968: # generate the multiply and divide instructions:
1969:
1970: # permute on signed vs. unsigned:
1971: for _sign in u s; do
1972: if test $_sign = u; then sign=u; else sign=; fi
1973:
1974: # permute on short vs. long:
1975: for size in s l; do
1976: if test $size = s; then
1977: _size=
1978: small=16
1979: large=32
1980: reg_size_shift=' << 1'
1981: else
1982: _size=l
1983: small=32
1984: large=64
1985: reg_size_shift=
1986: fi
1987:
1988: # if we're making the header, just emit declarations:
1989: if $header; then
1990: echo "TME_M68K_INSN_DECL(tme_m68k_mul${_sign}${_size});"
1991: echo "TME_M68K_INSN_DECL(tme_m68k_div${_sign}${_size});"
1992: continue
1993: fi
1994:
1995: # emit the multiply function:
1996: echo ""
1997: echo "TME_M68K_INSN(tme_m68k_mul${_sign}${_size})"
1998: echo "{"
1999: if test $large = 64; then
1.1.1.2 root 2000: echo "#ifndef TME_HAVE_INT${large}_T"
1.1 root 2001: echo " abort();"
1.1.1.2 root 2002: echo "#else /* TME_HAVE_INT${large}_T */"
1.1 root 2003: echo " unsigned int flag_v;"
2004: echo " int ireg_dh;"
2005: fi
2006: echo " int ireg_dl;"
2007: echo " tme_${sign}int${large}_t res;"
2008: echo " tme_uint8_t flags;"
2009:
2010: echo ""
2011: echo " /* get the register containing the factor: */"
2012: echo -n " ireg_dl = TME_M68K_IREG_D0 + "
2013: if test $size = s; then
2014: echo "TME_M68K_INSN_OP0(tme_uint32_t);"
2015: else
2016: echo "TME_FIELD_EXTRACTU(TME_M68K_INSN_SPECOP, 12, 3);"
2017: fi
2018:
2019: echo ""
2020: echo " /* perform the multiplication: */"
2021: echo " res = (((tme_${sign}int${large}_t) ic->tme_m68k_ireg_${sign}int${small}(ireg_dl${reg_size_shift}))"
2022: echo " * TME_M68K_INSN_OP1(tme_${sign}int${small}_t));"
2023:
2024: echo ""
2025: echo " /* store the result: */"
2026: echo " ic->tme_m68k_ireg_${sign}int32(ireg_dl) = (tme_${sign}int32_t) res;"
2027: if test $large = 64; then
2028: echo " flag_v = TME_M68K_FLAG_V;"
2029: echo " if (TME_M68K_INSN_SPECOP & TME_BIT(10)) {"
2030: echo " flag_v = 0;"
2031: echo " ireg_dh = TME_M68K_IREG_D0 + TME_FIELD_EXTRACTU(TME_M68K_INSN_SPECOP, 0, 3);"
2032: echo " ic->tme_m68k_ireg_${sign}int32(ireg_dh) = (tme_${sign}int32_t) (res >> 32);"
2033: echo " }"
2034: fi
2035:
2036: echo ""
2037: echo " /* set the flags: */"
2038: echo " flags = ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_X;"
2039: echo " if (((tme_int${large}_t) res) < 0) flags |= TME_M68K_FLAG_N;"
2040: echo " if (res == 0) flags |= TME_M68K_FLAG_Z;"
2041: if test $large = 64; then
1.1.1.2 root 2042: if test $_sign = s; then
2043: echo -n " if (res > 0x7fffffffL || res < ((0L - 0x7fffffffL) - 1L)"
2044: else
2045: echo -n " if (res > 0xffffffffUL"
2046: fi
1.1 root 2047: echo ") flags |= flag_v;"
2048: fi
2049: echo " ic->tme_m68k_ireg_ccr = flags;"
2050:
2051: echo ""
2052: echo " TME_M68K_INSN_OK;"
2053: if test $large = 64; then
1.1.1.2 root 2054: echo "#endif /* TME_HAVE_INT${large}_T */"
1.1 root 2055: fi
2056: echo "}"
2057:
2058: # emit the divide function:
2059: echo ""
2060: echo "TME_M68K_INSN(tme_m68k_div${_sign}${_size})"
2061: echo "{"
2062: if test $large = 64; then
1.1.1.2 root 2063: echo "#ifndef TME_HAVE_INT${large}_T"
1.1 root 2064: echo " abort();"
1.1.1.2 root 2065: echo "#else /* TME_HAVE_INT${large}_T */"
1.1 root 2066: echo " int ireg_dr;"
2067: fi
2068: echo " int ireg_dq;"
2069: echo " tme_${sign}int${large}_t dividend, quotient;"
2070: echo " tme_${sign}int${small}_t divisor, remainder;"
2071: echo " tme_uint8_t flags;"
2072:
2073: echo ""
2074: echo " /* get the register(s): */"
2075: echo -n " ireg_dq = TME_M68K_IREG_D0 + "
2076: if test $size = s; then
2077: echo "TME_M68K_INSN_OP0(tme_uint32_t);"
2078: else
2079: echo "TME_FIELD_EXTRACTU(TME_M68K_INSN_SPECOP, 12, 3);"
2080: echo " ireg_dr = TME_M68K_IREG_D0 + TME_FIELD_EXTRACTU(TME_M68K_INSN_SPECOP, 0, 3);"
2081: fi
2082:
2083: echo ""
2084: echo " /* form the dividend and the divisor: */"
2085: if test $large = 64; then
2086: echo " if (TME_M68K_INSN_SPECOP & TME_BIT(10)) {"
2087: echo " dividend = (tme_${sign}int${large}_t)"
2088: echo " ((((tme_uint${large}_t) ic->tme_m68k_ireg_uint32(ireg_dr)) << 32)"
2089: echo " | ic->tme_m68k_ireg_uint32(ireg_dq));"
2090: echo " }"
2091: echo " else"
2092: echo -n " "
2093: fi
2094: echo " dividend = (tme_${sign}int${large}_t) ic->tme_m68k_ireg_${sign}int32(ireg_dq);"
2095: echo " divisor = TME_M68K_INSN_OP1(tme_${sign}int${small}_t);"
2096: echo " if (divisor == 0) {"
1.1.1.3 root 2097: echo " ic->tme_m68k_ireg_pc_last = ic->tme_m68k_ireg_pc;"
1.1 root 2098: echo " ic->tme_m68k_ireg_pc = ic->tme_m68k_ireg_pc_next;"
1.1.1.3 root 2099: echo " TME_M68K_INSN_EXCEPTION(TME_M68K_EXCEPTION_INST(TME_M68K_VECTOR_DIV0));"
1.1 root 2100: echo " }"
2101:
2102: echo ""
2103: echo " /* do the division: */"
2104: echo " quotient = dividend / divisor;"
2105: echo " remainder = dividend % divisor;"
2106:
2107: echo ""
2108: echo " /* set the flags and return the quotient and remainder: */"
2109: echo " flags = ic->tme_m68k_ireg_ccr & TME_M68K_FLAG_X;"
1.1.1.2 root 2110: echo -n " if ("
2111: case "${small}${_sign}" in
2112: 16s) echo -n "quotient > 0x7fff || quotient < -32768" ;;
2113: 16u) echo -n "quotient > 0xffff" ;;
2114: 32s) echo -n "quotient > 0x7fffffffL || quotient < ((0L - 0x7fffffffL) - 1L)" ;;
2115: 32u) echo -n "quotient > 0xffffffffUL" ;;
2116: esac
1.1 root 2117: echo ") {"
2118: echo " flags |= TME_M68K_FLAG_V;"
2119: echo " }"
2120: echo " else {"
2121: echo " if (((tme_int${small}_t) quotient) < 0) flags |= TME_M68K_FLAG_N;"
2122: echo " if (quotient == 0) flags |= TME_M68K_FLAG_Z;"
2123: echo " ic->tme_m68k_ireg_${sign}int${small}(ireg_dq${reg_size_shift}) = (tme_${sign}int${small}_t) quotient;"
2124: if test $small = 16; then
2125: echo " ic->tme_m68k_ireg_${sign}int${small}((ireg_dq${reg_size_shift}) + 1) = remainder;"
2126: else
2127: echo " if (ireg_dr != ireg_dq) {"
2128: echo " ic->tme_m68k_ireg_${sign}int${small}(ireg_dr) = remainder;"
2129: echo " }"
2130: fi
2131: echo " }"
2132: echo " ic->tme_m68k_ireg_ccr = flags;"
2133:
2134: echo ""
2135: echo " TME_M68K_INSN_OK;"
2136: if test $large = 64; then
1.1.1.2 root 2137: echo "#endif /* TME_HAVE_INT${large}_T */"
1.1 root 2138: fi
2139: echo "}"
2140:
2141: done
2142: done
2143:
2144: # done:
2145: exit 0
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.