|
|
1.1 root 1: #! /bin/sh
2:
1.1.1.2 ! root 3: # $Id: m68k-misc-auto.sh,v 1.10 2005/04/30 15:19:45 fredette Exp $
1.1 root 4:
5: # ic/m68k/m68k-misc-auto.sh - automatically generates C code
6: # for miscellaneous m68k emulation support:
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! */
51: EOF
52:
53: # we need our own inclusion protection, since the instruction word
54: # fetch macros need to be multiply included:
55: if $header; then
56: echo ""
57: echo "#ifndef _IC_M68K_MISC_H"
58: echo "#define _IC_M68K_MISC_H"
59: fi
60:
61: # emit the register mapping macros:
62: if $header; then
63:
64: echo ""
65: echo "/* the register mapping: */"
66: echo "#define TME_M68K_IREG_UNDEF (-1)"
67: ireg32_next=0
68:
69: # NB: these are in a deliberate order, matching the order of
70: # registers in instruction encodings:
71: for regtype in d a; do
72: capregtype=`echo ${regtype} | tr a-z A-Z`
73: for regnum in 0 1 2 3 4 5 6 7; do
74: echo "#define TME_M68K_IREG_${capregtype}${regnum} (${ireg32_next})"
75: echo "#define tme_m68k_ireg_${regtype}${regnum} tme_m68k_ireg_uint32(TME_M68K_IREG_${capregtype}${regnum})"
76: ireg32_next=`expr ${ireg32_next} + 1`
77: done
78: done
79:
1.1.1.2 ! root 80: # the current, next, and last program counter:
1.1 root 81: echo "#define TME_M68K_IREG_PC (${ireg32_next})"
82: echo "#define tme_m68k_ireg_pc tme_m68k_ireg_uint32(TME_M68K_IREG_PC)"
83: ireg32_next=`expr ${ireg32_next} + 1`
84: echo "#define TME_M68K_IREG_PC_NEXT (${ireg32_next})"
85: echo "#define tme_m68k_ireg_pc_next tme_m68k_ireg_uint32(TME_M68K_IREG_PC_NEXT)"
86: ireg32_next=`expr ${ireg32_next} + 1`
1.1.1.2 ! root 87: echo "#define TME_M68K_IREG_PC_LAST (${ireg32_next})"
! 88: echo "#define tme_m68k_ireg_pc_last tme_m68k_ireg_uint32(TME_M68K_IREG_PC_LAST)"
! 89: ireg32_next=`expr ${ireg32_next} + 1`
1.1 root 90:
91: # the status register and ccr:
92: echo "#define tme_m68k_ireg_sr tme_m68k_ireg_uint16(${ireg32_next} << 1)"
93: echo "#define tme_m68k_ireg_ccr tme_m68k_ireg_uint8(${ireg32_next} << 2)"
94: ireg32_next=`expr ${ireg32_next} + 1`
95:
96: # the shadow status register and format/offset word:
97: echo "#define TME_M68K_IREG_SHADOW_SR (${ireg32_next} << 1)"
98: echo "#define tme_m68k_ireg_shadow_sr tme_m68k_ireg_uint16(TME_M68K_IREG_SHADOW_SR)"
99: echo "#define TME_M68K_IREG_FORMAT_OFFSET ((${ireg32_next} << 1) + 1)"
100: echo "#define tme_m68k_ireg_format_offset tme_m68k_ireg_uint16(TME_M68K_IREG_FORMAT_OFFSET)"
101: ireg32_next=`expr ${ireg32_next} + 1`
102:
103: # the memory buffers:
104: for mem_which in x y z; do
105: cap_mem_which=`echo ${mem_which} | tr a-z A-Z`
106: echo "#define TME_M68K_IREG_MEM${cap_mem_which}32 (${ireg32_next})"
107: echo "#define tme_m68k_ireg_mem${mem_which}32 tme_m68k_ireg_uint32(TME_M68K_IREG_MEM${cap_mem_which}32)"
108: echo "#define TME_M68K_IREG_MEM${cap_mem_which}16 (${ireg32_next} << 1)"
109: echo "#define tme_m68k_ireg_mem${mem_which}16 tme_m68k_ireg_uint16(TME_M68K_IREG_MEM${cap_mem_which}16)"
110: echo "#define TME_M68K_IREG_MEM${cap_mem_which}8 (${ireg32_next} << 2)"
111: echo "#define tme_m68k_ireg_mem${mem_which}8 tme_m68k_ireg_uint8(TME_M68K_IREG_MEM${cap_mem_which}8)"
112: ireg32_next=`expr ${ireg32_next} + 1`
113: done
114:
115: # the control registers:
1.1.1.2 ! root 116: for reg in usp isp msp sfc dfc vbr cacr caar; do
1.1 root 117: capreg=`echo $reg | tr a-z A-Z`
118: echo "#define TME_M68K_IREG_${capreg} (${ireg32_next})"
119: echo "#define tme_m68k_ireg_${reg} tme_m68k_ireg_uint32(TME_M68K_IREG_${capreg})"
120: ireg32_next=`expr ${ireg32_next} + 1`
121: done
122:
1.1.1.2 ! root 123: # this is the count of variable 32-bit registers:
1.1 root 124: echo "#define TME_M68K_IREG32_COUNT (${ireg32_next})"
1.1.1.2 ! root 125:
! 126: # the immediate register. there are actually three 32-bit
! 127: # registers in a row, to allow the fpgen specop to fetch up to a
! 128: # 96-bit immediate:
! 129: echo "#define TME_M68K_IREG_IMM32 (${ireg32_next})"
! 130: echo "#define tme_m68k_ireg_imm32 tme_m68k_ireg_uint32(TME_M68K_IREG_IMM32)"
! 131: ireg32_next=`expr ${ireg32_next} + 1`
! 132:
! 133: # the effective address register:
! 134: echo "#define TME_M68K_IREG_EA (${ireg32_next})"
! 135: echo "#define tme_m68k_ireg_ea tme_m68k_ireg_uint32(TME_M68K_IREG_EA)"
! 136: ireg32_next=`expr ${ireg32_next} + 1`
! 137:
! 138: # the constant registers:
! 139: for reg in zero one two three four five six seven eight; do
! 140: capreg=`echo $reg | tr a-z A-Z`
! 141: echo "#define TME_M68K_IREG_${capreg} (${ireg32_next})"
! 142: ireg32_next=`expr ${ireg32_next} + 1`
! 143: done
1.1 root 144: fi
145:
146: # emit the flags->conditions mapping. note that the nesting of the
147: # flag variables is deliberate, to make this array indexable with the
148: # condition code register:
149: if $header; then :; else
150: echo ""
151: echo "/* the flags->conditions mapping: */"
152: echo "const tme_uint16_t _tme_m68k_conditions[32] = {"
153: for xflag in 0 1; do
154: for nflag in 0 1; do
155: for zflag in 0 1; do
156: for vflag in 0 1; do
157: for cflag in 0 1; do
158:
159: # the True condition:
160: echo -n "TME_BIT(TME_M68K_C_T)"
161:
162: # the High condition:
163: if test $cflag != 1 && test $zflag != 1; then
164: echo -n " | TME_BIT(TME_M68K_C_HI)"
165: fi
166:
167: # the Low or Same condition:
168: if test $cflag = 1 || test $zflag = 1; then
169: echo -n " | TME_BIT(TME_M68K_C_LS)"
170: fi
171:
172: # the Carry Clear and Carry Set conditions:
173: if test $cflag != 1; then
174: echo -n " | TME_BIT(TME_M68K_C_CC)"
175: else
176: echo -n " | TME_BIT(TME_M68K_C_CS)"
177: fi
178:
179: # the Not Equal and Equal conditions:
180: if test $zflag != 1; then
181: echo -n " | TME_BIT(TME_M68K_C_NE)"
182: else
183: echo -n " | TME_BIT(TME_M68K_C_EQ)"
184: fi
185:
186: # the Overflow Clear and Overflow Set conditions:
187: if test $vflag != 1; then
188: echo -n " | TME_BIT(TME_M68K_C_VC)"
189: else
190: echo -n " | TME_BIT(TME_M68K_C_VS)"
191: fi
192:
193: # the Plus and Minus conditions:
194: if test $nflag != 1; then
195: echo -n " | TME_BIT(TME_M68K_C_PL)"
196: else
197: echo -n " | TME_BIT(TME_M68K_C_MI)"
198: fi
199:
200: # the Greater or Equal condition:
201: if (test $nflag = 1 && test $vflag = 1) || \
202: (test $nflag != 1 && test $vflag != 1); then
203: echo -n " | TME_BIT(TME_M68K_C_GE)"
204: fi
205:
206: # the Less Than condition:
207: if (test $nflag = 1 && test $vflag != 1) || \
208: (test $nflag != 1 && test $vflag = 1); then
209: echo -n " | TME_BIT(TME_M68K_C_LT)"
210: fi
211:
212: # the Greater Than condition:
213: if (test $nflag = 1 && test $vflag = 1 && test $zflag != 1) || \
214: (test $nflag != 1 && test $vflag != 1 && test $zflag != 1); then
215: echo -n " | TME_BIT(TME_M68K_C_GT)"
216: fi
217:
218: # the Less Than or Equal condition:
219: if test $zflag = 1 || \
220: (test $nflag = 1 && test $vflag != 1) || \
221: (test $nflag != 1 && test $vflag = 1); then
222: echo -n " | TME_BIT(TME_M68K_C_LE)"
223: fi
224:
225: echo ","
226: done
227: done
228: done
229: done
230: done
231: echo "};"
232: fi
233:
234: # emit the instruction word fetch macros:
235: if $header; then
236:
237: echo ""
238: echo "#endif /* _IC_M68K_MISC_H */"
239:
240: # permute for the fast vs. slow executors:
241: for executor in fast slow; do
242:
243: echo ""
244: echo -n "#if"
245: if test $executor = slow; then echo -n "n"; fi
246: echo "def _TME_M68K_EXECUTE_FAST"
247: echo ""
248: echo "/* these macros are for the ${executor} executor: */"
249:
250: # permute for any-alignment vs. strict-alignment:
251: for alignment in any strict; do
252:
253: # permute for the two different sizes we need to handle:
254: for size in 16 32; do
255:
256: # permute for big-endian vs. little-endian:
257: for endian in little big; do
258:
259: # permute for signed or unsigned:
260: for capsign in U S; do
261: if test $capsign = U; then sign=u ; un=un ; else sign= ; un= ; fi
262:
263: # the slow executor has only one possible
264: # version of each macro, no matter what the
265: # endianness or alignment or atomic requirements
266: # of the host, since the tme_m68k_fetch${size}
267: # functions take care of all of that:
268: if test $executor = slow; then
269: if test $endian = big && test $alignment = any; then
270: echo ""
271: echo "/* on all hosts, this fetches a ${size}-bit ${un}signed value for the slow executor: */"
272: echo "#undef _TME_M68K_EXECUTE_FETCH_${capsign}${size}"
273: echo "#define _TME_M68K_EXECUTE_FETCH_${capsign}${size}(v) \\"
1.1.1.2 ! root 274: echo " /* we update the instruction buffer fetch total and sizes values \\"
! 275: echo " before we do the actual fetch, because we may transfer a few \\"
! 276: echo " bytes and then fault. without this, those few bytes wouldn't get \\"
! 277: echo " saved in the exception stack frame by tme_m68k_insn_buffer_xfer(), \\"
! 278: echo " because it wouldn't know about the fetch. later, when the \\"
! 279: echo " instruction would be resumed, tme_m68k_fetch${size}() won't refetch \\"
! 280: echo " them, because it knows they've already been fetched and thinks \\"
! 281: echo " they're still in the instruction buffer: */ \\"
! 282: echo " ic->_tme_m68k_insn_buffer_fetch_total += sizeof(tme_${sign}int${size}_t); \\"
1.1 root 283: if test ${size} = 16; then
1.1.1.2 ! root 284: echo " ic->_tme_m68k_insn_buffer_fetch_sizes <<= 1; \\"
1.1 root 285: else
1.1.1.2 ! root 286: echo " ic->_tme_m68k_insn_buffer_fetch_sizes = (ic->_tme_m68k_insn_buffer_fetch_sizes << 1) | 1; \\"
1.1 root 287: fi
1.1.1.2 ! root 288: echo " (v) = (tme_${sign}int${size}_t) tme_m68k_fetch${size}(ic, linear_pc); \\"
1.1 root 289: echo " linear_pc += sizeof(tme_${sign}int${size}_t)"
290: fi
291: continue
292: fi
293:
294: # assume we'll be universal:
295: macro_comment="ll hosts"
296: macro_test=
297:
298: # if this is a 16-bit fetch:
299: if test $size = 16; then
300:
301: # we don't need a strict alignment version, since
302: # we're guaranteed to be reading from emulator
303: # addresses that are 16-bit aligned - for the fast
304: # executor, tme_m68k_go_slow guarantees that
305: # emulator_load is 16-bit aligned:
306: if test $alignment = strict; then continue; fi
307:
308: # we also don't need a little-endian version, since
309: # the fast macros we emit will always use tme_betoh_u16:
310: if test $endian = little; then continue; fi
311:
312: # if this is a 32-bit fetch:
313: else
314:
315: # while the emulator address we'll be reading
316: # from is 16-bit aligned as explained above,
317: # we still need a strict-alignment version of
318: # the 32-bit fetcher on hosts that require 32-bit
319: # values to be more aligned than 16-bit values.
320: #
321: # on a host that does not have this further
322: # requirement, we also don't need a little-endian
323: # version, since the fast macros we emit will always
324: # use tme_betoh_u32:
325: macro_comment=" host with ${alignment} alignment"
326: if test $alignment = strict; then
327: macro_comment=" ${endian}-endian${macro_comment}"
328: if test ${endian} = little; then macro_test="!"; fi
329: macro_test="(ALIGNOF_INT${size}_T > ALIGNOF_INT16_T) && ${macro_test}defined(WORDS_BIGENDIAN)"
330: else
331: macro_test="ALIGNOF_INT${size}_T <= ALIGNOF_INT16_T"
332: if test ${endian} = little; then continue; fi
333: fi
334: fi
335:
336: # open the macro:
337: echo ""
338: echo "/* on a${macro_comment}, "
339: echo " this loads a ${size}-bit ${un}signed value for the ${executor} instruction executor: */"
340: if test "x${macro_test}" != x; then echo "#if ${macro_test}"; fi
341: echo "#undef _TME_M68K_EXECUTE_FETCH_${capsign}${size}"
342: echo "#define _TME_M68K_EXECUTE_FETCH_${capsign}${size}(v) \\"
343:
344: # assume we'll be converting:
345: conv="tme_betoh_u${size}"
346:
347: # prepare the buffer to read out of:
348: if test ${executor} = fast; then
349:
350: # if we're doing a 32-bit read and the
351: # emulator address is not 32-bit aligned,
352: # on a strict-alignment host we will have
353: # to do a sequence of two 16-bit memory
354: # reads:
355: buffer="emulator_load"
356: misaligned="((unsigned long) emulator_load) & (sizeof(tme_uint32_t) - 1)"
357: update="emulator_load += sizeof(tme_${sign}int${size}_t)"
358:
359: # if we can't do the fast read, bail:
360: echo " if ((emulator_load + (sizeof(tme_uint${size}_t) - 1)) > emulator_load_last) \\"
361: echo " goto _tme_m68k_fast_fetch_failed; \\"
362: fi
363:
364: single="(v) = (tme_${sign}int${size}_t) ${conv}(*((tme_uint${size}_t *) ${buffer}));"
365:
366: # if this is a 16-bit read, the host can always
367: # do a simple assignment.
368: #
369: # we need the rdlock if we're on an architecture
370: # where an aligned access may not be atomic:
371: if test $size = 16; then
372: echo " tme_memory_aligned_rdlock(tlb->tme_m68k_tlb_bus_rwlock); \\"
373: echo " ${single} \\"
374: echo " tme_memory_aligned_unlock(tlb->tme_m68k_tlb_bus_rwlock); \\"
375:
376: # if this is a 32-bit read on an any-alignment host,
377: # do a simple assignment.
378: #
379: # we need the rdlock if this is an aligned access and
380: # we're on an architecture where an aligned access may
381: # not be atomic, or if this is an unaligned access and
382: # we're on an architecture where an unaligned access
383: # may not be atomic:
384: elif test $alignment = any; then
385: echo " if (${misaligned}) { \\"
386: echo " tme_memory_unaligned_rdlock(tlb->tme_m68k_tlb_bus_rwlock); \\"
387: echo " ${single} \\"
388: echo " tme_memory_unaligned_unlock(tlb->tme_m68k_tlb_bus_rwlock); \\"
389: echo " } \\"
390: echo " else { \\"
391: echo " tme_memory_aligned_rdlock(tlb->tme_m68k_tlb_bus_rwlock); \\"
392: echo " ${single} \\"
393: echo " tme_memory_aligned_unlock(tlb->tme_m68k_tlb_bus_rwlock); \\"
394: echo " } \\"
395:
396: # otherwise, this is a 32-bit read on a strict-alignment
397: # host.
398: #
399: # if doing a sequence access is not costlier than deciding
400: # whether to do a sequence or aligned access and then doing
401: # the chosen access, or if the buffer is misaligned,
402: # acquire the rdlock for a sequence and do the sequence
403: # of reads, else acquire the rdlock for an aligned access
404: # and do the single read:
405: else
406: echo " if (TME_SEQUENCE_ACCESS_NOT_COSTLIER || ${misaligned}) { \\";
407: if test $endian = little; then
408: word_lo=0 ; word_hi=1 ;
409: else
410: word_lo=1 ; word_hi=0 ; conv=
411: fi
412: echo " tme_memory_sequence_rdlock(tlb->tme_m68k_bus_tlb_rwlock); \\"
413: echo " (v) = (tme_${sign}int${size}_t) \\"
414: echo " ${conv}((((tme_uint32_t) ((tme_uint16_t *) ${buffer})[${word_hi}]) << 16) | \\"
415: echo " ((tme_uint32_t) ((tme_uint16_t *) ${buffer})[${word_lo}])); \\"
416: echo " tme_memory_sequence_unlock(tlb->tme_m68k_bus_tlb_rwlock); \\"
417: echo " } else { \\"
418: echo " tme_memory_aligned_rdlock(tlb->tme_m68k_tlb_bus_rwlock); \\"
419: echo " ${single} \\"
420: echo " tme_memory_aligned_unlock(tlb->tme_m68k_tlb_bus_rwlock); \\"
421: echo " } \\"
422: fi
423:
424: # remember if we did a 16-bit or 32-bit fetch, and update:
425: if test ${size} = 16; then
426: echo " insn_fetch_sizes <<= 1; \\"
427: else
428: echo " insn_fetch_sizes = (insn_fetch_sizes << 1) | 1; \\"
429: fi
430: echo " ${update}"
431:
432: # close the conditional:
433: if test "x${macro_test}" != x; then echo "#endif /* ${macro_test} */"; fi
434: done
435: done
436: done
437: done
438:
439: echo ""
440: echo -n "#endif /* "
441: if test $executor = slow; then echo -n "!"; fi
442: echo "_TME_M68K_EXECUTE_FAST */"
443: done
444: fi
445:
446: # done:
447: exit 0
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.