|
|
1.1 root 1: #! /bin/sh
2:
3: # $Id: sparc-vis-auto.sh,v 1.4 2010/02/20 22:01:40 fredette Exp $
4:
5: # ic/sparc-vis-auto.sh - automatically generates C code for many SPARC VIS
6: # emulation instructions:
7:
8: #
9: # Copyright (c) 2009 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: _TME_RCSID("\$Id: sparc-vis-auto.sh,v 1.4 2010/02/20 22:01:40 fredette Exp $");
52: EOF
53:
54: echo ""
55: echo "/* this handles VIS instructions: */"
56: echo "void"
57: echo "tme_sparc_vis(struct tme_sparc *ic)"
58: echo "{"
59: echo " unsigned int opf;"
60: echo " unsigned int fpreg_rd_number_encoded;"
61: echo " const struct tme_float *fpreg_rs1;"
62: echo " const struct tme_float *fpreg_rs2;"
63: echo " unsigned int fpreg_rd_format;"
64: echo " unsigned int fpreg_rd_number;"
65: echo " struct tme_float fpreg_rd;"
66: echo " tme_uint64_t value_fpreg_rs1;"
67: echo " tme_uint64_t value_fpreg_rs2;"
68: echo " unsigned int compare_result;"
69: echo " unsigned int reg_rd;"
70: echo " unsigned int alignaddr_off;"
71: echo ""
72: echo " TME_SPARC_INSN_FPU;"
73: echo ""
74: echo " /* extract the opf field: */"
75: echo " opf = TME_FIELD_MASK_EXTRACTU(TME_SPARC_INSN, (0x1ff << 5));"
76: echo ""
77: echo " /* extract the encoded rd: */"
78: echo " fpreg_rd_number_encoded = TME_FIELD_MASK_EXTRACTU(TME_SPARC_INSN, TME_SPARC_FORMAT3_MASK_RD);"
79:
80: echo ""
81: echo "#ifdef _TME_SPARC_RECODE_VERIFY"
82: echo " /* clear the rd buffer: */"
83: echo " memset(&fpreg_rd, 0, sizeof(fpreg_rd));"
84: echo "#endif /* _TME_SPARC_RECODE_VERIFY */"
85:
86: echo ""
87: echo " /* dispatch on the opf field: */"
88: echo " switch (opf) {"
89: echo "#define _TME_SPARC_FPU_FORMAT_RS1(format) fpreg_rs1 = tme_sparc_fpu_fpreg_read(ic, TME_SPARC_FORMAT3_MASK_RS1, (format))"
90: echo "#define _TME_SPARC_FPU_FORMAT_RS2(format) fpreg_rs2 = tme_sparc_fpu_fpreg_read(ic, TME_SPARC_FORMAT3_MASK_RS2, (format))"
91: echo "#define _TME_SPARC_FPU_FORMAT_RD(format) do { fpreg_rd_format = (format) | TME_IEEE754_FPREG_FORMAT_BUILTIN; fpreg_rd_number = tme_sparc_fpu_fpreg_decode(ic, fpreg_rd_number_encoded, fpreg_rd_format); } while (/* CONSTCOND */ 0)"
92: echo ""
93:
94: # permute over the opf field:
95: #
96: opf_decimal=-1
97: while test ${opf_decimal} != 511; do
98: opf_decimal=`expr ${opf_decimal} + 1`
99:
100: # make the binary version of the opf field:
101: #
102: bits=9
103: opf=
104: opf_shifted=${opf_decimal}
105: while test ${bits} != 0; do
106: bits=`expr ${bits} - 1`
107: opf_shifted_next=`expr ${opf_shifted} / 2`
108: opf_test=`expr ${opf_shifted_next} \* 2`
109: if test ${opf_test} = ${opf_shifted}; then
110: opf="0${opf}"
111: else
112: opf="1${opf}"
113: fi
114: opf_shifted=${opf_shifted_next}
115: done
116:
117: # dispatch on opf:
118: #
119: default=false
120: case "${opf}" in
121:
122: 00010???0)
123: compareopf=`echo ${opf} | sed -e 's/^00010\(.*\)0$/\1/'`
124: case "${compareopf}" in
125: ?1?) compareopsize=32 ;;
126: ?0?) compareopsize=16 ;;
127: esac
128: case "${compareopf}" in
129: 1?0) compareopname="GT" ; compareop=">" ;;
130: 0?0) compareopname="LE" ; compareop="<=" ;;
131: 0?1) compareopname="NE" ; compareop="!=" ;;
132: 1?1) compareopname="EQ" ; compareop="==" ;;
133: esac
134: echo " case ${opf_decimal}: /* ${opf} FCMP${compareopname}${compareopsize}: */"
135: echo " _TME_SPARC_FPU_FORMAT_RS1(TME_IEEE754_FPREG_FORMAT_DOUBLE);"
136: echo " _TME_SPARC_FPU_FORMAT_RS2(TME_IEEE754_FPREG_FORMAT_DOUBLE);"
137: echo " value_fpreg_rs1 = fpreg_rs1->tme_float_value_ieee754_double.tme_value64_uint;"
138: echo " value_fpreg_rs2 = fpreg_rs2->tme_float_value_ieee754_double.tme_value64_uint;"
139: echo " compare_result = 0;"
140: compare_off=0
141: while test ${compare_off} != 64; do
142: echo " if (((tme_uint${compareopsize}_t) value_fpreg_rs1)"
143: echo " ${compareop} (tme_uint${compareopsize}_t) value_fpreg_rs2) {"
144: echo " compare_result += (1 << (${compare_off} / ${compareopsize}));"
145: echo " }"
146: echo " value_fpreg_rs1 >>= ${compareopsize};"
147: echo " value_fpreg_rs2 >>= ${compareopsize};"
148: compare_off=`expr ${compare_off} + ${compareopsize}`
149: done
150: echo " reg_rd = TME_FIELD_MASK_EXTRACTU(TME_SPARC_INSN, TME_SPARC_FORMAT3_MASK_RD);"
151: echo " TME_SPARC_REG_INDEX(ic, reg_rd);"
152: echo " ic->tme_sparc_ireg_uint64(reg_rd) = compare_result;"
153: echo " fpreg_rd_format = TME_IEEE754_FPREG_FORMAT_NULL;"
154: echo " fpreg_rd_number = 0;"
155: ;;
156:
157: 001001000)
158: echo " case ${opf_decimal}: /* ${opf} FALIGNDATA: */"
159: echo " _TME_SPARC_FPU_FORMAT_RS1(TME_IEEE754_FPREG_FORMAT_DOUBLE);"
160: echo " _TME_SPARC_FPU_FORMAT_RS2(TME_IEEE754_FPREG_FORMAT_DOUBLE);"
161: echo " _TME_SPARC_FPU_FORMAT_RD(TME_IEEE754_FPREG_FORMAT_DOUBLE);"
162: echo " fpreg_rd.tme_float_format = TME_FLOAT_FORMAT_IEEE754_DOUBLE;"
163: echo " fpreg_rd.tme_float_value_ieee754_double = fpreg_rs1->tme_float_value_ieee754_double;"
164: echo " alignaddr_off = TME_FIELD_MASK_EXTRACTU(ic->tme_sparc_vis_gsr, TME_SPARC_VIS_GSR_ALIGNADDR_OFF);"
165: echo " if (alignaddr_off) {"
166: echo " fpreg_rd.tme_float_value_ieee754_double.tme_value64_uint"
167: echo " = ((fpreg_rd.tme_float_value_ieee754_double.tme_value64_uint"
168: echo " << (8 * alignaddr_off))"
169: echo " + (fpreg_rs2->tme_float_value_ieee754_double.tme_value64_uint"
170: echo " >> (64 - (8 * alignaddr_off))));"
171: echo " }"
172: ;;
173:
174: 0011?????)
175: logicalopf=`echo ${opf} | sed -e 's/^0011\(.*\)[01]$/\1/'`
176: logicalopname=
177: logicalop=
178: case "${logicalopf}" in
179: 0000)
180: logicalopname="ZERO"
181: logicalop="0"
182: ;;
183: 1111)
184: logicalopname="ONE"
185: logicalop="(0 - (type) 1)"
186: ;;
187: 1010)
188: logicalopname="SRC1"
189: logicalop="src1"
190: ;;
191: 1100)
192: logicalopname="SRC2"
193: logicalop="src2"
194: ;;
195: 0101)
196: logicalopname="NOT1"
197: logicalop="~src1"
198: ;;
199: 0011)
200: logicalopname="NOT2"
201: logicalop="~src2"
202: ;;
203: 1110)
204: logicalopname="OR"
205: logicalop="(src1 | src2)"
206: ;;
207: 0001)
208: logicalopname="NOR"
209: logicalop="~(src1 | src2)"
210: ;;
211: 1000)
212: logicalopname="AND"
213: logicalop="(src1 & src2)"
214: ;;
215: 0111)
216: logicalopname="NAND"
217: logicalop="~(src1 & src2)"
218: ;;
219: 0110)
220: logicalopname="XOR"
221: logicalop="(src1 ^ src2)"
222: ;;
223: 1001)
224: logicalopname="XNOR"
225: logicalop="~(src1 ^ src2)"
226: ;;
227: 1101)
228: logicalopname="ORNOT1"
229: logicalop="(src2 | ~src1)"
230: ;;
231: 1011)
232: logicalopname="ORNOT2"
233: logicalop="(src1 | ~src2)"
234: ;;
235: 0100)
236: logicalopname="ANDNOT1"
237: logicalop="(src2 & ~src1)"
238: ;;
239: 0010)
240: logicalopname="ANDNOT2"
241: logicalop="(src1 & ~src2)"
242: ;;
243: *) echo "$0 internal error: unknown VIS logical op ${logicalopf}" 1>&2 ; exit 1 ;;
244: esac
245:
246: case "${opf}" in
247: *1) capprecision="SINGLE"; size="32" ; value="single" ; logicalopname="${logicalopname}S" ;;
248: *0) capprecision="DOUBLE"; size="64" ; value="double.tme_value64_uint" ;;
249: esac
250:
251: echo " case ${opf_decimal}: /* ${opf} (${logicalopf}) F${logicalopname}: */"
252:
253: logicalop=`echo "${logicalop}" | sed -e "s/type/tme_uint${size}_t/g"`
254:
255: logicalop_next=`echo "${logicalop}" | sed -e "s/src1/fpreg_rs1->tme_float_value_ieee754_${value}/"`
256: if test "${logicalop_next}" != "${logicalop}"; then
257: echo " _TME_SPARC_FPU_FORMAT_RS1(TME_IEEE754_FPREG_FORMAT_${capprecision});"
258: logicalop="${logicalop_next}"
259: fi
260:
261: logicalop_next=`echo "${logicalop}" | sed -e "s/src2/fpreg_rs2->tme_float_value_ieee754_${value}/"`
262: if test "${logicalop_next}" != "${logicalop}"; then
263: echo " _TME_SPARC_FPU_FORMAT_RS2(TME_IEEE754_FPREG_FORMAT_${capprecision});"
264: logicalop="${logicalop_next}"
265: fi
266:
267: echo " _TME_SPARC_FPU_FORMAT_RD(TME_IEEE754_FPREG_FORMAT_${capprecision});"
268: echo " _TME_SPARC_FPU_BEGIN;"
269: echo " fpreg_rd.tme_float_format = TME_FLOAT_FORMAT_IEEE754_${capprecision};"
270: echo " fpreg_rd.tme_float_value_ieee754_${value} = ${logicalop};"
271: ;;
272:
273: *) default=true ;;
274: esac
275: if $default; then :; else echo " break;"; echo ""; fi
276: done
277: echo " default:"
278: echo " _TME_SPARC_FPU_UNIMPL;"
279: echo " fpreg_rd_format = TME_IEEE754_FPREG_FORMAT_NULL;"
280: echo " fpreg_rd_number = 0;"
281: echo " break;"
282: echo ""
283: echo "#undef _TME_SPARC_FPU_FORMAT_RS1"
284: echo "#undef _TME_SPARC_FPU_FORMAT_RS2"
285: echo "#undef _TME_SPARC_FPU_FORMAT_RD"
286: echo " }"
287:
288: echo ""
289: echo " /* store any destination: */"
290: echo " if (fpreg_rd_format != TME_IEEE754_FPREG_FORMAT_NULL) {"
291: echo " tme_sparc_fpu_fpreg_format(ic, fpreg_rd_number, fpreg_rd_format);"
292: echo " ic->tme_sparc_fpu_fpregs[fpreg_rd_number] = fpreg_rd;"
293: echo " TME_SPARC_FPU_DIRTY(ic, fpreg_rd_number);"
294: echo " }"
295:
296: echo ""
297: echo "}"
298:
299: # permute over architecture:
300: #
301: for arch in 64; do
302:
303: # permute over partial store word size:
304: #
305: for size in 64; do
306:
307: case "${arch}:${size}" in
308: *:64) insn="d" ; format="DOUBLE" ; value="double.tme_value64_uint" ;;
309: *) echo "$0 internal error: unknown architecture PST word size ${arch}:${size}" 1>&2 ; exit 1 ;;
310: esac
311:
312: cat <<EOF
313:
314: /* the sparc${arch} cycle handler for st${insn}fa ASI_PST*: */
315: static void
316: _tme_sparc${arch}_vis_ls_cycle_pst${insn}(struct tme_sparc *ic, struct tme_sparc_ls *ls)
317: {
318: unsigned int reg_rs2;
319: tme_uint32_t mask_raw;
320: unsigned int asi;
321: tme_uint32_t mask_0_31;
322: tme_uint32_t mask_32_63;
323: tme_uint${size}_t mask;
324: const struct tme_float *fpreg_rd;
325: tme_uint${size}_t value_written;
326: const struct tme_sparc_tlb *tlb;
327: tme_uint${arch}_t address;
328: tme_shared tme_uint8_t *emulator_off;
329: tme_shared tme_uint${size}_t *memory;
330: tme_uint${size}_t value_read;
331: tme_uint${size}_t value_cmp;
332:
333: /* decode rs2: */
334: reg_rs2 = TME_FIELD_MASK_EXTRACTU(ic->_tme_sparc_insn, TME_SPARC_FORMAT3_MASK_RS2);
335: TME_SPARC_REG_INDEX(ic, reg_rs2);
336:
337: /* get the raw mask: */
338: mask_raw = ic->tme_sparc_ireg_uint${arch}(reg_rs2);
339:
340: /* get the ASI: */
341: asi
342: = (TME_SPARC_ASI_MASK_WHICH(ls->tme_sparc_ls_asi_mask)
343: & ~(TME_SPARC${arch}_ASI_FLAG_SECONDARY
344: | TME_SPARC${arch}_ASI_FLAG_LITTLE));
345:
346: /* assume that this is ASI_PST32*: */
347: mask_0_31 = 0 - (mask_raw & TME_BIT(0));
348: mask_raw >>= 1;
349: mask_32_63 = 0 - (mask_raw & TME_BIT(0));
350: mask_raw >>= 1;
351:
352: /* if this is ASI_PST16*: */
353: if (asi == TME_SPARC_VIS_ASI_PST16) {
354:
355: /* convert the ASI_PST32* mask into bits 0..31 of the ASI_PST16* mask: */
356: mask_0_31
357: = ((mask_0_31 & (((tme_uint32_t) 0xffff) << 0))
358: + (mask_32_63 & (((tme_uint32_t) 0xffff) << 16)));
359:
360: /* make bits 32..63 of the ASI_PST16* mask: */
361: mask_32_63
362: = (((0 - (mask_raw & TME_BIT(0))) & (((tme_uint32_t) 0xffff) << 0))
363: + ((0 - (mask_raw & TME_BIT(1))) & (((tme_uint32_t) 0xffff) << 16)));
364: }
365:
366: /* otherwise, if this is ASI_PST8*: */
367: else if (asi == TME_SPARC_VIS_ASI_PST8) {
368:
369: /* convert the ASI_PST32* mask into bits 0..15 of the ASI_PST8*
370: mask, and make bits 16..31: */
371: mask_0_31
372: = ((mask_0_31 & (((tme_uint32_t) 0xff) << 0))
373: + (mask_32_63 & (((tme_uint32_t) 0xff) << 8))
374: + ((0 - (mask_raw & TME_BIT(0))) & (((tme_uint32_t) 0xff) << 16))
375: + ((0 - (mask_raw & TME_BIT(1))) & (((tme_uint32_t) 0xff) << 24)));
376:
377: /* make bits 32..63 of the ASI_PST8* mask: */
378: mask_raw >>= 2;
379: mask_32_63
380: = (((0 - (mask_raw & TME_BIT(0))) & (((tme_uint32_t) 0xff) << 0))
381: + ((0 - (mask_raw & TME_BIT(1))) & (((tme_uint32_t) 0xff) << 8))
382: + ((0 - (mask_raw & TME_BIT(2))) & (((tme_uint32_t) 0xff) << 16))
383: + ((0 - (mask_raw & TME_BIT(3))) & (((tme_uint32_t) 0xff) << 24)));
384: }
385:
386: /* make the full mask: */
387: mask = 0;
388: mask |= (((tme_uint64_t) mask_32_63) << 32);
389: mask |= mask_0_31;
390:
391: /* get the value to store from the double-precision fp register: */
392: fpreg_rd = tme_sparc_fpu_fpreg_read(ic, TME_SPARC_FORMAT3_MASK_RD, TME_IEEE754_FPREG_FORMAT_${format});
393: value_written = fpreg_rd->tme_float_value_ieee754_${value};
394:
395: /* get the TLB entry: */
396: tlb = ls->tme_sparc_ls_tlb;
397:
398: /* swap the mask and the value to store: */
399: if (ls->tme_sparc_ls_lsinfo & TME_SPARC_LSINFO_ENDIAN_LITTLE) {
400: value_written = tme_htole_u${size}(value_written);
401: mask = tme_htole_u${size}(mask);
402: }
403: else {
404: value_written = tme_htobe_u${size}(value_written);
405: mask = tme_htobe_u${size}(mask);
406: }
407:
408: /* get the current address: */
409: address = ls->tme_sparc_ls_address${arch};
410:
411: /* if this is the first transfer, and the TLB entry allows fast
412: transfer of all of the addresses: */
413: emulator_off = tlb->tme_sparc_tlb_emulator_off_write;
414: if (__tme_predict_true(ls->tme_sparc_ls_state == 0
415: && ((tme_bus_addr${arch}_t) tlb->tme_sparc_tlb_addr_last) >= (address + sizeof(tme_uint${size}_t) - 1)
416: && emulator_off != TME_EMULATOR_OFF_UNDEF
417: && emulator_off == tlb->tme_sparc_tlb_emulator_off_read)) {
418:
419: /* make the pointer to the memory to store: */
420: memory = (tme_shared tme_uint${size}_t *) (emulator_off + address);
421:
422: /* loop until we can do the atomic partial store: */
423: value_read = tme_memory_bus_read${size}(memory,
424: tlb->tme_sparc_tlb_bus_rwlock,
425: sizeof(tme_uint${size}_t),
426: sizeof(tme_uint${arch}_t));
427: do {
428:
429: /* make the value to write: */
430: value_written
431: = ((value_written & mask)
432: + (value_read & ~mask));
433:
434: /* try an atomic compare-and-exchange: */
435: value_cmp = value_read;
436: value_read
437: = tme_memory_atomic_cx${size}(memory,
438: value_cmp,
439: value_written,
440: tlb->tme_sparc_tlb_bus_rwlock,
441: sizeof(tme_uint${size}_t));
442:
443: /* loop while the atomic compare-and-exchange failed: */
444: } while (value_read != value_cmp);
445:
446: /* we finished this transfer: */
447: ls->tme_sparc_ls_size = 0;
448: return;
449: }
450:
451: /* otherwise, we have to do a slow transfer: */
452: ls->tme_sparc_ls_buffer_offset = 0;
453: /* XXX WRITEME: */
454: abort();
455: }
456: EOF
457: done
458:
459: cat <<EOF
460:
461: /* the sparc${arch} ASI handler for ASI_PST*: */
462: void
463: tme_sparc${arch}_vis_ls_asi_pst(struct tme_sparc *ic, struct tme_sparc_ls *ls)
464: {
465: tme_uint32_t insn;
466: unsigned int reg_rs1;
467: tme_uint${arch}_t address_first;
468:
469: /* NB: this checks for various traps in priority order: */
470:
471: /* the only faults that may have been set so far are an alignment
472: fault, which is probably wrong because the address checked was
473: (rs1 + rs2), instead of just rs1, and any ldd/std rd-odd fault.
474: we will override both faults: */
475: assert ((ls->tme_sparc_ls_faults
476: | TME_SPARC_LS_FAULT_ADDRESS_NOT_ALIGNED
477: | TME_SPARC_LS_FAULT_LDD_STD_RD_ODD)
478: == (TME_SPARC_LS_FAULT_ADDRESS_NOT_ALIGNED
479: | TME_SPARC_LS_FAULT_LDD_STD_RD_ODD));
480:
481: /* we need to do the complete transfer: */
482: ls->tme_sparc_ls_faults = TME_SPARC_LS_FAULT_NONE;
483: ls->tme_sparc_ls_lsinfo |= TME_SPARC_LSINFO_SLOW_CYCLES;
484: ls->tme_sparc_ls_state = 0;
485:
486: /* get the instruction: */
487: insn = ic->_tme_sparc_insn;
488:
489: /* NB: the exception for a non-stdfa opcode appears to be explicitly
490: prioritized above an illegal_instruction trap for an immediate
491: instruction: */
492:
493: /* if this is an stdfa: */
494: if (__tme_predict_true((insn
495: & (0x3f << 19))
496: == (0x37 << 19))) {
497:
498: /* set the slow cycle function: */
499: assert (ls->tme_sparc_ls_size == sizeof(tme_uint64_t));
500: ls->tme_sparc_ls_cycle = _tme_sparc${arch}_vis_ls_cycle_pstd;
501: }
502:
503: /* any other instruction is illegal: */
504: else {
505: ls->tme_sparc_ls_faults = ic->tme_sparc_vis_ls_fault_illegal;
506: return;
507: }
508:
509: /* immediate instruction forms are illegal: */
510: if (__tme_predict_false(insn & TME_BIT(13))) {
511: tme_sparc_tlb_unbusy(ls->tme_sparc_ls_tlb);
512: TME_SPARC_INSN_ILL(ic);
513: }
514:
515: /* the stdfa instruction handler must have already checked that the
516: FPU is enabled: */
517: assert (!TME_SPARC_FPU_IS_DISABLED(ic));
518:
519: /* decode rs1: */
520: reg_rs1 = TME_FIELD_MASK_EXTRACTU(insn, TME_SPARC_FORMAT3_MASK_RS1);
521: TME_SPARC_REG_INDEX(ic, reg_rs1);
522:
523: /* get the address: */
524: address_first = ic->tme_sparc_ireg_uint${arch}(reg_rs1);
525: ls->tme_sparc_ls_address${arch} = address_first;
526:
527: /* the address must be aligned: */
528: if (__tme_predict_false((((tme_uint32_t) address_first)
529: & (ls->tme_sparc_ls_size - 1)) != 0)) {
530: ls->tme_sparc_ls_faults = TME_SPARC_LS_FAULT_ADDRESS_NOT_ALIGNED;
531: return;
532: }
533:
534: /* the stdfa instruction handler must have already checked that the
535: FPU mode is not exception_pending: */
536: assert (ic->tme_sparc_fpu_mode != TME_SPARC_FPU_MODE_EXCEPTION_PENDING);
537: }
538:
539: /* the sparc${arch} cycle handler for lddfa and stdfa ASI_FL*: */
540: static void
541: _tme_sparc${arch}_vis_ls_cycle_fld(struct tme_sparc *ic, struct tme_sparc_ls *ls)
542: {
543: tme_uint64_t value;
544: unsigned int buffer_offset;
545:
546: /* if this is an stdfa: */
547: if (ic->_tme_sparc_insn & (4 << 19)) {
548:
549: /* the actual store cycles will be done directly: */
550: ls->tme_sparc_ls_cycle = tme_sparc${arch}_store;
551:
552: /* initialize the memory buffer with the value to store: */
553: value = *ls->tme_sparc_ls_rd${arch};
554: }
555:
556: /* otherwise, this is an lddfa: */
557: else {
558:
559: /* the actual load cycles will be done directly: */
560: ls->tme_sparc_ls_cycle = tme_sparc${arch}_load;
561:
562: /* initialize the memory buffer with zero: */
563: value = 0;
564: }
565:
566: /* initialize the memory buffer: */
567: if (ls->tme_sparc_ls_lsinfo & TME_SPARC_LSINFO_ENDIAN_LITTLE) {
568: value = tme_htole_u64(value);
569: buffer_offset = 0;
570: }
571: else {
572: value = tme_htobe_u64(value);
573: buffer_offset = sizeof(value) - ls->tme_sparc_ls_size;
574: }
575: ic->tme_sparc_memory_buffer.tme_sparc_memory_buffer64s[0] = value;
576: ls->tme_sparc_ls_buffer_offset = buffer_offset;
577:
578: /* do the (first) actual cycle: */
579: (*ls->tme_sparc_ls_cycle)(ic, ls);
580: }
581:
582: /* the sparc${arch} ASI handler for ASI_FL*: */
583: void
584: tme_sparc${arch}_vis_ls_asi_fl(struct tme_sparc *ic, struct tme_sparc_ls *ls)
585: {
586: tme_uint32_t insn;
587:
588: /* NB: this checks for various traps in priority order: */
589:
590: /* the only faults that may have been set so far are an alignment
591: fault, which is probably wrong because the size used for the
592: alignment check was wrong, and any ldd/std rd-odd fault. we will
593: override both faults: */
594: assert ((ls->tme_sparc_ls_faults
595: | TME_SPARC_LS_FAULT_ADDRESS_NOT_ALIGNED
596: | TME_SPARC_LS_FAULT_LDD_STD_RD_ODD)
597: == (TME_SPARC_LS_FAULT_ADDRESS_NOT_ALIGNED
598: | TME_SPARC_LS_FAULT_LDD_STD_RD_ODD));
599:
600: /* get the instruction: */
601: insn = ic->_tme_sparc_insn;
602:
603: /* we need to do the complete transfer: */
604: ls->tme_sparc_ls_faults = TME_SPARC_LS_FAULT_NONE;
605: ls->tme_sparc_ls_lsinfo |= TME_SPARC_LSINFO_SLOW_CYCLES;
606: ls->tme_sparc_ls_state = 0;
607:
608: /* set the cycle size: */
609: #if (TME_SPARC_VIS_ASI_FL16 & (TME_SPARC_VIS_ASI_FL16 - 1)) != TME_SPARC_VIS_ASI_FL8
610: #error "TME_SPARC_VIS_ASI_FL values changed"
611: #endif
612: ls->tme_sparc_ls_size
613: = (sizeof(tme_uint8_t)
614: + ((TME_SPARC_ASI_MASK_WHICH(ls->tme_sparc_ls_asi_mask)
615: / (TME_SPARC_VIS_ASI_FL16
616: ^ TME_SPARC_VIS_ASI_FL8))
617: & 1));
618:
619: /* if this is an stdfa or an lddfa: */
620: if (__tme_predict_true((insn
621: & (0x3b << 19))
622: == (0x33 << 19))) {
623:
624: /* set the slow cycle function: */
625: ls->tme_sparc_ls_cycle = _tme_sparc${arch}_vis_ls_cycle_fld;
626:
627: /* the stdfa or lddfa instruction handler must have already
628: checked that the FPU is enabled: */
629: assert (!TME_SPARC_FPU_IS_DISABLED(ic));
630: }
631:
632: /* any other instruction is illegal: */
633: /* XXX FIXME - is this correct? the UltraSPARC User's Manual
634: doesn't document data_access_exception for an illegal opcode: */
635: else {
636: ls->tme_sparc_ls_faults = ic->tme_sparc_vis_ls_fault_illegal;
637: return;
638: }
639:
640: /* the address must be aligned: */
641: if (__tme_predict_false((((tme_uint32_t) ls->tme_sparc_ls_address${arch})
642: & (ls->tme_sparc_ls_size - 1)) != 0)) {
643: ls->tme_sparc_ls_faults = TME_SPARC_LS_FAULT_ADDRESS_NOT_ALIGNED;
644: return;
645: }
646:
647: /* the stdfa or lddfa instruction handler must have already checked
648: that the FPU mode is execute: */
649: assert (ic->tme_sparc_fpu_mode == TME_SPARC_FPU_MODE_EXECUTE);
650: }
651:
652: /* the sparc${arch} VIS alternate ASI misalignment function: */
653: tme_uint32_t
654: tme_sparc${arch}_vis_ls_asi_misaligned(struct tme_sparc *ic,
655: tme_uint32_t misaligned)
656: {
657: tme_uint32_t insn;
658: tme_uint32_t asi;
659: tme_uint32_t asi_base;
660: unsigned int reg_rs1;
661:
662: /* get the instruction: */
663: insn = TME_SPARC_INSN;
664:
665: /* get the ASI, assuming that the i bit is zero: */
666: asi = TME_FIELD_MASK_EXTRACTU(insn, (0xff << 5));
667:
668: /* if the i bit is one, use the ASI register: */
669: if (insn & TME_BIT(13)) {
670: asi = ic->tme_sparc${arch}_ireg_asi;
671: }
672:
673: /* make a base version of the ASI, with the secondary and
674: little-endian flags cleared: */
675: asi_base = (asi & ~(TME_SPARC64_ASI_FLAG_SECONDARY | TME_SPARC64_ASI_FLAG_LITTLE));
676:
677: /* ASI_FL8* requires 8-bit alignment: */
678: if (asi_base == TME_SPARC_VIS_ASI_FL8) {
679: misaligned %= sizeof(tme_uint8_t);
680: }
681:
682: /* ASI_FL16* requires 16-bit alignment: */
683: else if (asi_base == TME_SPARC_VIS_ASI_FL16) {
684: misaligned %= sizeof(tme_uint16_t);
685: }
686:
687: /* if this is an ASI_PST*: */
688: else if (asi_base == TME_SPARC_VIS_ASI_PST8
689: || asi_base == TME_SPARC_VIS_ASI_PST16
690: || asi_base == TME_SPARC_VIS_ASI_PST32) {
691:
692: /* decode rs1: */
693: reg_rs1 = TME_FIELD_MASK_EXTRACTU(insn, TME_SPARC_FORMAT3_MASK_RS1);
694: TME_SPARC_REG_INDEX(ic, reg_rs1);
695:
696: /* if this is not a register mode stdfa: */
697: if (__tme_predict_false((insn
698: & ((0x3f << 19)
699: + TME_BIT(13)))
700: != (0x37 << 19))) {
701:
702: /* start a slow load/store, which will call the ASI handler,
703: which will cause the appropriate fault: */
704: tme_sparc${arch}_ls(ic,
705: ic->tme_sparc_ireg_uint${arch}(reg_rs1),
706: (tme_uint${arch}_t *) NULL, /* _rd */
707: (TME_SPARC_LSINFO_SIZE(1)
708: | TME_SPARC_LSINFO_ASI(asi)
709: | TME_SPARC_LSINFO_A));
710: assert(FALSE);
711: }
712:
713: /* get the least-significant 32 bits of the address: */
714: misaligned = ic->tme_sparc_ireg_uint${arch}(reg_rs1);
715:
716: /* ASI_PST* require 64-bit alignment, which the stdfa instruction
717: handler is already checking: */
718: }
719:
720: /* return a possibly updated misalignment: */
721: return (misaligned);
722: }
723: EOF
724:
725: done
726:
727: # done:
728: #
729: exit 0
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.