From: Michael Meissner Date: Tue, 23 Jul 1996 15:42:42 +0000 (+0000) Subject: New simulator changes from Andrew X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=30c87b55ec44de3a56cecf41fc7c93ed0c4005ca;p=binutils-gdb.git New simulator changes from Andrew --- diff --git a/sim/ppc/.Sanitize b/sim/ppc/.Sanitize index 47ca8819d4c..bf877e97abb 100644 --- a/sim/ppc/.Sanitize +++ b/sim/ppc/.Sanitize @@ -51,6 +51,7 @@ debug.c debug.h device.c device.h +device.maybe device_table.c device_table.h dgen.c @@ -68,9 +69,24 @@ emul_unix.c emul_unix.h events.c events.h +filter.c +filter.h filter_filename.c filter_filename.h +gen-icache.c +gen-icache.h +gen-idecode.c +gen-idecode.h +gen-itable.c +gen-itable.h +gen-model.c +gen-model.h +gen-semantics.c +gen-semantics.h +gen-support.c +gen-support.h hw_com.c +hw_core.c hw_cpu.c hw_cpu.h hw_disk.c @@ -92,10 +108,17 @@ idecode_branch.h idecode_expression.h idecode_fields.h igen.c +igen.h inline.c inline.h interrupts.c interrupts.h +ld-cache.c +ld-cache.h +ld-decode.c +ld-decode.h +ld-insn.c +ld-insn.h lf.c lf.h main.c @@ -112,6 +135,7 @@ ppc-cache-rules ppc-instructions ppc-opcode-complex ppc-opcode-flat +ppc-opcode-jump ppc-opcode-simple ppc-opcode-stupid ppc-opcode-test-1 diff --git a/sim/ppc/ChangeLog b/sim/ppc/ChangeLog index 9481d41ab58..a4aa13e316d 100644 --- a/sim/ppc/ChangeLog +++ b/sim/ppc/ChangeLog @@ -1,3 +1,255 @@ +Sun Jul 21 21:18:05 1996 Andrew Cagney + + * gen-semantics.c: Make the my_index variable a macro MY_INDEX. + + * ppc-instructions: Adjust so that references are to MY_INDEX and + not my_index. + +Sun Jul 21 21:18:05 1996 Andrew Cagney + + * gen-idecode.c: Output the complete run_until_stop function + instead of just the code to handle a single instruction issue. + * : Have the generated idecode.c include inline.c (instead of psim.c). + + * std-config.h: Change psim.c so that it isn't inlined (as this is + no longer needed). + + * psim.c (run_until_stop): Delete the old run_until_stop function + instead calling the idecode_run and idecode_run_until_stop + functions that gen-idecode.c is now creating. + +Sun Jul 21 21:18:05 1996 Andrew Cagney + + * dgen.c: Maintenance - update to use new features found in lf.c. + + * filter_filename.c (filter_filename): Maintenance - make the + string constant. + +Sun Jul 21 21:18:05 1996 Andrew Cagney + + * debug.c (TRACE, ITRACE, DTRACE): Have GCC instead of CPP + eliminate trace statements. + + * debug.c: Change trace format so that it is consistent + (file:line-nr) with CC's error output. + + * gen-itable.c (itable_c_insn): Add the source file name and + source line number to the instruction's informational entry. + + * debug.c (ITRACE): Use the itable (and my_index) to get the + current instructions name and source line number. + + * gen-semantics.c, gen-icache.c: Adjust generated ITRACE calls to + match new interface. + + * emul_bugapi.c (emul_bugapi_instruction_call): Adjust + corresponding call to ITRACE so that it still matches. + + * idecode_expression.h (ALU_END, CR0_COMPARE): Use TRACE instead + of ITRACE. The CPP line directives would have previously set the + line-nr and file name so ITRACE isn't needed. + +Sun Jul 21 21:18:05 1996 Andrew Cagney + + * gen-idecode.c (print_jump_until_stop_body): New function and + idecode generation option. Instead of generating and calling + separate functions containing the semantic and icache code + generate a single monolythic function and use goto's (and GCC's + indirect jump) to move between code blocks. + + * Makefile.in: Add sim_jump flag to those passed to igen. + + * configure.in: New option --enable-sim-jump (default disabled) + + * ppc-instructions: Eliminate any uses of labels and goto's. + These result in duplicate declarations when a single flat function + is being create. + + * ppc-opcode-jump: New file. Set of opcode rules useful when + testing jumping idecodes. + +Sun Jul 21 21:18:05 1996 Andrew Cagney + + * gen-idecode.c: Optionally include the semantic code for an + instruction in the function that is doing the decoding. + + * igen.c: Add option (-C) to generate semantics in the instruction + decode functions. + + * configure.in (--enable-sim-icache): Accept an option list such + as 1024,define. Add a new choice to the list - semantic - which + will cause igen to generate instruction decode functions that + include the corresponding semantic code. + +Sun Jul 21 21:18:05 1996 Andrew Cagney + + * configure.in: New option --enable-sim-line-nr (default enabled). + Enable/disable the inclusion of CPP line directives in the + generated files. Such directives refer back to the source files + used when generating the simulator code. + + * Makefile.in (sim_line_nr): Pass to igen. + +Sun Jul 21 21:18:05 1996 Andrew Cagney + + * igen.c (main): Revamp the options so that more letters are + available. + + * configure.in: Adjust to match igen's revamped options + +Sun Jul 21 21:18:05 1996 Andrew Cagney + + * Makefile.in (pk.h, hw.h): Rewrite depenencies for hw.h (etc) so + that they use the same technique as igen (ie a dummy targets + tmp-pk and tmp-hw are created). + +Mon Jun 24 22:28:00 1996 Andrew Cagney + + * Makefile.in (BUILD_CFLAGS): Include WARNING_CFLAGS. + +Wed Jun 19 21:45:28 1996 Andrew Cagney + + * ld-cache.[hc], ld-decode.[hc], ld-insn.[hc]: New files. Separate + out the loading of each of the tables from the rest of igen. + * Makefile.in: Adjust. + * igen.c: Adjust. + + * gen-icache.[hc], gen-idecode.[hc], gen-itable.[hc], + gen-model.[hc], gen-semantics.[hc]: New files. Separate out the + code creating each separate set of generated files. + * Makefile.in: Adjust. + * igen.c: Adjust. + + * gen-support.[ch]: New files. Output the support functions (found + in the ppc-instructions file) into a separate file. + * Makefile.in: Add. + * inline.h, inline.c: Add. + * std-config.h: Add. + + * ld-cache.c: Re-design the cache table format. + * ppc-cache-rules: Update to new format. + + * ld-decode.c: Re-design the decode table format. + * ppc-opcode-simple: Update to new format + * ppc-opcode-complex: Ditto + * ppc-opcode-flat: Ditto + + * filter.h, filter.c: New files. Separate the opcode filter table + reading code from the rest of igen.c. Re-design the filter so that + it works inclusivly not exclusivly. + * igen.c: Remove the opcode filter table loading code. + * Makefile.in (filter.o): Adjust + * configure.in: Adjust filter flag so that default includes 32bit + and floating point. + * ppc-instructions: Clean up filter fields so that only in use + entries are specifed (ie delete `be'). + + * misc.c (name2i, i2name): New function. Map between a string and + an integer value. + +Mon Jun 17 20:08:03 1996 Andrew Cagney + + * sim_calls.c (sim_close): If simulator not created, skip printing + of run information. + +Mon Jun 17 20:08:03 1996 Andrew Cagney + + * registers.c (register_description): Typo, insns not insn. + + * ppc-instructions (model_get_number_of_stalls): New model function, + returns number of stalls for the specified processor. + * psim.c (psim_read_register): Add call to new function + model_get_number_of_stalls(). + + * ppc-instructions (model_get_number_of_cycles): New model function, + returns number of stalls for the specified processor. + * psim.c (psim_read_register): Add call to new function + model_get_number_of_cycles(). + +Fri Jun 14 00:11:56 1996 Andrew Cagney + + * device_table.h: Don't pass the parent device into a devices + create function. This makes the create function consistent with + the documentation. + * device.c (device_template_create_device): Ditto + * hw_pal.c (hw_pal_create): Ditto + * hw_core.c (hw_core_create): Ditto + * hw_vm.c (hw_vm_create): Ditto + * hw_disk.c (hw_disk_create): Ditto + * hw_nvram.c (hw_nvram_create): Ditto + * hw_memory.c (hw_memory_create): Ditto + * hw_cpu.c (hw_cpu_create): Ditto. + + * device.c (split_find_device): Allow a null initial parent device. + (device_template_create_device): Ditto. + + * device.c (device_create_from): Make local (static) only used + within device.c. + * device_table.h: typedef device_callbacks moved here (from + device.h) where it belongs. + + * hw_core.c: New file. Implements just the core device using the + core object. + + * corefile.c: Moved all core device functions into the new + hw_core.c file. core_device_create() disapears. + + * psim.c (psim_tree): Use device_tree_add_parsed() to create the + core device. + +Thu Jun 13 00:09:29 1996 Andrew Cagney + + * hw_init.c: Correct typo in comment. + + * corefile.c (core_init): Remove any remaining references to a + default map. + (core_map_find_mapping): Ditto. + +Wed Jun 12 22:30:32 1996 Andrew Cagney + + * corefile.c (core_init): Make function global so that other + devices are able to use the full core object. + + * corefile.c (core_create, core_from_device): Break core_create + into two functions. The first creates a core object, the second + returns the core object associated with a core device. + + * corefile.c (core_device_create): Use core_create to make the + core object. + + * psim.c (psim_create): Use core_from_device() instead of + core_create(). + + * device.c (device_template_create_device): Make static as only + needed by functions internal to device.c. + +Fri Jun 7 23:47:18 1996 Andrew Cagney + + * ppc-opcode-test-2: Remove description of fields. + * ppc-opcode-complex: Ditto + * ppc-opcode-flat: Ditto + * ppc-opcode-simple: Ditto + * ppc-opcode-stupid: Ditto + * ppc-opcode-test-1: Ditto + * ppc-cache-rules: Ditto + + * igen.c: Add description of files as a comment at the front. + +Wed Jun 26 12:50:33 1996 Michael Meissner + + * configure.in: Check for whether the termios and termio + structures are really defined, and whether or not, they define the + c_line field. + * configure: Regenerate. + + * Makefile.in ({,TERMIO_}CFLAGS): Add TERMIO_CFLAGS options set by + configure. + + * emul_unix.c: Various changes to allow for building on systems + with different termio and termios structures. If host has both + termio and termios, just use termios. No longer include + sys/ioctl.h. + Wed Jun 26 12:26:55 1996 Jason Molenda (crash@godzilla.cygnus.co.jp) * Makefile.in (bindir, libdir, datadir, mandir, infodir, includedir, @@ -7,6 +259,13 @@ Wed Jun 26 12:26:55 1996 Jason Molenda (crash@godzilla.cygnus.co.jp) (AC_PROG_INSTALL): Added. * configure: Rebuilt. +Wed Jun 5 23:53:42 1996 Andrew Cagney + + * corefile.h: Rewrite documentation so that it can be extracted and + converted into texinfo (and hence ready for translation into html, + tex or nroff). + * device.h: Ditto + Thu Jun 6 09:52:37 1996 Michael Meissner * hw_disk.c (SEEK_SET): If SEEK_SET is not defined, define as 0. diff --git a/sim/ppc/Makefile.in b/sim/ppc/Makefile.in index 9adf027636e..6e34cedb983 100644 --- a/sim/ppc/Makefile.in +++ b/sim/ppc/Makefile.in @@ -84,6 +84,7 @@ RESERVED_CFLAGS = @sim_reserved@ MONITOR_CFLAGS = @sim_monitor@ MODEL_CFLAGS = @sim_model@ @sim_default_model@ @sim_model_issue@ STDIO_CFLAGS = @sim_stdio@ +TERMIO_CFLAGS = @sim_termio@ WARNING_CFLAGS = @sim_warnings@ CONFIG_CFLAGS = $(BSWAP_CFLAGS) \ $(ENDIAN_CFLAGS) \ @@ -101,24 +102,28 @@ CONFIG_CFLAGS = $(BSWAP_CFLAGS) \ $(RESERVED_CFLAGS) \ $(MONITOR_CFLAGS) \ $(MODEL_CFLAGS) \ - $(STDIO_CFLAGS) + $(STDIO_CFLAGS) \ + $(TERMIO_CFLAGS) STD_CFLAGS = $(CFLAGS) $(INLINE_CFLAGS) $(CONFIG_CFLAGS) $(WARNING_CFLAGS) $(SIM_CFLAGS) $(HDEFINES) $(TDEFINES) $(INCLUDES) NOWARN_CFLAGS = $(CFLAGS) $(INLINE_CFLAGS) $(CONFIG_CFLAGS) $(SIM_CFLAGS) $(HDEFINES) $(TDEFINES) $(INCLUDES) -BUILD_CFLAGS = -O $(INCLUDES) +BUILD_CFLAGS = -O $(INCLUDES) $(WARNING_CFLAGS) BUILD_LDFLAGS = CONFIG_FILE = @sim_config@ IGEN_OPCODE_RULES = @sim_opcode@ IGEN_DUPLICATE = @sim_dup@ +IGEN_JUMP = @sim_jump@ IGEN_FILTER = @sim_filter@ IGEN_ICACHE = @sim_icache@ +IGEN_SMP = @sim_igen_smp@ +IGEN_LINE_NR = @sim_line_nr@ DGEN_FLAGS = @sim_switch@ HDEFINES = @HDEFINES@ TDEFINES = -IGEN_FLAGS = $(IGEN_DUPLICATE) $(IGEN_FILTER) $(IGEN_ICACHE) +IGEN_FLAGS = $(IGEN_DUPLICATE) $(IGEN_JUMP) $(IGEN_FILTER) $(IGEN_ICACHE) $(IGEN_SMP) $(IGEN_LINE_NR) .NOEXPORT: MAKEOVERRIDES= @@ -170,13 +175,13 @@ CPU_H = \ cpu.h \ $(BASICS_H) \ $(REGISTERS_H) \ + $(IDECODE_H) \ device.h \ corefile.h \ vm.h \ events.h \ interrupts.h \ psim.h \ - icache.h \ itable.h \ mon.h \ model.h @@ -199,12 +204,14 @@ INLINE = \ inline.c BUILT_SRC_WO_CONFIG = \ - icache.h \ + icache.h icache.c \ + support.h support.c \ idecode.h idecode.c \ semantics.h semantics.c \ itable.h itable.c \ spreg.h spreg.c \ model.h model.c \ + support.h support.c \ pk.h \ hw.h hw.c \ filter_host.c @@ -273,12 +280,14 @@ LIB_OBJ = \ device_table.o \ itable.o \ mon.o \ + icache.o \ semantics.o \ idecode.o \ + support.o \ psim.o \ options.o \ - $(PACKAGES) \ - $(HW) + $(PACKAGE_OBJ) \ + $(HW_OBJ) GDB_OBJ = sim_calls.o @@ -294,9 +303,10 @@ HW_SRC = \ hw_register.c \ hw_vm.c \ hw_init.c \ + hw_core.c \ hw_pal.c -HW = \ +HW_OBJ = \ hw_cpu.o \ hw_memory.o \ hw_nvram.o \ @@ -307,12 +317,13 @@ HW = \ hw_register.o \ hw_vm.o \ hw_init.o \ + hw_core.o \ hw_pal.o PACKAGE_SRC = \ pk_disklabel.c -PACKAGES = \ +PACKAGE_OBJ = \ pk_disklabel.o @@ -323,7 +334,7 @@ run: psim rm -f run ln psim run -$(TARGETLIB): tmp-igen tmp-dgen $(HW) $(LIB_OBJ) $(GDB_OBJ) +$(TARGETLIB): tmp-igen tmp-dgen tmp-hw tmp-pk $(LIB_OBJ) $(GDB_OBJ) rm -f $(TARGETLIB) $(AR) $(AR_FLAGS) $(TARGETLIB) $(LIB_OBJ) $(GDB_OBJ) $(RANLIB) $(TARGETLIB) @@ -382,6 +393,11 @@ cap.o: cap.c cap.h $(BASICS_H) semantics.o: semantics.c semantics.h $(CPU_H) $(IDECODE_H) $(CC) -c $(NOWARN_CFLAGS) $< +icache.o: icache.c icache.h $(IDECODE_H) $(CPU_H) + $(CC) -c $(NOWARN_CFLAGS) $< + +support.o: support.c support.h $(IDECODE_H) $(CPU_H) + itable.o: itable.c itable.h mon.o: mon.c $(CPU_H) @@ -401,28 +417,32 @@ ppc-config.h: $(CONFIG_FILE) tmp-dgen: dgen ppc-spr-table $(srcdir)/../../move-if-change ./dgen $(DGEN_FLAGS) \ -r $(srcdir)/ppc-spr-table \ - -n spreg.h -P tmp-spreg.h \ - -n spreg.c -p tmp-spreg.c + -n spreg.h -hp tmp-spreg.h \ + -n spreg.c -p tmp-spreg.c $(srcdir)/../../move-if-change tmp-spreg.h spreg.h $(srcdir)/../../move-if-change tmp-spreg.c spreg.c touch tmp-dgen -tmp-igen: igen ppc-instructions $(IGEN_OPCODE_RULES) ppc-cache-rules $(srcdir)/../../move-if-change +tmp-igen: igen ppc-instructions $(IGEN_OPCODE_RULES) ppc-cache-rules $(srcdir)/../../move-if-change tmp-ld-decode tmp-ld-cache tmp-ld-insn tmp-filter ./igen $(IGEN_FLAGS) \ -o $(srcdir)/$(IGEN_OPCODE_RULES) \ -k $(srcdir)/ppc-cache-rules \ -i $(srcdir)/ppc-instructions \ - -n icache.h -C tmp-icache.h \ - -n semantics.h -S tmp-semantics.h \ - -n semantics.c -s tmp-semantics.c \ - -n idecode.h -D tmp-idecode.h \ - -n idecode.c -d tmp-idecode.c \ - -n itable.h -T tmp-itable.h \ - -n itable.c -t tmp-itable.c \ - -n model.h -M tmp-model.h \ - -n model.c -m tmp-model.c + -n icache.h -hc tmp-icache.h \ + -n icache.c -c tmp-icache.c \ + -n semantics.h -hs tmp-semantics.h \ + -n semantics.c -s tmp-semantics.c \ + -n idecode.h -hd tmp-idecode.h \ + -n idecode.c -d tmp-idecode.c \ + -n itable.h -ht tmp-itable.h \ + -n itable.c -t tmp-itable.c \ + -n model.h -hm tmp-model.h \ + -n model.c -m tmp-model.c \ + -n support.h -hf tmp-support.h \ + -n support.c -f tmp-support.c $(srcdir)/../../move-if-change tmp-icache.h icache.h + $(srcdir)/../../move-if-change tmp-icache.c icache.c $(srcdir)/../../move-if-change tmp-idecode.h idecode.h $(srcdir)/../../move-if-change tmp-idecode.c idecode.c $(srcdir)/../../move-if-change tmp-semantics.h semantics.h @@ -431,20 +451,22 @@ tmp-igen: igen ppc-instructions $(IGEN_OPCODE_RULES) ppc-cache-rules $(srcdir)/. $(srcdir)/../../move-if-change tmp-itable.c itable.c $(srcdir)/../../move-if-change tmp-model.h model.h $(srcdir)/../../move-if-change tmp-model.c model.c + $(srcdir)/../../move-if-change tmp-support.h support.h + $(srcdir)/../../move-if-change tmp-support.c support.c touch tmp-igen # NOTE: Some versions of make don't handle files created as side-effects # uncomment the below if that is the case. $(TARGETLIB): tmp-igen tmp-dgen -itable.h itable.c icache.h idecode.h idecode.c semantics.h semantics.c model.h model.c: tmp-igen +itable.h itable.c icache.h icache.c idecode.h idecode.c semantics.h semantics.c model.h model.c support.h support.c: tmp-igen spreg.h spreg.c: tmp-dgen dgen: dgen.o table.o lf.o misc.o filter_host.o $(CC_FOR_BUILD) $(BUILD_CFLAGS) -o dgen dgen.o table.o lf.o misc.o filter_host.o $(BUILD_LIBS) -igen: igen.o table.o lf.o misc.o filter_host.o - $(CC_FOR_BUILD) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) -o igen igen.o table.o lf.o misc.o filter_host.o $(BUILD_LIBS) +igen: igen.o table.o lf.o misc.o filter_host.o ld-decode.o ld-cache.o filter.o ld-insn.o gen-model.o gen-itable.o gen-icache.o gen-semantics.o gen-idecode.o gen-support.o + $(CC_FOR_BUILD) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) -o igen igen.o table.o lf.o misc.o filter_host.o ld-decode.o ld-cache.o filter.o ld-insn.o gen-model.o gen-itable.o gen-icache.o gen-semantics.o gen-idecode.o gen-support.o $(BUILD_LIBS) filter_host.c: filter_filename.c cat $(srcdir)/filter_filename.c > filter_host.c @@ -458,36 +480,76 @@ table.o: table.c misc.h filter_filename.h lf.h table.h lf.o: lf.c misc.h filter_filename.h lf.h $(CC_FOR_BUILD) $(BUILD_CFLAGS) -c $(srcdir)/lf.c +filter.o: filter.c misc.h lf.h table.h filter.h + $(CC_FOR_BUILD) $(BUILD_CFLAGS) -c $(srcdir)/filter.c +tmp-filter: filter.c misc.h misc.o + $(CC_FOR_BUILD) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) -o tmp-filter -DMAIN $(srcdir)/filter.c misc.o $(BUILD_LIBS) + +ld-decode.o: ld-decode.c misc.h lf.h table.h ld-decode.h + $(CC_FOR_BUILD) $(BUILD_CFLAGS) -c $(srcdir)/ld-decode.c +tmp-ld-decode: ld-decode.o misc.o lf.o table.o filter_host.o + $(CC_FOR_BUILD) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) -o tmp-ld-decode -DMAIN $(srcdir)/ld-decode.c misc.o lf.o table.o filter_host.o $(BUILD_LIBS) + +ld-cache.o: ld-cache.c misc.h lf.h table.h ld-cache.h + $(CC_FOR_BUILD) $(BUILD_CFLAGS) -c $(srcdir)/ld-cache.c +tmp-ld-cache: ld-cache.o misc.o lf.o table.o filter_host.o + $(CC_FOR_BUILD) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) -o tmp-ld-cache -DMAIN $(srcdir)/ld-cache.c misc.o lf.o table.o filter_host.o $(BUILD_LIBS) + +ld-insn.o: ld-insn.c misc.h lf.h table.h ld-insn.h ld-decode.h igen.h + $(CC_FOR_BUILD) $(BUILD_CFLAGS) -c $(srcdir)/ld-insn.c +tmp-ld-insn: ld-insn.o misc.o lf.o table.o ld-decode.o filter_host.o filter.o + $(CC_FOR_BUILD) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) -o tmp-ld-insn -DMAIN $(srcdir)/ld-insn.c misc.o lf.o table.o ld-decode.o filter_host.o filter.o $(BUILD_LIBS) + +gen-model.o: gen-model.c misc.h lf.h table.h gen-model.h ld-decode.h igen.h ld-insn.h + $(CC_FOR_BUILD) $(BUILD_CFLAGS) -c $(srcdir)/gen-model.c + +gen-itable.o: gen-itable.c misc.h lf.h table.h gen-itable.h ld-decode.h igen.h ld-insn.h igen.h + $(CC_FOR_BUILD) $(BUILD_CFLAGS) -c $(srcdir)/gen-itable.c + +gen-icache.o: gen-icache.c misc.h lf.h table.h gen-icache.h ld-decode.h igen.h ld-insn.h gen-semantics.h gen-idecode.h + $(CC_FOR_BUILD) $(BUILD_CFLAGS) -c $(srcdir)/gen-icache.c + +gen-semantics.o: gen-semantics.c misc.h lf.h table.h gen-semantics.h ld-decode.h igen.h ld-insn.h + $(CC_FOR_BUILD) $(BUILD_CFLAGS) -c $(srcdir)/gen-semantics.c + +gen-idecode.o: gen-idecode.c misc.h lf.h table.h gen-idecode.h gen-icache.h gen-semantics.h ld-decode.h igen.h ld-insn.h + $(CC_FOR_BUILD) $(BUILD_CFLAGS) -c $(srcdir)/gen-idecode.c + +gen-support.o: gen-support.c misc.h lf.h table.h gen-support.h ld-decode.h igen.h ld-insn.h + $(CC_FOR_BUILD) $(BUILD_CFLAGS) -c $(srcdir)/gen-support.c + dgen.o: dgen.c misc.h filter_filename.h lf.h table.h $(CC_FOR_BUILD) $(BUILD_CFLAGS) -c $(srcdir)/dgen.c -igen.o: igen.c misc.h filter_filename.h lf.h table.h +igen.o: igen.c misc.h filter_filename.h lf.h table.h ld-decode.h ld-cache.h ld-insn.h filter.h gen-model.h gen-itable.h gen-icache.h gen-idecode.h gen-semantics.h gen-support.h igen.h $(CC_FOR_BUILD) $(BUILD_CFLAGS) -c $(srcdir)/igen.c misc.o: misc.c misc.h filter_filename.h $(CC_FOR_BUILD) $(BUILD_CFLAGS) -c $(srcdir)/misc.c -# With out this #, make thinks that misc.o doesn't have a rule + # real hardware -hw.h: Makefile +tmp-hw: Makefile $(HW_SRC) $(srcdir)/../../move-if-change (cd $(srcdir); ls $(HW_SRC)) \ | sed -e 's/^.*\(hw_.*\)\.c/\1/' \ -e 's/^/extern const device_descriptor /' \ -e 's/$$/_device_descriptor\[\];/' \ > tmp-hw.h - mv tmp-hw.h hw.h -hw.c: Makefile (cd $(srcdir); ls $(HW_SRC)) \ | sed -e 's/^.*\(hw_.*\)\.c/\1/' \ -e 's/^/ /' \ -e 's/$$/_device_descriptor,/' \ > tmp-hw.c - mv tmp-hw.c hw.c + $(srcdir)/../../move-if-change tmp-hw.h hw.h + $(srcdir)/../../move-if-change tmp-hw.c hw.c + touch tmp-hw + hw_cpu.o: hw_cpu.c $(DEVICE_TABLE_H) hw_memory.o: hw_memory.c $(DEVICE_TABLE_H) hw_nvram.o: hw_nvram.c $(DEVICE_TABLE_H) hw_iobus.o: hw_iobus.c $(DEVICE_TABLE_H) +hw_core.o: hw_core.c $(DEVICE_TABLE_H) hw_pal.o: hw_pal.c $(DEVICE_TABLE_H) hw_htab.o: hw_htab.c $(DEVICE_TABLE_H) hw_disk.o: hw_disk.c $(DEVICE_TABLE_H) pk.h @@ -498,18 +560,22 @@ hw_init.o: hw_init.c $(DEVICE_TABLE_H) # ignore this line, it stops make from getting confused + # real packages -pk.h: Makefile +tmp-pk: Makefile $(PACKAGE_SRC) $(srcdir)/../../move-if-change (cd $(srcdir); ls $(PACKAGE_SRC)) \ | sed -e 's/^pk_\(.*\)\.c/\1/' \ -e 's/^/extern package_create_instance_callback pk_/' \ -e 's/$$/_create_instance;/' \ > tmp-pk.h - mv tmp-pk.h pk.h + $(srcdir)/../../move-if-change tmp-pk.h pk.h + touch tmp-pk pk_disklabel.o: pk.h $(DEVICE_TABLE_H) # ignore this line, it stops make from getting confused + + tags etags: TAGS TAGS: $(BUILT_SRC) diff --git a/sim/ppc/NOTES b/sim/ppc/NOTES deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/sim/ppc/configure b/sim/ppc/configure index ce91e0438a4..ba7712ce0ed 100755 --- a/sim/ppc/configure +++ b/sim/ppc/configure @@ -15,6 +15,8 @@ ac_help="$ac_help --enable-sim-cflags=opts Extra CFLAGS for use in building simulator" ac_help="$ac_help --enable-sim-warnings=opts Extra CFLAGS for turning on compiler warnings except for idecode.o, semantics.o and psim.o" +ac_help="$ac_help + --enable-sim-line-nr=opts Generate extra CPP code that references source rather than generated code" ac_help="$ac_help --enable-sim-config=file Override default config file" ac_help="$ac_help @@ -23,6 +25,8 @@ ac_help="$ac_help --enable-sim-switch Use a switch instead of a table for instruction call." ac_help="$ac_help --enable-sim-duplicate Expand (duplicate) semantic functions." +ac_help="$ac_help + --enable-sim-jump Jump between semantic code (instead of call/return)." ac_help="$ac_help --enable-sim-filter=rule Specify filter rules." ac_help="$ac_help @@ -569,6 +573,84 @@ fi +ac_aux_dir= +for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; } +fi +ac_config_guess=$ac_aux_dir/config.guess +ac_config_sub=$ac_aux_dir/config.sub +ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 +if test -z "$INSTALL"; then +if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + # Account for people who put trailing slashes in PATH elements. + case "$ac_dir/" in + /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + for ac_prog in ginstall installbsd scoinst install; do + if test -f $ac_dir/$ac_prog; then + if test $ac_prog = install && + grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + # OSF/1 installbsd also uses dspmsg, but is usable. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + IFS="$ac_save_ifs" + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL="$ac_cv_path_install" + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL="$ac_install_sh" + fi +fi +echo "$ac_t""$INSTALL" 1>&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 @@ -655,7 +737,7 @@ else yes; #endif EOF -if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:659: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then +if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:741: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then ac_cv_prog_gcc=yes else ac_cv_prog_gcc=no @@ -692,84 +774,6 @@ else test "${CFLAGS+set}" = set || CFLAGS="-g" fi -ac_aux_dir= -for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do - if test -f $ac_dir/install-sh; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install-sh -c" - break - elif test -f $ac_dir/install.sh; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install.sh -c" - break - fi -done -if test -z "$ac_aux_dir"; then - { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; } -fi -ac_config_guess=$ac_aux_dir/config.guess -ac_config_sub=$ac_aux_dir/config.sub -ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. - -# Find a good install program. We prefer a C program (faster), -# so one script is as good as another. But avoid the broken or -# incompatible versions: -# SysV /etc/install, /usr/sbin/install -# SunOS /usr/etc/install -# IRIX /sbin/install -# AIX /bin/install -# AFS /usr/afsws/bin/install, which mishandles nonexistent args -# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" -# ./install, which can be erroneously created by make from ./install.sh. -echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 -if test -z "$INSTALL"; then -if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" - for ac_dir in $PATH; do - # Account for people who put trailing slashes in PATH elements. - case "$ac_dir/" in - /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; - *) - # OSF1 and SCO ODT 3.0 have their own names for install. - for ac_prog in ginstall installbsd scoinst install; do - if test -f $ac_dir/$ac_prog; then - if test $ac_prog = install && - grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then - # AIX install. It has an incompatible calling convention. - # OSF/1 installbsd also uses dspmsg, but is usable. - : - else - ac_cv_path_install="$ac_dir/$ac_prog -c" - break 2 - fi - fi - done - ;; - esac - done - IFS="$ac_save_ifs" - -fi - if test "${ac_cv_path_install+set}" = set; then - INSTALL="$ac_cv_path_install" - else - # As a last resort, use the slow shell script. We don't cache a - # path for INSTALL within a source directory, because that will - # break other packages using the cache if that directory is - # removed, or if the path is relative. - INSTALL="$ac_install_sh" - fi -fi -echo "$ac_t""$INSTALL" 1>&6 - -# Use test -z because SunOS4 sh mishandles braces in ${var-val}. -# It thinks the first close brace ends the variable substitution. -test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' - -test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' - # Put a plausible default for CC_FOR_BUILD in Makefile. # If we cannot run a trivial program, we must be cross compiling. @@ -781,11 +785,11 @@ else ac_cv_c_cross=yes else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } +{ (eval echo configure:793: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } if test -s conftest && (./conftest; exit) 2>/dev/null; then ac_cv_c_cross=no else @@ -834,6 +838,21 @@ else sim_warnings="" fi +# Check whether --enable-sim-line-nr or --disable-sim-line-nr was given. +if test "${enable_sim_line_nr+set}" = set; then + enableval="$enable_sim_line_nr" + case "${enableval}" in + yes) sim_line_nr="";; + no) sim_line_nr="-L";; + *) { echo "configure: error: "--enable-sim-line-nr does not take a value"" 1>&2; exit 1; }; sim_line_nr="";; +esac +if test x"$silent" != x"yes" && test x"$sim_line_nr" != x""; then + echo "Setting warning flags = $sim_line_nr" 6>&1 +fi +else + sim_line-nr="" +fi + # Check whether --enable-sim-config or --disable-sim-config was given. if test "${enable_sim_config+set}" = set; then enableval="$enable_sim_config" @@ -904,7 +923,7 @@ fi if test "${enable_sim_duplicate+set}" = set; then enableval="$enable_sim_duplicate" case "${enableval}" in - yes) sim_dup="-e";; + yes) sim_dup="-E";; no) sim_dup="";; *) { echo "configure: error: "--enable-sim-duplicate does not take a value"" 1>&2; exit 1; }; sim_dup="";; esac @@ -912,25 +931,43 @@ if test x"$silent" != x"yes" && test x"$sim_dup" != x""; then echo "Setting duplicate flags = $sim_dup" 6>&1 fi else - sim_dup="-e" + sim_dup="-E" if test x"$silent" != x"yes"; then echo "Setting duplicate flags = $sim_dup" 6>&1 fi fi +# Check whether --enable-sim-jump or --disable-sim-jump was given. +if test "${enable_sim_jump+set}" = set; then + enableval="$enable_sim_jump" + case "${enableval}" in + yes) sim_jump="-J";; + no) sim_jump="";; + *) { echo "configure: error: "--enable-sim-jump does not take a value"" 1>&2; exit 1; }; sim_jump="";; +esac +if test x"$silent" != x"yes" && test x"$sim_jump" != x""; then + echo "Setting jump flag = $sim_jump" 6>&1 +fi +else + sim_jump="-E" +if test x"$silent" != x"yes"; then + echo "Setting jump flag = $sim_jump" 6>&1 +fi +fi + # Check whether --enable-sim-filter or --disable-sim-filter was given. if test "${enable_sim_filter+set}" = set; then enableval="$enable_sim_filter" case "${enableval}" in yes) { echo "configure: error: "--enable-sim-filter must be specified with a rule to filter or no"" 1>&2; exit 1; }; sim_filter="";; no) sim_filter="";; - *) sim_filter="-f $enableval";; + *) sim_filter="-F $enableval";; esac if test x"$silent" != x"yes" && test x"$sim_filter" != x""; then echo "Setting filter flags = $sim_filter" 6>&1 fi else - sim_filter="-f 64" + sim_filter="-F 32,f" if test x"$silent" != x"yes"; then echo "Setting filter flags = $sim_filter" 6>&1 fi @@ -941,18 +978,27 @@ if test "${enable_sim_icache+set}" = set; then enableval="$enable_sim_icache" icache="" case "${enableval}" in - yes) sim_icache="-r 1024"; icache="1024";; - define) sim_icache="-r 1024 -R"; icache="1024";; + yes) icache="1024"; sim_icache="-I $icache";; no) sim_icache="";; - *) sim_icache="-r ${enableval}"; icache="${enableval}";; + *) icache=1024 + sim_icache="-" + for x in `echo "${enableval}" | sed -e "s/,/ /g"`; do + case "$x" in + define) sim_icache="${sim_icache}R";; + semantic) sim_icache="${sim_icache}C";; + 0*|1*|2*|3*|4*|5*|6*|7*|8*|9*) icache=$x;; + *) { echo "configure: error: "Unknown value $x for --enable-sim-icache"" 1>&2; exit 1; }; sim_icache="";; + esac + done + sim_icache="${sim_icache}I $icache";; esac if test x"$silent" != x"yes" && test x"$icache" != x""; then - echo "Setting instruction cache size to $icache" + echo "Setting instruction cache size to $icache ($sim_icache)" fi else - sim_icache="-r 1024" + sim_icache="-CI 1024" if test x"$silent" != x"yes"; then - echo "Setting instruction cache size to 1024" + echo "Setting instruction cache size to 1024 ($sim_icache)" fi fi @@ -1052,7 +1098,7 @@ else ac_cv_c_bigendian=unknown # See if sys/param.h defines the BYTE_ORDER macro. cat > conftest.$ac_ext < #include @@ -1064,11 +1110,11 @@ int t() { #endif ; return 0; } EOF -if { (eval echo configure:1068: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:1114: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* # It does; now see whether it defined to BIG_ENDIAN or not. cat > conftest.$ac_ext < #include @@ -1080,7 +1126,7 @@ int t() { #endif ; return 0; } EOF -if { (eval echo configure:1084: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:1130: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_c_bigendian=yes else @@ -1097,7 +1143,7 @@ if test "$cross_compiling" = yes; then { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } +{ (eval echo configure:1160: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } if test -s conftest && (./conftest; exit) 2>/dev/null; then ac_cv_c_bigendian=no else @@ -1143,15 +1189,15 @@ fi if test "${enable_sim_smp+set}" = set; then enableval="$enable_sim_smp" case "${enableval}" in - yes) sim_smp="-DWITH_SMP=5";; - no) sim_smp="-DWITH_SMP=0";; - *) sim_smp="-DWITH_SMP=$enableval";; + yes) sim_smp="-DWITH_SMP=5" ; sim_igen_smp="-N 5";; + no) sim_smp="-DWITH_SMP=0" ; sim_igen_smp="-N 0";; + *) sim_smp="-DWITH_SMP=$enableval" ; sim_igen_smp="-N $enableval";; esac if test x"$silent" != x"yes" && test x"$sim_smp" != x""; then echo "Setting smp flags = $sim_smp" 6>&1 fi else - sim_smp="-DWITH_SMP=5" + sim_smp="-DWITH_SMP=5" ; sim_igen_smp="-N 5" if test x"$silent" != x"yes"; then echo "Setting smp flags = $sim_smp" 6>&1 fi @@ -1509,68 +1555,6 @@ test "$program_transform_name" = "" && program_transform_name="s,x,x," . ${srcdir}/../../bfd/configure.host - - - - - - -AR=${AR-ar} - -# Extract the first word of "ranlib", so it can be a program name with args. -set dummy ranlib; ac_word=$2 -echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - if test -n "$RANLIB"; then - ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. -else - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" - for ac_dir in $PATH; do - test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/$ac_word; then - ac_cv_prog_RANLIB="ranlib" - break - fi - done - IFS="$ac_save_ifs" - test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":" -fi -fi -RANLIB="$ac_cv_prog_RANLIB" -if test -n "$RANLIB"; then - echo "$ac_t""$RANLIB" 1>&6 -else - echo "$ac_t""no" 1>&6 -fi - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1579,7 +1563,7 @@ if eval "test \"`echo '$''{'ac_cv_struct_st_blksize'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include @@ -1588,7 +1572,7 @@ int t() { struct stat s; s.st_blksize; ; return 0; } EOF -if { (eval echo configure:1592: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:1576: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_struct_st_blksize=yes else @@ -1612,7 +1596,7 @@ if eval "test \"`echo '$''{'ac_cv_struct_st_blocks'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include @@ -1621,7 +1605,7 @@ int t() { struct stat s; s.st_blocks; ; return 0; } EOF -if { (eval echo configure:1625: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:1609: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_struct_st_blocks=yes else @@ -1647,7 +1631,7 @@ if eval "test \"`echo '$''{'ac_cv_struct_st_rdev'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include @@ -1656,7 +1640,7 @@ int t() { struct stat s; s.st_rdev; ; return 0; } EOF -if { (eval echo configure:1660: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:1644: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_struct_st_rdev=yes else @@ -1680,7 +1664,7 @@ if eval "test \"`echo '$''{'ac_cv_struct_tm'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include @@ -1689,7 +1673,7 @@ int t() { struct tm *tp; tp->tm_sec; ; return 0; } EOF -if { (eval echo configure:1693: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:1677: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_struct_tm=time.h else @@ -1713,7 +1697,7 @@ if eval "test \"`echo '$''{'ac_cv_struct_tm_zone'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include <$ac_cv_struct_tm> @@ -1722,7 +1706,7 @@ int t() { struct tm tm; tm.tm_zone; ; return 0; } EOF -if { (eval echo configure:1726: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:1710: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_struct_tm_zone=yes else @@ -1745,7 +1729,7 @@ if eval "test \"`echo '$''{'ac_cv_var_tzname'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #ifndef tzname /* For SGI. */ @@ -1756,7 +1740,7 @@ int t() { atoi(*tzname); ; return 0; } EOF -if { (eval echo configure:1760: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then +if { (eval echo configure:1744: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then rm -rf conftest* ac_cv_var_tzname=yes else @@ -1792,13 +1776,13 @@ else # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. cat > conftest.$ac_ext < Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:1802: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:1786: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then : @@ -1807,13 +1791,13 @@ else rm -rf conftest* CPP="${CC-cc} -E -traditional-cpp" cat > conftest.$ac_ext < Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:1817: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:1801: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then : @@ -1838,7 +1822,7 @@ if eval "test \"`echo '$''{'ac_cv_type_uid_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF @@ -1874,7 +1858,7 @@ else ac_cv_type_getgroups=cross else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } +{ (eval echo configure:1887: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } if test -s conftest && (./conftest; exit) 2>/dev/null; then ac_cv_type_getgroups=gid_t else @@ -1909,7 +1893,7 @@ fi rm -fr conftest* if test $ac_cv_type_getgroups = cross; then cat > conftest.$ac_ext < EOF @@ -1937,7 +1921,7 @@ if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include @@ -1945,7 +1929,7 @@ else #include EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:1949: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:1933: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then rm -rf conftest* @@ -1960,7 +1944,7 @@ rm -f conftest* if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat > conftest.$ac_ext < EOF @@ -1978,7 +1962,7 @@ fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat > conftest.$ac_ext < EOF @@ -1999,7 +1983,7 @@ if test "$cross_compiling" = yes; then : else cat > conftest.$ac_ext < #define ISLOWER(c) ('a' <= (c) && (c) <= 'z') @@ -2010,7 +1994,7 @@ if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); exit (0); } EOF -{ (eval echo configure:2014: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } +{ (eval echo configure:1998: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } if test -s conftest && (./conftest; exit) 2>/dev/null; then : else @@ -2034,7 +2018,7 @@ if eval "test \"`echo '$''{'ac_cv_type_mode_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #if STDC_HEADERS @@ -2065,7 +2049,7 @@ if eval "test \"`echo '$''{'ac_cv_type_off_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #if STDC_HEADERS @@ -2096,7 +2080,7 @@ if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #if STDC_HEADERS @@ -2127,7 +2111,7 @@ if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include @@ -2145,7 +2129,7 @@ int t() { int i; ; return 0; } EOF -if { (eval echo configure:2149: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:2133: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_type_signal=void else @@ -2167,7 +2151,7 @@ if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #if STDC_HEADERS @@ -2198,7 +2182,7 @@ if eval "test \"`echo '$''{'ac_cv_type_uid_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF @@ -2234,7 +2218,7 @@ if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; }; then +if { (eval echo configure:2246: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -2289,12 +2273,12 @@ if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:2298: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:2282: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then rm -rf conftest* @@ -2327,7 +2311,7 @@ if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include <$ac_hdr> @@ -2336,7 +2320,7 @@ int t() { DIR *dirp = 0; ; return 0; } EOF -if { (eval echo configure:2340: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:2324: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* eval "ac_cv_header_dirent_$ac_safe=yes" else @@ -2367,7 +2351,7 @@ else ac_save_LIBS="$LIBS" LIBS="-ldir $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; }; then +if { (eval echo configure:2367: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -2406,7 +2390,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lx $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; }; then +if { (eval echo configure:2406: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -2437,6 +2421,217 @@ else fi fi + + +sim_termio="" +echo $ac_n "checking for struct termios""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_termios_struct'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +int main() { return 0; } +int t() { +static struct termios x; + x.c_iflag = 0; + x.c_oflag = 0; + x.c_cflag = 0; + x.c_lflag = 0; + x.c_cc[NCCS] = 0; +; return 0; } +EOF +if { (eval echo configure:2447: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_termios_struct=yes +else + rm -rf conftest* + ac_cv_termios_struct=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_termios_struct" 1>&6 +if test $ac_cv_termios_struct = yes; then + sim_termio="$sim_termio -DHAVE_TERMIOS_STRUCTURE" +fi + +if test "$ac_cv_termios_struct" = "yes"; then + echo $ac_n "checking for c_line field in struct termios""... $ac_c" 1>&6 + if eval "test \"`echo '$''{'ac_cv_termios_cline'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +int main() { return 0; } +int t() { +static struct termios x; x.c_line = 0; +; return 0; } +EOF +if { (eval echo configure:2478: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_termios_cline=yes +else + rm -rf conftest* + ac_cv_termios_cline=no +fi +rm -f conftest* + +fi + + + echo "$ac_t""$ac_cv_termios_cline" 1>&6 + if test $ac_cv_termios_cline = yes; then + sim_termio="$sim_termio -DHAVE_TERMIOS_CLINE" + fi +else + ac_cv_termios_cline=no +fi + +if test "$ac_cv_termios_struct" != "yes"; then + echo $ac_n "checking for struct termio""... $ac_c" 1>&6 + if eval "test \"`echo '$''{'ac_cv_termio_struct'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +int main() { return 0; } +int t() { +static struct termio x; + x.c_iflag = 0; + x.c_oflag = 0; + x.c_cflag = 0; + x.c_lflag = 0; + x.c_cc[NCC] = 0; +; return 0; } +EOF +if { (eval echo configure:2518: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_termio_struct=yes +else + rm -rf conftest* + ac_cv_termio_struct=no +fi +rm -f conftest* + +fi + + echo "$ac_t""$ac_cv_termio_struct" 1>&6 + if test $ac_cv_termio_struct = yes; then + sim_termio="$sim_termio -DHAVE_TERMIO_STRUCTURE" + fi +else + ac_cv_termio_struct=no +fi + +if test "$ac_cv_termio_struct" = "yes"; then + echo $ac_n "checking for c_line field in struct termio""... $ac_c" 1>&6 + if eval "test \"`echo '$''{'ac_cv_termio_cline'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +int main() { return 0; } +int t() { +static struct termio x; x.c_line = 0; +; return 0; } +EOF +if { (eval echo configure:2552: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_termio_cline=yes +else + rm -rf conftest* + ac_cv_termio_cline=no +fi +rm -f conftest* + +fi + + + echo "$ac_t""$ac_cv_termio_cline" 1>&6 + if test $ac_cv_termio_cline = yes; then + sim_termio="$sim_termio -DHAVE_TERMIO_CLINE" + fi +else + ac_cv_termio_cline=no +fi + + + + +AR=${AR-ar} + +# Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_RANLIB="ranlib" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":" +fi +fi +RANLIB="$ac_cv_prog_RANLIB" +if test -n "$RANLIB"; then + echo "$ac_t""$RANLIB" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + trap '' 1 2 15 @@ -2556,9 +2751,9 @@ s%@includedir@%$includedir%g s%@oldincludedir@%$oldincludedir%g s%@infodir@%$infodir%g s%@mandir@%$mandir%g -s%@CC@%$CC%g s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g s%@INSTALL_DATA@%$INSTALL_DATA%g +s%@CC@%$CC%g s%@host@%$host%g s%@host_alias@%$host_alias%g s%@host_cpu@%$host_cpu%g @@ -2574,16 +2769,20 @@ s%@build_alias@%$build_alias%g s%@build_cpu@%$build_cpu%g s%@build_vendor@%$build_vendor%g s%@build_os@%$build_os%g +s%@LIBOBJS@%$LIBOBJS%g +s%@CPP@%$CPP%g s%@CC_FOR_BUILD@%$CC_FOR_BUILD%g s%@HDEFINES@%$HDEFINES%g s%@AR@%$AR%g s%@RANLIB@%$RANLIB%g s%@sim_cflags@%$sim_cflags%g s%@sim_warnings@%$sim_warnings%g +s%@sim_line_nr@%$sim_line_nr%g s%@sim_config@%$sim_config%g s%@sim_opcode@%$sim_opcode%g s%@sim_switch@%$sim_switch%g s%@sim_dup@%$sim_dup%g +s%@sim_jump@%$sim_jump%g s%@sim_filter@%$sim_filter%g s%@sim_icache@%$sim_icache%g s%@sim_inline@%$sim_inline%g @@ -2592,6 +2791,7 @@ s%@sim_endian@%$sim_endian%g s%@sim_xor_endian@%$sim_xor_endian%g s%@sim_hostendian@%$sim_hostendian%g s%@sim_smp@%$sim_smp%g +s%@sim_igen_smp@%$sim_igen_smp%g s%@sim_bitsize@%$sim_bitsize%g s%@sim_hostbitsize@%$sim_hostbitsize%g s%@sim_env@%$sim_env%g @@ -2606,8 +2806,7 @@ s%@sim_model@%$sim_model%g s%@sim_default_model@%$sim_default_model%g s%@sim_model_issue@%$sim_model_issue%g s%@sim_stdio@%$sim_stdio%g -s%@LIBOBJS@%$LIBOBJS%g -s%@CPP@%$CPP%g +s%@sim_termio@%$sim_termio%g CEOF EOF diff --git a/sim/ppc/configure.in b/sim/ppc/configure.in index 5d0f779f394..e7b40ad73bc 100644 --- a/sim/ppc/configure.in +++ b/sim/ppc/configure.in @@ -1,7 +1,8 @@ dnl Process this file with autoconf to produce a configure script. -AC_PREREQ(2.3)dnl +AC_PREREQ(2.5)dnl AC_INIT(Makefile.in) +AC_PROG_INSTALL AC_PROG_CC # Put a plausible default for CC_FOR_BUILD in Makefile. @@ -34,6 +35,17 @@ if test x"$silent" != x"yes" && test x"$sim_warnings" != x""; then echo "Setting warning flags = $sim_warnings" 6>&1 fi],[sim_warnings=""])dnl +AC_ARG_ENABLE(sim-line-nr, +[ --enable-sim-line-nr=opts Generate extra CPP code that references source rather than generated code], +[case "${enableval}" in + yes) sim_line_nr="";; + no) sim_line_nr="-L";; + *) AC_MSG_ERROR("--enable-sim-line-nr does not take a value"); sim_line_nr="";; +esac +if test x"$silent" != x"yes" && test x"$sim_line_nr" != x""; then + echo "Setting warning flags = $sim_line_nr" 6>&1 +fi],[sim_line-nr=""])dnl + AC_ARG_ENABLE(sim-config, [ --enable-sim-config=file Override default config file], [case "${enableval}" in @@ -91,27 +103,41 @@ fi])dnl AC_ARG_ENABLE(sim-duplicate, [ --enable-sim-duplicate Expand (duplicate) semantic functions.], [case "${enableval}" in - yes) sim_dup="-e";; + yes) sim_dup="-E";; no) sim_dup="";; *) AC_MSG_ERROR("--enable-sim-duplicate does not take a value"); sim_dup="";; esac if test x"$silent" != x"yes" && test x"$sim_dup" != x""; then echo "Setting duplicate flags = $sim_dup" 6>&1 -fi],[sim_dup="-e" +fi],[sim_dup="-E" if test x"$silent" != x"yes"; then echo "Setting duplicate flags = $sim_dup" 6>&1 fi])dnl +AC_ARG_ENABLE(sim-jump, +[ --enable-sim-jump Jump between semantic code (instead of call/return).], +[case "${enableval}" in + yes) sim_jump="-J";; + no) sim_jump="";; + *) AC_MSG_ERROR("--enable-sim-jump does not take a value"); sim_jump="";; +esac +if test x"$silent" != x"yes" && test x"$sim_jump" != x""; then + echo "Setting jump flag = $sim_jump" 6>&1 +fi],[sim_jump="-E" +if test x"$silent" != x"yes"; then + echo "Setting jump flag = $sim_jump" 6>&1 +fi])dnl + AC_ARG_ENABLE(sim-filter, [ --enable-sim-filter=rule Specify filter rules.], [case "${enableval}" in yes) AC_MSG_ERROR("--enable-sim-filter must be specified with a rule to filter or no"); sim_filter="";; no) sim_filter="";; - *) sim_filter="-f $enableval";; + *) sim_filter="-F $enableval";; esac if test x"$silent" != x"yes" && test x"$sim_filter" != x""; then echo "Setting filter flags = $sim_filter" 6>&1 -fi],[sim_filter="-f 64" +fi],[sim_filter="-F 32,f" if test x"$silent" != x"yes"; then echo "Setting filter flags = $sim_filter" 6>&1 fi])dnl @@ -120,16 +146,25 @@ AC_ARG_ENABLE(sim-icache, [ --enable-sim-icache=size Specify instruction cache size.], icache="" [case "${enableval}" in - yes) sim_icache="-r 1024"; icache="1024";; - define) sim_icache="-r 1024 -R"; icache="1024";; + yes) icache="1024"; sim_icache="-I $icache";; no) sim_icache="";; - *) sim_icache="-r ${enableval}"; icache="${enableval}";; + *) icache=1024 + sim_icache="-" + for x in `echo "${enableval}" | sed -e "s/,/ /g"`; do + case "$x" in + define) sim_icache="${sim_icache}R";; + semantic) sim_icache="${sim_icache}C";; + 0*|1*|2*|3*|4*|5*|6*|7*|8*|9*) icache=$x;; + *) AC_MSG_ERROR("Unknown value $x for --enable-sim-icache"); sim_icache="";; + esac + done + sim_icache="${sim_icache}I $icache";; esac if test x"$silent" != x"yes" && test x"$icache" != x""; then - echo "Setting instruction cache size to $icache" -fi],[sim_icache="-r 1024" + echo "Setting instruction cache size to $icache ($sim_icache)" +fi],[sim_icache="-CI 1024" if test x"$silent" != x"yes"; then - echo "Setting instruction cache size to 1024" + echo "Setting instruction cache size to 1024 ($sim_icache)" fi])dnl AC_ARG_ENABLE(sim-inline, @@ -219,13 +254,13 @@ fi])dnl AC_ARG_ENABLE(sim-smp, [ --enable-sim-smp=n Specify number of processors to configure for.], [case "${enableval}" in - yes) sim_smp="-DWITH_SMP=5";; - no) sim_smp="-DWITH_SMP=0";; - *) sim_smp="-DWITH_SMP=$enableval";; + yes) sim_smp="-DWITH_SMP=5" ; sim_igen_smp="-N 5";; + no) sim_smp="-DWITH_SMP=0" ; sim_igen_smp="-N 0";; + *) sim_smp="-DWITH_SMP=$enableval" ; sim_igen_smp="-N $enableval";; esac if test x"$silent" != x"yes" && test x"$sim_smp" != x""; then echo "Setting smp flags = $sim_smp" 6>&1 -fi],[sim_smp="-DWITH_SMP=5" +fi],[sim_smp="-DWITH_SMP=5" ; sim_igen_smp="-N 5" if test x"$silent" != x"yes"; then echo "Setting smp flags = $sim_smp" 6>&1 fi])dnl @@ -500,10 +535,12 @@ AC_SUBST(AR) AC_PROG_RANLIB AC_SUBST(sim_cflags) AC_SUBST(sim_warnings) +AC_SUBST(sim_line_nr) AC_SUBST(sim_config) AC_SUBST(sim_opcode) AC_SUBST(sim_switch) AC_SUBST(sim_dup) +AC_SUBST(sim_jump) AC_SUBST(sim_filter) AC_SUBST(sim_icache) AC_SUBST(sim_inline) @@ -512,6 +549,7 @@ AC_SUBST(sim_endian) AC_SUBST(sim_xor_endian) AC_SUBST(sim_hostendian) AC_SUBST(sim_smp) +AC_SUBST(sim_igen_smp) AC_SUBST(sim_bitsize) AC_SUBST(sim_hostbitsize) AC_SUBST(sim_env) diff --git a/sim/ppc/device.c b/sim/ppc/device.c index 618c5a48954..83d9e3fd4ff 100644 --- a/sim/ppc/device.c +++ b/sim/ppc/device.c @@ -1,6 +1,6 @@ /* This file is part of the program psim. - Copyright (C) 1994-1995, Andrew Cagney + Copyright (C) 1994-1996, Andrew Cagney This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -25,6 +25,7 @@ #include #include "device_table.h" +#include "cap.h" #ifdef HAVE_STDLIB_H #include @@ -40,72 +41,141 @@ #include +STATIC_INLINE_DEVICE (void) clean_device_properties(device *); +STATIC_INLINE_DEVICE (void) init_device_properties(device *, void*); +/* property entries */ typedef struct _device_property_entry device_property_entry; struct _device_property_entry { - const char *name; device_property_entry *next; device_property *value; + const void *init_array; + unsigned sizeof_init_array; +}; + + +/* Interrupt edges */ + +typedef struct _device_interrupt_edge device_interrupt_edge; +struct _device_interrupt_edge { + int my_port; + device *dest; + int dest_port; + device_interrupt_edge *next; + object_disposition disposition; }; +STATIC_INLINE_DEVICE\ +(void) +attach_device_interrupt_edge(device_interrupt_edge **list, + int my_port, + device *dest, + int dest_port, + object_disposition disposition) +{ + device_interrupt_edge *new_edge = ZALLOC(device_interrupt_edge); + new_edge->my_port = my_port; + new_edge->dest = dest; + new_edge->dest_port = dest_port; + new_edge->next = *list; + new_edge->disposition = disposition; + *list = new_edge; +} + +STATIC_INLINE_DEVICE\ +(void) +detach_device_interrupt_edge(device *me, + device_interrupt_edge **list, + int my_port, + device *dest, + int dest_port) +{ + while (*list != NULL) { + device_interrupt_edge *old_edge = *list; + if (old_edge->dest == dest + && old_edge->dest_port == dest_port + && old_edge->my_port == my_port) { + if (old_edge->disposition == permenant_object) + device_error(me, "attempt to delete permenant interrupt\n"); + *list = old_edge->next; + zfree(old_edge); + return; + } + } + device_error(me, "attempt to delete unattached interrupt\n"); +} + +STATIC_INLINE_DEVICE\ +(void) +clean_device_interrupt_edges(device_interrupt_edge **list) +{ + while (*list != NULL) { + device_interrupt_edge *old_edge = *list; + switch (old_edge->disposition) { + case permenant_object: + list = &old_edge->next; + break; + case tempoary_object: + *list = old_edge->next; + zfree(old_edge); + break; + } + } +} + /* A device */ + struct _device { + /* my name is ... */ const char *name; - const char *full_name; + device_unit unit_address; + const char *path; + /* device tree */ device *parent; device *children; device *sibling; - /* hw/sw callbacks */ + + /* its template methods */ void *data; /* device specific data */ const device_callbacks *callback; + /* device properties */ device_property_entry *properties; + + /* interrupts */ + device_interrupt_edge *interrupt_destinations; + + /* any open instances of this device */ + device_instance *instances; + + /* the internal/external mappings and other global requirements */ + cap *ihandles; + cap *phandles; + psim *system; }; -INLINE_DEVICE\ -(device *) -device_create(const char *name, - device *parent) -{ - device_descriptor *descr; - int name_len; - char *chp; - chp = strchr(name, '@'); - name_len = (chp == NULL ? strlen(name) : chp - name); - for (descr = device_table; descr->name != NULL; descr++) { - if (strncmp(name, descr->name, name_len) == 0 - && (descr->name[name_len] == '\0' - || descr->name[name_len] == '@')) { - void *data = (descr->creator != NULL - ? descr->creator(name, parent) - : NULL); - return device_create_from(name, data, descr->callbacks, parent); - } - } - error("device_create() unknown device %s\n", name); - return NULL; -} +/* an instance of a device */ +struct _device_instance { + void *data; + char *args; + char *path; + const device_instance_callbacks *callback; + /* the root instance */ + device *owner; + device_instance *next; + /* interposed instance */ + device_instance *parent; + device_instance *child; +}; -INLINE_DEVICE\ -(device *) -device_create_from(const char *name, - void *data, - const device_callbacks *callbacks, - device *parent) -{ - device *new_device = ZALLOC(device); - new_device->data = data; - new_device->name = strdup(name); - new_device->callback = callbacks; - new_device->parent = parent; - return new_device; -} + +/* Device node: */ INLINE_DEVICE\ (device *) @@ -135,6 +205,13 @@ device_name(device *me) return me->name; } +INLINE_DEVICE\ +(const char *) +device_path(device *me) +{ + return me->path; +} + INLINE_DEVICE\ (void *) device_data(device *me) @@ -143,273 +220,823 @@ device_data(device *me) } INLINE_DEVICE\ -(void) -device_traverse_properties(device *me, - device_traverse_property_function *traverse, - void *data) +(psim *) +device_system(device *me) { - device_property_entry *entry = me->properties; - while (entry != NULL) { - traverse(me, entry->name, data); - entry = entry->next; + return me->system; +} + +INLINE_DEVICE\ +(const device_unit *) +device_unit_address(device *me) +{ + return &me->unit_address; +} + + + +/* device template: */ + +/* determine the full name of the device. If buf is specified it is + stored in there. Failing that, a safe area of memory is allocated */ + +STATIC_INLINE_DEVICE\ +(const char *) +device_full_name(device *leaf, + char *buf, + unsigned sizeof_buf) +{ + /* get a buffer */ + char full_name[1024]; + if (buf == (char*)0) { + buf = full_name; + sizeof_buf = sizeof(full_name); + } + + /* construct a name */ + if (leaf->parent == NULL) { + if (sizeof_buf < 1) + error("device_full_name: buffer overflow\n"); + *buf = '\0'; + } + else { + char unit[1024]; + device_full_name(leaf->parent, buf, sizeof_buf); + if (leaf->parent != NULL + && leaf->parent->callback->convert.encode_unit(leaf->parent, + &leaf->unit_address, + unit+1, + sizeof(unit)-1) > 0) + unit[0] = '@'; + else + unit[0] = '\0'; + if (strlen(buf) + strlen("/") + strlen(leaf->name) + strlen(unit) + >= sizeof_buf) + error("device_full_name: buffer overflow\n"); + strcat(buf, "/"); + strcat(buf, leaf->name); + strcat (buf, unit); + } + + /* return it usefully */ + if (buf == full_name) + buf = strdup(full_name); + return buf; +} + +/* manipulate/lookup device names */ + +typedef struct _name_specifier { + /* components in the full length name */ + char *path; + char *property; + char *value; + /* current device */ + char *name; + char *unit; + char *args; + /* previous device */ + char *last_name; + char *last_unit; + char *last_args; + /* work area */ + char buf[1024]; +} name_specifier; + +/* Given a device specifier, break it up into its main components: + path (and if present) property name and property value. */ +STATIC_INLINE_DEVICE\ +(int) +split_device_specifier(const char *device_specifier, + name_specifier *spec) +{ + char *chp; + if (strlen(device_specifier) >= sizeof(spec->buf)) + error("split_device_specifier: buffer overflow\n"); + + /* expand aliases (later) */ + strcpy(spec->buf, device_specifier); + + /* strip the leading spaces and check that remainder isn't a comment */ + chp = spec->buf; + while (*chp != '\0' && isspace(*chp)) + chp++; + if (*chp == '\0' || *chp == '#') + return 0; + + /* find the path and terminate it with null */ + spec->path = chp; + while (*chp != '\0' && !isspace(*chp)) + chp++; + if (*chp != '\0') { + *chp = '\0'; + chp++; + } + + /* and any value */ + while (*chp != '\0' && isspace(*chp)) + chp++; + spec->value = chp; + + /* now go back and chop the property off of the path */ + if (spec->value[0] == '\0') { + spec->property = NULL; /*not a property*/ + spec->value = NULL; + } + else if (spec->value[0] == '>' + || spec->value[0] == '<') { + /* an interrupt spec */ + spec->property = NULL; + } + else { + chp = strrchr(spec->path, '/'); + if (chp == NULL) { + spec->property = spec->path; + spec->path = strchr(spec->property, '\0'); + } + else { + *chp = '\0'; + spec->property = chp+1; + } + } + + /* and mark the rest as invalid */ + spec->name = NULL; + spec->unit = NULL; + spec->args = NULL; + spec->last_name = NULL; + spec->last_unit = NULL; + spec->last_args = NULL; + + return 1; +} + +/* given a device specifier break it up into its main components - + path and property name - assuming that the last `device' is a + property name. */ +STATIC_INLINE_DEVICE\ +(int) +split_property_specifier(const char *property_specifier, + name_specifier *spec) +{ + if (split_device_specifier(property_specifier, spec)) { + if (spec->property == NULL) { + /* force the last name to be a property name */ + char *chp = strrchr(spec->path, '/'); + if (chp == NULL) { + spec->property = spec->path; + spec->path = strrchr(spec->property, '\0');; + } + else { + *chp = '\0'; + spec->property = chp+1; + } + } + return 1; + } + else + return 0; +} + +/* parse the next device name and split it up, return 0 when no more + names to parse */ +STATIC_INLINE_DEVICE\ +(int) +split_device_name(name_specifier *spec) +{ + char *chp; + /* remember what came before */ + spec->last_name = spec->name; + spec->last_unit = spec->unit; + spec->last_args = spec->args; + /* finished? */ + if (spec->path[0] == '\0') { + spec->name = NULL; + spec->unit = NULL; + spec->args = NULL; + return 0; + } + /* break the device name from the path */ + spec->name = spec->path; + chp = strchr(spec->name, '/'); + if (chp == NULL) + spec->path = strchr(spec->name, '\0'); + else { + spec->path = chp+1; + *chp = '\0'; + } + /* now break out the unit */ + chp = strchr(spec->name, '@'); + if (chp == NULL) { + spec->unit = NULL; + chp = spec->name; + } + else { + *chp = '\0'; + chp += 1; + spec->unit = chp; + } + /* finally any args */ + chp = strchr(chp, ':'); + if (chp == NULL) + spec->args = NULL; + else { + *chp = '\0'; + spec->args = chp+1; + } + return 1; +} + +/* parse the value, returning the next non-space token */ + +STATIC_INLINE_DEVICE\ +(char *) +split_value(name_specifier *spec) +{ + char *token; + if (spec->value == NULL) + return NULL; + /* skip leading white space */ + while (isspace(spec->value[0])) + spec->value++; + if (spec->value[0] == '\0') { + spec->value = NULL; + return NULL; + } + token = spec->value; + /* find trailing space */ + while (spec->value[0] != '\0' && !isspace(spec->value[0])) + spec->value++; + /* chop this value out */ + if (spec->value[0] != '\0') { + spec->value[0] = '\0'; + spec->value++; + } + return token; +} + + + +/* traverse the path specified by spec starting at current */ + +STATIC_INLINE_DEVICE\ +(device *) +split_find_device(device *current, + name_specifier *spec) +{ + /* strip off (and process) any leading ., .., ./ and / */ + while (1) { + if (strncmp(spec->path, "/", strlen("/")) == 0) { + /* cd /... */ + while (current != NULL && current->parent != NULL) + current = current->parent; + spec->path += strlen("/"); + } + else if (strncmp(spec->path, "./", strlen("./")) == 0) { + /* cd ./... */ + current = current; + spec->path += strlen("./"); + } + else if (strncmp(spec->path, "../", strlen("../")) == 0) { + /* cd ../... */ + if (current != NULL && current->parent != NULL) + current = current->parent; + spec->path += strlen("../"); + } + else if (strcmp(spec->path, ".") == 0) { + /* cd . */ + current = current; + spec->path += strlen("."); + } + else if (strcmp(spec->path, "..") == 0) { + /* cd . */ + if (current != NULL && current->parent != NULL) + current = current->parent; + spec->path += strlen(".."); + } + else + break; + } + + /* now go through the path proper */ + + if (current == NULL) { + split_device_name(spec); + return current; + } + + while (split_device_name(spec)) { + device_unit phys; + device *child; + current->callback->convert.decode_unit(current, spec->unit, &phys); + for (child = current->children; child != NULL; child = child->sibling) { + if (strcmp(spec->name, child->name) == 0) { + if (phys.nr_cells == 0 + || memcmp(&phys, &child->unit_address, sizeof(device_unit)) == 0) + break; + } + } + if (child == NULL) + return current; /* search failed */ + current = child; + } + + return current; +} + + +STATIC_INLINE_DEVICE\ +(device *) +device_create_from(const char *name, + const device_unit *unit_address, + void *data, + const device_callbacks *callbacks, + device *parent) +{ + device *new_device = ZALLOC(device); + + /* insert it into the device tree */ + new_device->parent = parent; + new_device->children = NULL; + if (parent != NULL) { + device **sibling = &parent->children; + while ((*sibling) != NULL) + sibling = &(*sibling)->sibling; + *sibling = new_device; + } + + /* give it a name */ + new_device->name = strdup(name); + new_device->unit_address = *unit_address; + new_device->path = device_full_name(new_device, NULL, 0); + + /* its template */ + new_device->data = data; + new_device->callback = callbacks; + + /* its properties - already null */ + /* interrupts - already null */ + + /* mappings - if needed */ + if (parent == NULL) { + new_device->ihandles = cap_create(name); + new_device->phandles = cap_create(name); + } + + return new_device; +} + + +STATIC_INLINE_DEVICE\ +(device *) +device_template_create_device(device *parent, + const char *name, + const char *unit_address, + const char *args) +{ + const device_descriptor *const *table; + int name_len; + char *chp; + chp = strchr(name, '@'); + name_len = (chp == NULL ? strlen(name) : chp - name); + for (table = device_table; *table != NULL; table++) { + const device_descriptor *descr; + for (descr = *table; descr->name != NULL; descr++) { + if (strncmp(name, descr->name, name_len) == 0 + && (descr->name[name_len] == '\0' + || descr->name[name_len] == '@')) { + device_unit address = { 0 }; + void *data = NULL; + if (parent != NULL && parent->callback->convert.decode_unit != NULL) + parent->callback->convert.decode_unit(parent, + unit_address, + &address); + if (descr->creator != NULL) + data = descr->creator(name, &address, args); + return device_create_from(name, &address, data, + descr->callbacks, parent); + } + } } + device_error(parent, "attempt to attach unknown device %s\n", name); + return NULL; } + +/* device-instance: */ + INLINE_DEVICE\ -(void) -device_init(device *me, - psim *system) +(device_instance *) +device_create_instance_from(device *me, + device_instance *parent, + void *data, + const char *path, + const char *args, + const device_instance_callbacks *callbacks) { - me->callback->init(me, system); + device_instance *instance = ZALLOC(device_instance); + if ((me == NULL) == (parent == NULL)) + device_error(me, "can't have both parent instance and parent device\n"); + instance->owner = me; + instance->parent = parent; + instance->data = data; + instance->args = (args == NULL ? NULL : strdup(args)); + instance->path = (path == NULL ? NULL : strdup(path)); + instance->callback = callbacks; + /*instance->unit*/ + if (me != NULL) { + instance->next = me->instances; + me->instances = instance; + } + if (parent != NULL) { + device_instance **previous; + parent->child = instance; + instance->owner = parent->owner; + instance->next = parent->next; + /* replace parent with this new node */ + previous = &instance->owner->instances; + while (*previous != parent) + previous = &(*previous)->next; + *previous = instance; + } + return instance; } + INLINE_DEVICE\ +(device_instance *) +device_create_instance(device *me, + const char *device_specifier) +{ + /* find the device node */ + name_specifier spec; + if (!split_device_specifier(device_specifier, &spec)) + return NULL; + me = split_find_device(me, &spec); + if (spec.name != NULL) + return NULL; + /* create the instance */ + if (me->callback->instance_create == NULL) + device_error(me, "no instance_create method\n"); + return me->callback->instance_create(me, + device_specifier, spec.last_args); +} + +STATIC_INLINE_DEVICE\ (void) -device_attach_address(device *me, - const char *name, - attach_type attach, - int space, - unsigned_word addr, - unsigned nr_bytes, - access_type access, - device *who) /*callback/default*/ +clean_device_instances(device *me) { - me->callback->attach_address(me, name, attach, space, - addr, nr_bytes, access, who); + device_instance **instance = &me->instances; + while (*instance != NULL) { + device_instance *old_instance = *instance; + device_instance_delete(old_instance); + instance = &me->instances; + } } INLINE_DEVICE\ (void) -device_detach_address(device *me, - const char *name, - attach_type attach, - int space, - unsigned_word addr, - unsigned nr_bytes, - access_type access, - device *who) /*callback/default*/ +device_instance_delete(device_instance *instance) { - me->callback->detach_address(me, name, attach, space, - addr, nr_bytes, access, who); + device *me = instance->owner; + device_instance **curr; + if (instance->callback->delete == NULL) + device_error(me, "no delete method\n"); + instance->callback->delete(instance); + if (instance->args != NULL) + zfree(instance->args); + if (instance->path != NULL) + zfree(instance->path); + curr = &me->instances; + while (*curr != NULL && *curr != instance) + curr = &(*curr)->next; + ASSERT(*curr != NULL); + *curr = instance->next; + zfree(instance); } INLINE_DEVICE\ -(unsigned) -device_io_read_buffer(device *me, - void *dest, - int space, - unsigned_word addr, - unsigned nr_bytes, - cpu *processor, - unsigned_word cia) +(int) +device_instance_read(device_instance *instance, + void *addr, + unsigned_word len) { - return me->callback->io_read_buffer(me, dest, space, - addr, nr_bytes, - processor, cia); + device *me = instance->owner; + if (instance->callback->read == NULL) + device_error(me, "no read method\n"); + return instance->callback->read(instance, addr, len); } INLINE_DEVICE\ -(unsigned) -device_io_write_buffer(device *me, - const void *source, - int space, - unsigned_word addr, - unsigned nr_bytes, - cpu *processor, - unsigned_word cia) +(int) +device_instance_write(device_instance *instance, + const void *addr, + unsigned_word len) { - return me->callback->io_write_buffer(me, source, space, - addr, nr_bytes, - processor, cia); + device *me = instance->owner; + if (instance->callback->write == NULL) + device_error(me, "no write method\n"); + return instance->callback->write(instance, addr, len); } INLINE_DEVICE\ -(unsigned) -device_dma_read_buffer(device *me, - void *dest, - int space, - unsigned_word addr, - unsigned nr_bytes) +(int) +device_instance_seek(device_instance *instance, + unsigned_word pos_hi, + unsigned_word pos_lo) { - return me->callback->dma_read_buffer(me, dest, space, - addr, nr_bytes); + device *me = instance->owner; + if (instance->callback->seek == NULL) + device_error(me, "no seek method\n"); + return instance->callback->seek(instance, pos_hi, pos_lo); } INLINE_DEVICE\ -(unsigned) -device_dma_write_buffer(device *me, - const void *source, - int space, - unsigned_word addr, - unsigned nr_bytes, - int violate_read_only_section) +(unsigned_word) +device_instance_claim(device_instance *instance, + unsigned_word address, + unsigned_word length, + unsigned_word alignment) { - return me->callback->dma_write_buffer(me, source, space, - addr, nr_bytes, - violate_read_only_section); + device *me = instance->owner; + if (instance->callback->claim == NULL) + device_error(me, "no claim method\n"); + return instance->callback->claim(instance, address, length, alignment); } INLINE_DEVICE\ (void) -device_attach_interrupt(device *me, - device *who, - int interrupt_line, - const char *name) +device_instance_release(device_instance *instance, + unsigned_word address, + unsigned_word length) { - me->callback->attach_interrupt(me, who, interrupt_line, name); + device *me = instance->owner; + if (instance->callback->release == NULL) + device_error(me, "no release method\n"); + instance->callback->release(instance, address, length); } INLINE_DEVICE\ -(void) -device_detach_interrupt(device *me, - device *who, - int interrupt_line, - const char *name) +(device *) +device_instance_device(device_instance *instance) { - me->callback->detach_interrupt(me, who, interrupt_line, name); + return instance->owner; } INLINE_DEVICE\ -(void) -device_interrupt(device *me, - device *who, - int interrupt_line, - int interrupt_status, - cpu *processor, - unsigned_word cia) +(const char *) +device_instance_path(device_instance *instance) { - me->callback->interrupt(me, who, interrupt_line, interrupt_status, - processor, cia); + return instance->path; } INLINE_DEVICE\ +(void *) +device_instance_data(device_instance *instance) +{ + return instance->data; +} + + + +/* Device initialization: */ + +STATIC_INLINE_DEVICE\ (void) -device_interrupt_ack(device *me, - int interrupt_line, - int interrupt_status) +clean_device(device *root, + void *data) { - me->callback->interrupt_ack(me, interrupt_line, interrupt_status); + psim *system; + system = (psim*)data; + clean_device_interrupt_edges(&root->interrupt_destinations); + clean_device_instances(root); + clean_device_properties(root); } -EXTERN_DEVICE\ +STATIC_INLINE_DEVICE\ (void) -device_ioctl(device *me, - psim *system, - cpu *processor, - unsigned_word cia, - ...) +init_device_address(device *me, + void *data) +{ + psim *system = (psim*)data; + TRACE(trace_device_init, ("init_device_address() initializing %s\n", me->path)); + me->system = system; /* misc things not known until now */ + if (me->callback->init.address != NULL) + me->callback->init.address(me); +} + +STATIC_INLINE_DEVICE\ +(void) +init_device_data(device *me, + void *data) +{ + TRACE(trace_device_init, ("device_init_data() initializing %s\n", me->path)); + if (me->callback->init.data != NULL) + me->callback->init.data(me); +} + +INLINE_DEVICE\ +(void) +device_tree_init(device *root, + psim *system) { - va_list ap; - va_start(ap, cia); - me->callback->ioctl(me, system, processor, cia, ap); - va_end(ap); + TRACE(trace_device_tree, ("device_tree_init(root=0x%lx, system=0x%lx)\n", + (long)root, + (long)system)); + /* remove the old, rebuild the new */ + device_tree_traverse(root, clean_device, NULL, system); + TRACE(trace_tbd, ("Need to dump the device tree here\n")); + device_tree_traverse(root, init_device_address, NULL, system); + device_tree_traverse(root, init_device_properties, NULL, system); + device_tree_traverse(root, init_device_data, NULL, system); + TRACE(trace_device_tree, ("device_tree_init() = void\n")); } - -/* Manipulate properties attached to devices */ + +/* Device Properties: */ + +/* local - not available externally */ STATIC_INLINE_DEVICE\ -(device_property *) +(void) device_add_property(device *me, const char *property, device_property_type type, + const void *init_array, + unsigned sizeof_init_array, const void *array, - int sizeof_array) + unsigned sizeof_array, + const device_property *original, + object_disposition disposition) { - device_property_entry *new_entry = 0; - device_property *new_value = 0; - void *new_array = 0; + device_property_entry *new_entry = NULL; + device_property *new_value = NULL; + void *new_array = NULL; + void *new_init_array = NULL; + /* find the list end */ device_property_entry **insertion_point = &me->properties; while (*insertion_point != NULL) { - if (strcmp((**insertion_point).name, property) == 0) - return (**insertion_point).value; - insertion_point = &(**insertion_point).next; + if (strcmp((*insertion_point)->value->name, property) == 0) + return; + insertion_point = &(*insertion_point)->next; } - /* alloc data for the new property */ - new_entry = ZALLOC(device_property_entry); + + /* create a new value */ new_value = ZALLOC(device_property); - new_array = (sizeof_array > 0 - ? zalloc(sizeof_array) - : (void*)0); - /* insert the new property into the list */ - *insertion_point = new_entry; - new_entry->name = strdup(property); - new_entry->value = new_value; + new_value->name = strdup(property); new_value->type = type; new_value->sizeof_array = sizeof_array; + new_array = (sizeof_array > 0 ? zalloc(sizeof_array) : NULL); new_value->array = new_array; + new_value->owner = me; + new_value->original = original; + new_value->disposition = disposition; if (sizeof_array > 0) memcpy(new_array, array, sizeof_array); - return new_value; -} -INLINE_DEVICE\ -(void) -device_add_array_property(device *me, - const char *property, - const void *array, - int sizeof_array) -{ - TRACE(trace_devices, - ("device_add_array_property(me=0x%lx, property=%s, ...)\n", - (long)me, property)); - device_add_property(me, property, - array_property, array, sizeof_array); + /* insert the value into the list */ + new_entry = ZALLOC(device_property_entry); + *insertion_point = new_entry; + new_entry->sizeof_init_array = sizeof_init_array; + new_init_array = (sizeof_init_array > 0 ? zalloc(sizeof_init_array) : NULL); + new_entry->init_array = new_init_array; + new_entry->value = new_value; + if (sizeof_init_array > 0) + memcpy(new_init_array, init_array, sizeof_init_array); + } -INLINE_DEVICE\ + +/* local - not available externally */ +STATIC_INLINE_DEVICE\ (void) -device_add_integer_property(device *me, - const char *property, - signed32 integer) +device_set_property(device *me, + const char *property, + device_property_type type, + const void *array, + int sizeof_array, + const device_property *original) { - TRACE(trace_devices, - ("device_add_integer_property(me=0x%lx, property=%s, integer=%ld)\n", - (long)me, property, (long)integer)); - H2BE(integer); - device_add_property(me, property, integer_property, - &integer, sizeof(integer)); + /* find the property */ + device_property_entry *entry = me->properties; + while (entry != NULL) { + if (strcmp(entry->value->name, property) == 0) { + void *new_array = 0; + device_property *value = entry->value; + /* check the type matches */ + if (value->type != type) + device_error(me, "conflict between type of new and old value for property %s\n", property); + /* replace its value */ + if (value->array != NULL) + zfree((void*)value->array); + new_array = (sizeof_array > 0 + ? zalloc(sizeof_array) + : (void*)0); + value->array = new_array; + value->sizeof_array = sizeof_array; + if (sizeof_array > 0) + memcpy(new_array, array, sizeof_array); + return; + } + entry = entry->next; + } + device_add_property(me, property, type, + NULL, 0, array, sizeof_array, + original, tempoary_object); } -INLINE_DEVICE\ + +STATIC_INLINE_DEVICE\ (void) -device_add_boolean_property(device *me, - const char *property, - int boolean) +clean_device_properties(device *me) { - signed32 new_boolean = (boolean ? -1 : 0); - TRACE(trace_devices, - ("device_add_boolean(me=0x%lx, property=%s, boolean=%d)\n", - (long)me, property, boolean)); - device_add_property(me, property, boolean_property, - &new_boolean, sizeof(new_boolean)); + device_property_entry **delete_point = &me->properties; + while (*delete_point != NULL) { + device_property_entry *current = *delete_point; + device_property *property = current->value; + switch (current->value->disposition) { + case permenant_object: + { + /* delete the property, and replace it with the original */ + ASSERT(((property->array == NULL) == (current->init_array == NULL)) + || property->type == ihandle_property); + if (current->init_array != NULL) { + zfree((void*)current->value->array); + current->value->array = NULL; + if (property->type != ihandle_property) { + device_set_property(me, property->name, + property->type, + current->init_array, current->sizeof_init_array, + NULL); + } + } + delete_point = &(*delete_point)->next; + } + break; + case tempoary_object: + { + /* zap the actual property, was created during simulation run */ + *delete_point = current->next; + if (current->value->array != NULL) + zfree((void*)current->value->array); + zfree(current->value); + zfree(current); + } + break; + } + } } -INLINE_DEVICE\ + +STATIC_INLINE_DEVICE\ (void) -device_add_null_property(device *me, - const char *property) +init_device_properties(device *me, + void *data) { - TRACE(trace_devices, - ("device_add_null(me=0x%lx, property=%s)\n", - (long)me, property)); - device_add_property(me, property, null_property, - NULL, 0); + device_property_entry *property = me->properties; + while (property != NULL) { + /* now do the phandles */ + if (property->value->type == ihandle_property) { + if (property->value->original != NULL) { + const device_property *original = property->value->original; + if (original->array == NULL) { + init_device_properties(original->owner, data); + } + ASSERT(original->array != NULL); + device_set_property(me, property->value->name, + ihandle_property, + original->array, original->sizeof_array, NULL); + } + else { + device_instance *instance = + device_create_instance(me, (char*)property->init_array); + unsigned32 ihandle = H2BE_4(device_instance_to_external(instance)); + device_set_property(me, property->value->name, + ihandle_property, + &ihandle, sizeof(ihandle), NULL); + } + } + property = property->next; + } } + INLINE_DEVICE\ -(void) -device_add_string_property(device *me, - const char *property, - const char *string) +(const device_property *) +device_next_property(const device_property *property) { - - TRACE(trace_devices, - ("device_add_property(me=0x%lx, property=%s, string=%s)\n", - (long)me, property, string)); - device_add_property(me, property, string_property, - string, strlen(string) + 1); + /* find the property in the list */ + device *owner = property->owner; + device_property_entry *entry = owner->properties; + while (entry != NULL && entry->value != property) + entry = entry->next; + /* now return the following property */ + ASSERT(entry != NULL); /* must be a member! */ + if (entry->next != NULL) + return entry->next->value; + else + return NULL; } INLINE_DEVICE\ @@ -417,35 +1044,23 @@ INLINE_DEVICE\ device_find_property(device *me, const char *property) { - if (me != (device*)0) { - device_property_entry *entry = me->properties; - while (entry != (device_property_entry*)0) { - if (strcmp(entry->name, property) == 0) - return entry->value; - entry = entry->next; - } + name_specifier spec; + if (me == NULL) { + return NULL; } - return (device_property*)0; -} - -INLINE_DEVICE\ -(const char *) -device_find_next_property(device *me, - const char *property) -{ - if (me != NULL) { - if (property == NULL || strcmp(property, "") == 0) { - return (me->properties != NULL - ? me->properties->name - : NULL); - } - else { + else if (property == NULL || strcmp(property, "") == 0) { + if (me->properties == NULL) + return NULL; + else + return me->properties->value; + } + else if (split_property_specifier(property, &spec)) { + me = split_find_device(me, &spec); + if (spec.name == NULL) { /*got to root*/ device_property_entry *entry = me->properties; while (entry != NULL) { - if (strcmp(entry->name, property) == 0) - return (entry->next != NULL - ? entry->next->name - : NULL); + if (strcmp(entry->value->name, spec.property) == 0) + return entry->value; entry = entry->next; } } @@ -453,6 +1068,34 @@ device_find_next_property(device *me, return NULL; } +STATIC_INLINE_DEVICE\ +(void) +device_add_array_property(device *me, + const char *property, + const void *array, + int sizeof_array) +{ + TRACE(trace_devices, + ("device_add_array_property(me=0x%lx, property=%s, ...)\n", + (long)me, property)); + device_add_property(me, property, array_property, + array, sizeof_array, array, sizeof_array, + NULL, permenant_object); +} + +INLINE_DEVICE\ +(void) +device_set_array_property(device *me, + const char *property, + const void *array, + int sizeof_array) +{ + TRACE(trace_devices, + ("device_set_array_property(me=0x%lx, property=%s, ...)\n", + (long)me, property)); + device_set_property(me, property, array_property, array, sizeof_array, NULL); +} + INLINE_DEVICE\ (const device_property *) device_find_array_property(device *me, @@ -465,30 +1108,25 @@ device_find_array_property(device *me, node = device_find_property(me, property); if (node == (device_property*)0 || node->type != array_property) - error("%s property %s not found or of wrong type\n", - me->name, property); + device_error(me, "property %s not found or of wrong type\n", property); return node; } -INLINE_DEVICE\ -(signed_word) -device_find_integer_property(device *me, - const char *property) + +STATIC_INLINE_DEVICE\ +(void) +device_add_boolean_property(device *me, + const char *property, + int boolean) { - const device_property *node; - signed32 integer; + signed32 new_boolean = (boolean ? -1 : 0); TRACE(trace_devices, - ("device_find_integer(me=0x%lx, property=%s)\n", - (long)me, property)); - node = device_find_property(me, property); - if (node == (device_property*)0 - || node->type != integer_property) - error("%s property %s not found or of wrong type\n", - me->name, property); - ASSERT(sizeof(integer) == node->sizeof_array); - memcpy(&integer, node->array, sizeof(integer)); - BE2H(integer); - return integer; + ("device_add_boolean(me=0x%lx, property=%s, boolean=%d)\n", + (long)me, property, boolean)); + device_add_property(me, property, boolean_property, + &new_boolean, sizeof(new_boolean), + &new_boolean, sizeof(new_boolean), + NULL, permenant_object); } INLINE_DEVICE\ @@ -504,727 +1142,828 @@ device_find_boolean_property(device *me, node = device_find_property(me, property); if (node == (device_property*)0 || node->type != boolean_property) - error("%s property %s not found or of wrong type\n", - me->name, property); + device_error(me, "property %s not found or of wrong type\n", property); ASSERT(sizeof(boolean) == node->sizeof_array); memcpy(&boolean, node->array, sizeof(boolean)); return boolean; } +STATIC_INLINE_DEVICE\ +(void) +device_add_ihandle_property(device *me, + const char *property, + const char *path) +{ + TRACE(trace_devices, + ("device_add_ihandle_property(me=0x%lx, property=%s, path=%s)\n", + (long)me, property, path)); + device_add_property(me, property, ihandle_property, + path, strlen(path) + 1, + NULL, 0, + NULL, permenant_object); +} + INLINE_DEVICE\ -(const char *) -device_find_string_property(device *me, - const char *property) +(device_instance *) +device_find_ihandle_property(device *me, + const char *property) { const device_property *node; - const char *string; + unsigned32 ihandle; + device_instance *instance; TRACE(trace_devices, - ("device_find_string(me=0x%lx, property=%s)\n", + ("device_find_ihandle_property(me=0x%lx, property=%s)\n", (long)me, property)); node = device_find_property(me, property); - if (node == (device_property*)0 - || node->type != string_property) - error("%s property %s not found or of wrong type\n", - me->name, property); - string = node->array; - ASSERT(strlen(string) + 1 == node->sizeof_array); - return string; + if (node == NULL || node->type != ihandle_property) + device_error(me, "property %s not found or of wrong type\n", property); + if (node->array == NULL) + device_error(me, "property %s not yet initialized\n", property); + ASSERT(sizeof(ihandle) == node->sizeof_array); + memcpy(&ihandle, node->array, sizeof(ihandle)); + BE2H(ihandle); + instance = external_to_device_instance(me, ihandle); + ASSERT(instance != NULL); + return instance; } - -/* determine the full name of the device. If buf is specified it is - stored in there. Failing that, a safe area of memory is allocated */ STATIC_INLINE_DEVICE\ -(const char *) -device_tree_full_name(device *leaf, - char *buf, - unsigned sizeof_buf) +(void) +device_add_integer_property(device *me, + const char *property, + signed32 integer) { - /* get a buffer */ - char full_name[1024]; - if (buf == (char*)0) { - buf = full_name; - sizeof_buf = sizeof(full_name); - } - - /* construct a name */ - if (leaf->parent == NULL) { - if (sizeof_buf < 1) - error("device_full_name() buffer overflow\n"); - *buf = '\0'; - } - else { - device_tree_full_name(leaf->parent, buf, sizeof_buf); - if (strlen(buf) + strlen("/") + strlen(leaf->name) + 1 > sizeof_buf) - error("device_full_name() buffer overflow\n"); - strcat(buf, "/"); - strcat(buf, leaf->name); - } - - /* return it usefully */ - if (buf == full_name) - buf = strdup(full_name); - return buf; + TRACE(trace_devices, + ("device_add_integer_property(me=0x%lx, property=%s, integer=%ld)\n", + (long)me, property, (long)integer)); + H2BE(integer); + device_add_property(me, property, integer_property, + &integer, sizeof(integer), + &integer, sizeof(integer), + NULL, permenant_object); } - -/* find/create a node in the device tree */ - -typedef enum { - device_tree_return_null = 2, - device_tree_abort = 3, -} device_tree_action; +INLINE_DEVICE\ +(signed_word) +device_find_integer_property(device *me, + const char *property) +{ + const device_property *node; + signed32 integer; + TRACE(trace_devices, + ("device_find_integer(me=0x%lx, property=%s)\n", + (long)me, property)); + node = device_find_property(me, property); + if (node == (device_property*)0 + || node->type != integer_property) + device_error(me, "property %s not found or of wrong type\n", property); + ASSERT(sizeof(integer) == node->sizeof_array); + memcpy(&integer, node->array, sizeof(integer)); + BE2H(integer); + return integer; +} STATIC_INLINE_DEVICE\ -(device *) -device_tree_find_node(device *root, - const char *path, - const char *full_path, - device_tree_action action) +(void) +device_add_string_property(device *me, + const char *property, + const char *string) { - const char *name; - int strlen_name; - device *child; - /* strip off any leading `/', `../' or `./' */ - while (1) { - if (strncmp(path, "/", strlen("/")) == 0) { - while (root != NULL && root->parent != NULL) - root = root->parent; - path += strlen("/"); - } - else if (strncmp(path, "./", strlen("./")) == 0) { - root = root; - path += strlen("./"); - } - else if (strncmp(path, "../", strlen("../")) == 0) { - if (root != NULL && root->parent != NULL) - root = root->parent; - path += strlen("../"); - } - else { - break; - } - } - - /* parse the driver_name/unit-address */ - ASSERT(*path != '/'); - name = path; - while (isalnum(*path) - || *path == ',' || *path == ',' || *path == '_' - || *path == '+' || *path == '-') - path++; - if ((*path != '/' && *path != '@' && *path != ':' && *path != '\0') - || (name == path && *name != '\0')) - error("device_tree: path %s invalid at %s\n", full_path, path); - - /* parse the unit-address */ - if (*path == '@') { - path++; - while ((*path != '\0' && *path != ':' && *path != '/') - || (*path == ':' && path[-1] == '\\') - || (*path == '/' && path[-1] == '\\')) - path++; - } - strlen_name = path - name; - - /* skip the device-arguments */ - if (*path == ':') { - path++; - while ((*path != '\0' && *path != '/' && *path != ':' && *path != '@') - || (*path == '/' && path[-1] == '\\') - || (*path == ':' && path[-1] == '\\') - || (*path == '@' && path[-1] == '\\')) - path++; - } - - /* sanity checks */ - if (*path != '\0' && *path != '/') - error("device_tree: path %s invalid at %s\n", full_path, path); + TRACE(trace_devices, + ("device_add_property(me=0x%lx, property=%s, string=%s)\n", + (long)me, property, string)); + device_add_property(me, property, string_property, + string, strlen(string) + 1, + string, strlen(string) + 1, + NULL, permenant_object); +} - /* leaf? and growing? */ - if (name[0] == '\0') { - return root; - } - else if (root != NULL) { - for (child = root->children; - child != NULL; - child = child->sibling) { - if (strncmp(name, child->name, strlen_name) == 0 - && strlen(child->name) >= strlen_name - && (child->name[strlen_name] == '\0' - || child->name[strlen_name] == '@')) { - if (*path == '\0') - return child; - else - return device_tree_find_node(child, - path + 1/* / */, - full_path, - action); - } - } - } +INLINE_DEVICE\ +(const char *) +device_find_string_property(device *me, + const char *property) +{ + const device_property *node; + const char *string; + TRACE(trace_devices, + ("device_find_string(me=0x%lx, property=%s)\n", + (long)me, property)); + node = device_find_property(me, property); + if (node == (device_property*)0 + || node->type != string_property) + device_error(me, "property %s not found or of wrong type\n", property); + string = node->array; + ASSERT(strlen(string) + 1 == node->sizeof_array); + return string; +} - /* search failed, take default action */ - switch (action) { - case device_tree_return_null: - return NULL; - case device_tree_abort: - error("device_tree_find_node() could not find %s in tree\n", - full_path); - return NULL; - default: - error("device_tree_find_node() invalid default action %d\n", action); - return NULL; - } +STATIC_INLINE_DEVICE\ +(void) +device_add_duplicate_property(device *me, + const char *property, + const device_property *original) +{ + TRACE(trace_devices, + ("device_add_duplicate_property(me=0x%lx, property=%s, ...)\n", + (long)me, property)); + if (original->disposition != permenant_object) + device_error(me, "Can only duplicate permenant objects\n"); + device_add_property(me, property, + original->type, + original->array, original->sizeof_array, + original->array, original->sizeof_array, + original, permenant_object); } -/* grow the device tree */ + +/* Device Hardware: */ INLINE_DEVICE\ -(device *) -device_tree_add_device(device *root, - const char *prefix, - device *new_sub_tree) +(unsigned) +device_io_read_buffer(device *me, + void *dest, + int space, + unsigned_word addr, + unsigned nr_bytes, + cpu *processor, + unsigned_word cia) { - device *parent; - TRACE(trace_device_tree, - ("device_tree_add_device(root=0x%lx, prefix=%s, dev=0x%lx)\n", - (long)root, prefix, (long)new_sub_tree)); - - /* find our parent */ - parent = device_tree_find_node(root, - prefix, - prefix, /* full-path */ - device_tree_abort); - - /* create/insert a new child */ - new_sub_tree->parent = parent; - if (parent != NULL) { - device **sibling = &parent->children; - while ((*sibling) != NULL) - sibling = &(*sibling)->sibling; - *sibling = new_sub_tree; - } - - return new_sub_tree; + if (me->callback->io.read_buffer == NULL) + device_error(me, "no io_read_buffer method\n"); + return me->callback->io.read_buffer(me, dest, space, + addr, nr_bytes, + processor, cia); } INLINE_DEVICE\ -(device *) -device_tree_find_device(device *root, - const char *path) +(unsigned) +device_io_write_buffer(device *me, + const void *source, + int space, + unsigned_word addr, + unsigned nr_bytes, + cpu *processor, + unsigned_word cia) { - device *node; - TRACE(trace_device_tree, - ("device_tree_find_device_tree(root=0x%lx, path=%s)\n", - (long)root, path)); - node = device_tree_find_node(root, - path, - path, /* full-name */ - device_tree_return_null); - return node; + if (me->callback->io.write_buffer == NULL) + device_error(me, "no io_write_buffer method\n"); + return me->callback->io.write_buffer(me, source, space, + addr, nr_bytes, + processor, cia); } - -/* init all the devices */ - -STATIC_INLINE_DEVICE\ -(void) -device_tree_init_device(device *root, - void *data) +INLINE_DEVICE\ +(unsigned) +device_dma_read_buffer(device *me, + void *dest, + int space, + unsigned_word addr, + unsigned nr_bytes) { - psim *system; - system = (psim*)data; - TRACE(trace_device_tree, - ("device_tree_init() initializing device=0x%lx:%s\n", - (long)root, root->full_name)); - device_init(root, system); + if (me->callback->dma.read_buffer == NULL) + device_error(me, "no dma_read_buffer method\n"); + return me->callback->dma.read_buffer(me, dest, space, + addr, nr_bytes); } - INLINE_DEVICE\ -(void) -device_tree_init(device *root, - psim *system) +(unsigned) +device_dma_write_buffer(device *me, + const void *source, + int space, + unsigned_word addr, + unsigned nr_bytes, + int violate_read_only_section) { - TRACE(trace_device_tree, - ("device_tree_init(root=0x%lx, system=0x%lx)\n", (long)root, (long)system)); - device_tree_traverse(root, device_tree_init_device, NULL, system); - TRACE(trace_device_tree, - ("device_tree_init() = void\n")); + if (me->callback->dma.write_buffer == NULL) + device_error(me, "no dma_write_buffer method\n"); + return me->callback->dma.write_buffer(me, source, space, + addr, nr_bytes, + violate_read_only_section); } - -/* traverse a device tree applying prefix/postfix functions to it */ - INLINE_DEVICE\ (void) -device_tree_traverse(device *root, - device_tree_traverse_function *prefix, - device_tree_traverse_function *postfix, - void *data) +device_attach_address(device *me, + const char *name, + attach_type attach, + int space, + unsigned_word addr, + unsigned nr_bytes, + access_type access, + device *who) /*callback/default*/ { - device *child; - if (prefix != NULL) - prefix(root, data); - for (child = root->children; child != NULL; child = child->sibling) { - device_tree_traverse(child, prefix, postfix, data); - } - if (postfix != NULL) - postfix(root, data); + if (me->callback->address.attach == NULL) + device_error(me, "no address_attach method\n"); + me->callback->address.attach(me, name, attach, space, + addr, nr_bytes, access, who); } - -/* dump out a device node and addresses */ - INLINE_DEVICE\ (void) -device_tree_dump(device *device, - void *ignore_data_argument) +device_detach_address(device *me, + const char *name, + attach_type attach, + int space, + unsigned_word addr, + unsigned nr_bytes, + access_type access, + device *who) /*callback/default*/ { - printf_filtered("(device_tree@0x%lx\n", (long)device); - printf_filtered(" (parent 0x%lx)\n", (long)device->parent); - printf_filtered(" (children 0x%lx)\n", (long)device->children); - printf_filtered(" (sibling 0x%lx)\n", (long)device->sibling); - printf_filtered(" (name %s)\n", device->name); - error("FIXME - need to print out properties\n"); - printf_filtered(")\n"); + if (me->callback->address.detach == NULL) + device_error(me, "no address_detach method\n"); + me->callback->address.detach(me, name, attach, space, + addr, nr_bytes, access, who); } -/* lookup/create a device various formats */ + +/* Interrupts: */ -STATIC_INLINE_DEVICE\ -(void) -u_strcat(char *buf, - unsigned_word uw) +INLINE_DEVICE(void) +device_interrupt_event(device *me, + int my_port, + int level, + cpu *processor, + unsigned_word cia) { - if (MASKED64(uw, 32, 63) == uw - || WITH_HOST_WORD_BITSIZE == 64) { - char *end = strchr(buf, '\0'); - sprintf(end, "0x%x", (unsigned)uw); - } - else { - char *end = strchr(buf, '\0'); - sprintf(end, "0x%x%08x", - (unsigned)EXTRACTED64(uw, 0, 31), - (unsigned)EXTRACTED64(uw, 32, 63)); + int found_an_edge = 0; + device_interrupt_edge *edge; + /* device's interrupt lines directly connected */ + for (edge = me->interrupt_destinations; + edge != NULL; + edge = edge->next) { + if (edge->my_port == my_port) { + if (edge->dest->callback->interrupt.event == NULL) + device_error(me, "no interrupt method\n"); + edge->dest->callback->interrupt.event(edge->dest, + edge->dest_port, + me, + my_port, + level, + processor, cia); + found_an_edge = 1; + } } -} - -STATIC_INLINE_DEVICE\ -(void) -c_strcat(char *buf, - const char *c) -{ - char *end = strchr(buf, '\0'); - while (*c) { - if (*c == '/' || *c == ',') - *end++ = '\\'; - *end++ = *c++; + if (!found_an_edge) { + device_error(me, "No interrupt edge for port %d\n", my_port); } - *end = '\0'; } INLINE_DEVICE\ -(device *) -device_tree_add_found(device *root, - const char *prefix, - const char *name) +(void) +device_interrupt_attach(device *me, + int my_port, + device *dest, + int dest_port, + object_disposition disposition) { - device *parent; - device *new_device; - device *new_node; - TRACE(trace_device_tree, - ("device_tree_add_found(root=0x%lx, prefix=%s, name=%lx)\n", - (unsigned long)root, prefix, (unsigned long)name)); - parent = device_tree_find_node(root, prefix, prefix, - device_tree_abort); - new_device = device_tree_find_device(parent, name); - if (new_device != NULL) - return new_device; - else { - new_device = device_create(name, parent); - new_node = device_tree_add_device(parent, "", new_device); - ASSERT(new_device == new_node); - return new_node; - } + attach_device_interrupt_edge(&me->interrupt_destinations, + my_port, + dest, + dest_port, + disposition); } INLINE_DEVICE\ -(device *) -device_tree_add_found_c(device *root, - const char *prefix, - const char *name, - const char *c1) +(void) +device_interrupt_detach(device *me, + int my_port, + device *dest, + int dest_port) { - char buf[1024]; - strcpy(buf, name); - strcat(buf, "@"); - c_strcat(buf, c1); - if (strlen(buf) + 1 >= sizeof(buf)) - error("device_tree_add_found_c - buffer overflow\n"); - return device_tree_add_found(root, prefix, buf); + detach_device_interrupt_edge(me, + &me->interrupt_destinations, + my_port, + dest, + dest_port); } INLINE_DEVICE\ -(device *) -device_tree_add_found_c_uw(device *root, - const char *prefix, - const char *name, - const char *c1, - unsigned_word uw2) +(int) +device_interrupt_decode(device *me, + const char *port_name) { - char buf[1024]; - strcpy(buf, name); - strcat(buf, "@"); - c_strcat(buf, c1); - strcat(buf, ","); - u_strcat(buf, uw2); - if (strlen(buf) + 1 >= sizeof(buf)) - error("device_tree_add_found_* - buffer overflow\n"); - return device_tree_add_found(root, prefix, buf); + if (port_name == NULL || port_name[0] == '\0') + return 0; + if (isdigit(port_name[0])) { + return strtoul(port_name, NULL, 0); + } + else { + const device_interrupt_port_descriptor *ports = + me->callback->interrupt.ports; + if (ports != NULL) { + while (ports->name != NULL) { + if (ports->bound > ports->number) { + int len = strlen(ports->name); + if (strncmp(port_name, ports->name, len) == 0) { + if (port_name[len] == '\0') + return ports->number; + else if(isdigit(port_name[len])) { + int port = ports->number + strtoul(&port_name[len], NULL, 0); + if (port >= ports->bound) + device_error(me, "Interrupt port %s out of range\n", + port_name); + return port; + } + } + } + else if (strcmp(port_name, ports->name) == 0) + return ports->number; + ports++; + } + } + } + device_error(me, "Unreconized interrupt port %s\n", port_name); + return 0; } INLINE_DEVICE\ -(device *) -device_tree_add_found_uw_u(device *root, - const char *prefix, - const char *name, - unsigned_word uw1, - unsigned u2) +(int) +device_interrupt_encode(device *me, + int port_number, + char *buf, + int sizeof_buf) { - char buf[1024]; - strcpy(buf, name); - strcat(buf, "@"); - u_strcat(buf, uw1); - strcat(buf, ","); - u_strcat(buf, u2); - if (strlen(buf) + 1 >= sizeof(buf)) - error("device_tree_add_found_* - buffer overflow\n"); - return device_tree_add_found(root, prefix, buf); + const device_interrupt_port_descriptor *ports = NULL; + ports = me->callback->interrupt.ports; + if (ports != NULL) { + while (ports->name != NULL) { + if (ports->bound > ports->number) { + if (port_number >= ports->number + && port_number < ports->bound) { + strcpy(buf, ports->name); + sprintf(buf + strlen(buf), "%d", port_number - ports->number); + if (strlen(buf) >= sizeof_buf) + error("device_interrupt_encode:buffer overflow\n"); + return strlen(buf); + } + } + else { + if (ports->number == port_number) { + if (strlen(ports->name) >= sizeof_buf) + error("device_interrupt_encode: buffer overflow\n"); + strcpy(buf, ports->name); + return strlen(buf); + } + } + ports++; + } + } + sprintf(buf, "%d", port_number); + if (strlen(buf) >= sizeof_buf) + error("device_interrupt_encode: buffer overflow\n"); + return strlen(buf); } -INLINE_DEVICE\ -(device *) -device_tree_add_found_uw_u_u(device *root, - const char *prefix, - const char *name, - unsigned_word uw1, - unsigned u2, - unsigned u3) -{ - char buf[1024]; - strcpy(buf, name); - strcat(buf, "@"); - u_strcat(buf, uw1); - strcat(buf, ","); - u_strcat(buf, u2); - strcat(buf, ","); - u_strcat(buf, u3); - if (strlen(buf) + 1 >= sizeof(buf)) - error("device_tree_add_found_* - buffer overflow\n"); - return device_tree_add_found(root, prefix, buf); -} -INLINE_DEVICE\ -(device *) -device_tree_add_found_uw_u_u_c(device *root, - const char *prefix, - const char *name, - unsigned_word uw1, - unsigned u2, - unsigned u3, - const char *c4) + +/* IOCTL: */ + +EXTERN_DEVICE\ +(int) +device_ioctl(device *me, + cpu *processor, + unsigned_word cia, + ...) { - char buf[1024]; - strcpy(buf, name); - strcat(buf, "@"); - u_strcat(buf, uw1); - strcat(buf, ","); - u_strcat(buf, u2); - strcat(buf, ","); - u_strcat(buf, u3); - strcat(buf, ","); - c_strcat(buf, c4); - if (strlen(buf) + 1 >= sizeof(buf)) - error("device_tree_add_found_* - buffer overflow\n"); - return device_tree_add_found(root, prefix, buf); + int status; + va_list ap; + va_start(ap, cia); + if (me->callback->ioctl == NULL) + device_error(me, "no ioctl method\n"); + status = me->callback->ioctl(me, processor, cia, ap); + va_end(ap); + return status; } + -INLINE_DEVICE\ -(device *) -device_tree_add_found_uw_uw_u_u_c(device *root, - const char *prefix, - const char *name, - unsigned_word uw1, - unsigned_word uw2, - unsigned u3, - unsigned u4, - const char *c5) + +/* I/O */ + +EXTERN_DEVICE\ +(void volatile) +device_error(device *me, + const char *fmt, + ...) { - char buf[1024]; - strcpy(buf, name); - strcat(buf, "@"); - u_strcat(buf, uw1); - strcat(buf, ","); - u_strcat(buf, uw2); - strcat(buf, ","); - u_strcat(buf, u3); - strcat(buf, ","); - u_strcat(buf, u4); - strcat(buf, ","); - c_strcat(buf, c5); - if (strlen(buf) + 1 >= sizeof(buf)) - error("device_tree_add_found_* - buffer overflow\n"); - return device_tree_add_found(root, prefix, buf); + char message[1024]; + va_list ap; + /* format the message */ + va_start(ap, fmt); + vsprintf(message, fmt, ap); + va_end(ap); + /* sanity check */ + if (strlen(message) >= sizeof(message)) + error("device_error: buffer overflow\n"); + if (me == NULL) + error("device: %s\n", message); + else + error("%s: %s\n", me->path, message); + while(1); } -INLINE_DEVICE\ + +/* Tree utilities: */ + +EXTERN_DEVICE\ (device *) -device_tree_add_found_uw_uw_u_u_u(device *root, - const char *prefix, - const char *name, - unsigned_word uw1, - unsigned_word uw2, - unsigned u3, - unsigned u4, - unsigned u5) +device_tree_add_parsed(device *current, + const char *fmt, + ...) { - char buf[1024]; - strcpy(buf, name); - strcat(buf, "@"); - u_strcat(buf, uw1); - strcat(buf, ","); - u_strcat(buf, uw2); - strcat(buf, ","); - u_strcat(buf, u3); - strcat(buf, ","); - u_strcat(buf, u4); - strcat(buf, ","); - u_strcat(buf, u5); - if (strlen(buf) + 1 >= sizeof(buf)) - error("device_tree_add_found_* - buffer overflow\n"); - return device_tree_add_found(root, prefix, buf); -} - - -/* Parse a device name, various formats */ - -#define SCAN_INIT(NAME) \ - char *START = (char*)0; \ - char *END = (char*)0; \ - int COUNT = -1; \ - /* find the first element */ \ - END = strchr(NAME, '@'); \ - if (END == (char*)0) \ - return COUNT; \ - COUNT += 1; \ - START = END + 1 - -#define SCAN_END \ - return COUNT - -#define SCAN_U(U) \ -do { \ - *U = strtoul(START, &END, 0); \ - if (START == END) \ - return COUNT; \ - COUNT += 1; \ - if (*END != ',') \ - return COUNT; \ - START = END + 1; \ -} while (0) - -#define SCAN_P(P) \ -do { \ - *P = (void*)(unsigned)strtouq(START, END, 0); \ - if (START == END) \ - return COUNT; \ - COUNT += 1; \ - if (*END != ',') \ - return COUNT; \ - START = END + 1; \ -} while (0) - -#define SCAN_C(C, SIZE) \ -do { \ - char *chp = C; \ - END = START; \ - while (*END != '\0' && *END != ',') { \ - if (*END == '\\') \ - END += 1; \ - *chp = *END; \ - chp += 1; \ - END += 1; \ - if ((SIZE) <= ((END) - (START))) \ - return COUNT; /* overflow */ \ - } \ - *chp = '\0'; \ - if (START == END) \ - return COUNT; \ - COUNT += 1; \ - if (*END != ',') \ - return COUNT; \ - START = END + 1; \ -} while (0) + char device_specifier[1024]; + name_specifier spec; + + /* format the path */ + { + va_list ap; + va_start(ap, fmt); + vsprintf(device_specifier, fmt, ap); + va_end(ap); + if (strlen(device_specifier) >= sizeof(device_specifier)) + error("device_tree_add_parsed: buffer overflow\n"); + } -INLINE_DEVICE\ -(int) -scand_c(const char *name, - char *c1, - unsigned c1size) -{ - SCAN_INIT(name); - SCAN_C(c1, c1size); - SCAN_END; -} + /* break it up */ + if (!split_device_specifier(device_specifier, &spec)) + device_error(current, "error parsing %s\n", device_specifier); -INLINE_DEVICE\ -(int) -scand_c_uw_u(const char *name, - char *c1, - unsigned c1size, - unsigned_word *uw2, - unsigned *u3) -{ - SCAN_INIT(name); - SCAN_C(c1, c1size); - SCAN_U(uw2); - SCAN_U(u3); - SCAN_END; -} + /* fill our tree with its contents */ + current = split_find_device(current, &spec); -INLINE_DEVICE\ -(int) -scand_uw(const char *name, - unsigned_word *uw1) -{ - SCAN_INIT(name); - SCAN_U(uw1); - SCAN_END; + /* add any additional devices as needed */ + if (spec.name != NULL) { + do { + current = + device_template_create_device(current, spec.name, spec.unit, spec.args); + } while (split_device_name(&spec)); + } + + /* is there an interrupt spec */ + if (spec.property == NULL + && spec.value != NULL) { + char *op = split_value(&spec); + switch (op[0]) { + case '>': + { + char *my_port_name = split_value(&spec); + char *dest_port_name = split_value(&spec); + device *dest = device_tree_find_device(current, split_value(&spec)); + int my_port = device_interrupt_decode(current, my_port_name); + int dest_port = device_interrupt_decode(dest, dest_port_name); + device_interrupt_attach(current, + my_port, + dest, + dest_port, + permenant_object); + } + break; + default: + device_error(current, "unreconised interrupt spec %s\n", spec.value); + break; + } + } + + /* is there a property */ + if (spec.property != NULL) { + if (strcmp(spec.value, "true") == 0) + device_add_boolean_property(current, spec.property, 1); + else if (strcmp(spec.value, "false") == 0) + device_add_boolean_property(current, spec.property, 0); + else { + const device_property *property; + switch (spec.value[0]) { + case '*': + { + spec.value++; + device_add_ihandle_property(current, spec.property, spec.value); + } + break; + case '-': case '+': + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + { + unsigned long ul = strtoul(spec.value, &spec.value, 0); + device_add_integer_property(current, spec.property, ul); + } + break; + case '[': + { + unsigned8 words[1024]; + char *curr = spec.value + 1; + int nr_words = 0; + while (1) { + char *next; + words[nr_words] = H2BE_1(strtoul(curr, &next, 0)); + if (curr == next) + break; + curr = next; + nr_words += 1; + } + device_add_array_property(current, spec.property, + words, sizeof(words[0]) * nr_words); + } + break; + case '{': + { + unsigned32 words[1024]; + char *curr = spec.value + 1; + int nr_words = 0; + while (1) { + char *next; + words[nr_words] = H2BE_4(strtoul(curr, &next, 0)); + if (curr == next) + break; + curr = next; + nr_words += 1; + } + device_add_array_property(current, spec.property, + words, sizeof(words[0]) * nr_words); + } + break; + case '"': + spec.value++; + default: + device_add_string_property(current, spec.property, spec.value); + break; + case '!': + spec.value++; + property = device_find_property(current, spec.value); + if (property == NULL) + device_error(current, "property %s not found\n", spec.value); + device_add_duplicate_property(current, + spec.property, + property); + break; + } + } + } + return current; } INLINE_DEVICE\ -(int) -scand_uw_c(const char *name, - unsigned_word *uw1, - char *c2, - unsigned c2size) +(void) +device_tree_traverse(device *root, + device_tree_traverse_function *prefix, + device_tree_traverse_function *postfix, + void *data) { - SCAN_INIT(name); - SCAN_U(uw1); - SCAN_C(c2, c2size); - SCAN_END; + device *child; + if (prefix != NULL) + prefix(root, data); + for (child = root->children; child != NULL; child = child->sibling) { + device_tree_traverse(child, prefix, postfix, data); + } + if (postfix != NULL) + postfix(root, data); } INLINE_DEVICE\ -(int) -scand_uw_u(const char *name, - unsigned_word *uw1, - unsigned *u2) +(void) +device_tree_print_device(device *me, + void *ignore_or_null) { - SCAN_INIT(name); - SCAN_U(uw1); - SCAN_U(u2); - SCAN_END; + const device_property *property; + device_interrupt_edge *interrupt_edge; + /* output my name */ + printf_filtered("%s\n", me->path); + /* properties */ + for (property = device_find_property(me, NULL); + property != NULL; + property = device_next_property(property)) { + printf_filtered("%s/%s", me->path, property->name); + if (property->original != NULL) { + printf_filtered(" !"); + printf_filtered("%s/%s\n", property->original->owner->path, + property->original->name); + } + else { + switch (property->type) { + case array_property: + { + if ((property->sizeof_array % sizeof(unsigned32)) == 0) { + unsigned32 *w = (unsigned32*)property->array; + printf_filtered(" {"); + while ((char*)w - (char*)property->array < property->sizeof_array) { + printf_filtered(" 0x%lx", BE2H_4(*w)); + w++; + } + } + else { + unsigned8 *w = (unsigned8*)property->array; + printf_filtered(" ["); + while ((char*)w - (char*)property->array < property->sizeof_array) { + printf_filtered(" 0x%2x", BE2H_1(*w)); + w++; + } + } + printf_filtered("\n"); + } + break; + case boolean_property: + { + int b = device_find_boolean_property(me, property->name); + printf_filtered(" %s\n", b ? "true" : "false"); + } + break; + case ihandle_property: + { + if (property->array != NULL) { + device_instance *i = device_find_ihandle_property(me, property->name); + printf_filtered(" *%s\n", i->path); + } + else { + /* drats, the instance hasn't yet been created. Grub + around and find the path that will be used to create + the ihandle */ + device_property_entry *entry = me->properties; + while (entry->value != property) { + entry = entry->next; + ASSERT(entry != NULL); + } + ASSERT(entry->init_array != NULL); + printf_filtered(" *%s\n", (char*)entry->init_array); + } + } + break; + case integer_property: + { + unsigned_word w = device_find_integer_property(me, property->name); + printf_filtered(" 0x%lx\n", (unsigned long)w); + } + break; + case string_property: + { + const char *s = device_find_string_property(me, property->name); + printf_filtered(" \"%s\n", s); + } + break; + } + } + } + /* interrupts */ + for (interrupt_edge = me->interrupt_destinations; + interrupt_edge != NULL; + interrupt_edge = interrupt_edge->next) { + char src[32]; + char dst[32]; + device_interrupt_encode(me, interrupt_edge->my_port, src, sizeof(src)); + device_interrupt_encode(interrupt_edge->dest, + interrupt_edge->dest_port, dst, sizeof(dst)); + printf_filtered("%s > %s %s %s\n", + me->path, + src, dst, + interrupt_edge->dest->path); + } } INLINE_DEVICE\ -(int) -scand_uw_u_u(const char *name, - unsigned_word *uw1, - unsigned *u2, - unsigned *u3) +(device *) +device_tree_find_device(device *root, + const char *path) { - SCAN_INIT(name); - SCAN_U(uw1); - SCAN_U(u2); - SCAN_U(u3); - SCAN_END; + device *node; + name_specifier spec; + TRACE(trace_device_tree, + ("device_tree_find_device_tree(root=0x%lx, path=%s)\n", + (long)root, path)); + /* parse the path */ + split_device_specifier(path, &spec); + if (spec.value != NULL) + return NULL; /* something wierd */ + + /* now find it */ + node = split_find_device(root, &spec); + if (spec.name != NULL) + return NULL; /* not a leaf */ + + return node; } INLINE_DEVICE\ -(int) -scand_uw_u_u_c(const char *name, - unsigned_word *uw1, - unsigned *u2, - unsigned *u3, - char *c4, - unsigned c4size) +(void) +device_usage(int verbose) { - SCAN_INIT(name); - SCAN_U(uw1); - SCAN_U(u2); - SCAN_U(u3); - SCAN_C(c4, c4size); - SCAN_END; + if (verbose == 1) { + const device_descriptor *const *table; + int pos; + printf_filtered("\n"); + printf_filtered("A device/property specifier has the form:\n"); + printf_filtered("\n"); + printf_filtered(" /path/to/a/device [ property-value ]\n"); + printf_filtered("\n"); + printf_filtered("and a possible device is\n"); + printf_filtered("\n"); + pos = 0; + for (table = device_table; *table != NULL; table++) { + const device_descriptor *descr; + for (descr = *table; descr->name != NULL; descr++) { + pos += strlen(descr->name) + 2; + if (pos > 75) { + pos = strlen(descr->name) + 2; + printf_filtered("\n"); + } + printf_filtered(" %s", descr->name); + } + printf_filtered("\n"); + } + } + if (verbose > 1) { + const device_descriptor *const *table; + printf_filtered("\n"); + printf_filtered("A device/property specifier () has the format:\n"); + printf_filtered("\n"); + printf_filtered(" ::= [ ] ;\n"); + printf_filtered(" ::= { } { \"/\" } ;\n"); + printf_filtered(" ::= ( | \"/\" | \"../\" | \"./\" ) ;\n"); + printf_filtered(" ::= [ \"@\" ] [ \":\" ] ;\n"); + printf_filtered(" ::= { \",\" } ;\n"); + printf_filtered("\n"); + printf_filtered("Where:\n"); + printf_filtered("\n"); + printf_filtered(" is the name of a device (list below)\n"); + printf_filtered(" is the unit-address relative to the parent bus\n"); + printf_filtered(" additional arguments used when creating the device\n"); + printf_filtered(" ::= ( # integer property\n"); + printf_filtered(" | \"[\" { } # array property (byte)\n"); + printf_filtered(" | \"{\" { } # array property (cell)\n"); + printf_filtered(" | [ \"true\" | \"false\" ] # boolean property\n"); + printf_filtered(" | \"*\" # ihandle property\n"); + printf_filtered(" | \"!\" # copy property\n"); + printf_filtered(" | \">\" [ ] # attach interrupt\n"); + printf_filtered(" | \"<\" # attach child interrupt\n"); + printf_filtered(" | \"\\\"\" # string property\n"); + printf_filtered(" | # string property\n"); + printf_filtered(" ) ;\n"); + printf_filtered("\n"); + printf_filtered("And the following are valid device names:\n"); + printf_filtered("\n"); + for (table = device_table; *table != NULL; table++) { + const device_descriptor *descr; + for (descr = *table; descr->name != NULL; descr++) { + printf_filtered(" %s:\n", descr->name); + /* interrupt ports */ + if (descr->callbacks->interrupt.ports != NULL) { + const device_interrupt_port_descriptor *ports = + descr->callbacks->interrupt.ports; + printf_filtered(" interrupt ports:"); + while (ports->name != NULL) { + printf_filtered(" %s", ports->name); + ports++; + } + printf_filtered("\n"); + } + /* general info */ + if (descr->callbacks->usage != NULL) + descr->callbacks->usage(verbose); + } + } + } } + + +/* External representation */ + INLINE_DEVICE\ -(int) -scand_uw_uw(const char *name, - unsigned_word *uw1, - unsigned_word *uw2) +(device *) +external_to_device(device *tree_member, + unsigned32 phandle) { - SCAN_INIT(name); - SCAN_U(uw1); - SCAN_U(uw2); - SCAN_END; + device *root = device_tree_find_device(tree_member, "/"); + device *me = cap_internal(root->phandles, phandle); + return me; } INLINE_DEVICE\ -(int) -scand_uw_uw_u(const char *name, - unsigned_word *uw1, - unsigned_word *uw2, - unsigned *u3) +(unsigned32) +device_to_external(device *me) { - SCAN_INIT(name); - SCAN_U(uw1); - SCAN_U(uw2); - SCAN_U(u3); - SCAN_END; + device *root = device_tree_find_device(me, "/"); + unsigned32 phandle = cap_external(root->phandles, me); + return phandle; } INLINE_DEVICE\ -(int) -scand_uw_uw_u_u_c(const char *name, - unsigned_word *uw1, - unsigned_word *uw2, - unsigned *u3, - unsigned *u4, - char *c5, - unsigned c5size) -{ - SCAN_INIT(name); - SCAN_U(uw1); - SCAN_U(uw2); - SCAN_U(u3); - SCAN_U(u4); - SCAN_C(c5, c5size); - SCAN_END; +(device_instance *) +external_to_device_instance(device *tree_member, + unsigned32 ihandle) +{ + device *root = device_tree_find_device(tree_member, "/"); + device_instance *instance = cap_internal(root->ihandles, ihandle); + return instance; } INLINE_DEVICE\ -(int) -scand_uw_uw_u_u_u(const char *name, - unsigned_word *uw1, - unsigned_word *uw2, - unsigned *u3, - unsigned *u4, - unsigned *u5) -{ - SCAN_INIT(name); - SCAN_U(uw1); - SCAN_U(uw2); - SCAN_U(u3); - SCAN_U(u4); - SCAN_U(u5); - SCAN_END; +(unsigned32) +device_instance_to_external(device_instance *instance) +{ + device *root = device_tree_find_device(instance->owner, "/"); + unsigned32 ihandle = cap_external(root->ihandles, instance); + return ihandle; } - #endif /* _DEVICE_C_ */ diff --git a/sim/ppc/device.h b/sim/ppc/device.h index cc6bd5373ed..4fa5a9d2057 100644 --- a/sim/ppc/device.h +++ b/sim/ppc/device.h @@ -1,6 +1,6 @@ /* This file is part of the program psim. - Copyright (C) 1994-1995, Andrew Cagney + Copyright (C) 1994-1996, Andrew Cagney This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -19,417 +19,396 @@ */ -#ifndef _DEVICE_TREE_H_ -#define _DEVICE_TREE_H_ +#ifndef _DEVICE_H_ +#define _DEVICE_H_ #ifndef INLINE_DEVICE #define INLINE_DEVICE #endif - - /* declared in basics.h, this object is used everywhere */ /* typedef struct _device device; */ +/* Introduction: - -/* Device Tree: + As explained in earlier sections, the device, device instance, + property and interrupts lie at the heart of PSIM's device model. - All the devices in this model live in a tree. The following allow - the location/manipulation of this tree */ + In the below a synopsis of the device object and the operations it + supports are given. Details of this object can be found in the + files <> and <>. -INLINE_DEVICE(device *) device_parent -(device *me); - -INLINE_DEVICE(device *) device_sibling -(device *me); + */ -INLINE_DEVICE(device *) device_child -(device *me); -INLINE_DEVICE(const char *) device_name -(device *me); +/* Constructing the device tree: -INLINE_DEVICE(void *) device_data -(device *me); + The initial device tree populated with devices and basic properties + is created using the function <>. This + function parses a PSIM device specification and uses it to populate + the tree accordingly. + This function accepts a printf style formatted string as the + argument that describes the entry. Any properties or interrupt + connections added to a device tree using this function are marked + as having a permenant disposition. When the tree is (re) + initialized they will be restored to their initial value. -/* Grow the device tree adding either a specific device or - alternativly a device found in the device table */ + */ -INLINE_DEVICE(device *)device_tree_add_device -(device *root, - const char *prefix, - device *new_sub_tree); +EXTERN_DEVICE\ +(device *) device_tree_add_parsed +(device *current, + const char *fmt, + ...) __attribute__ ((format (printf, 2, 3))); -INLINE_DEVICE(device *) device_tree_add_found -(device *root, - const char *prefix, - const char *name); -INLINE_DEVICE(device *) device_tree_add_found_c -(device *root, - const char *prefix, - const char *name, - const char *c1); +/* Initializing the created tree: -INLINE_DEVICE(device *) device_tree_add_found_c_uw -(device *root, - const char *prefix, - const char *name, - const char *c1, - unsigned_word uw2); + Once a device tree has been created the <> + function is used to initialize it. The exact sequence of events + that occure during initialization are described separatly. -INLINE_DEVICE(device *) device_tree_add_found_uw_u -(device *root, - const char *prefix, - const char *name, - unsigned_word uw1, - unsigned u2); + */ -INLINE_DEVICE(device *) device_tree_add_found_uw_u_u +INLINE_DEVICE\ +(void) device_tree_init (device *root, - const char *prefix, - const char *name, - unsigned_word uw1, - unsigned u2, - unsigned u3); + psim *system); -INLINE_DEVICE(device *) device_tree_add_found_uw_u_u_c -(device *root, - const char *prefix, - const char *name, - unsigned_word uw1, - unsigned u2, - unsigned u3, - const char *c4); -INLINE_DEVICE(device *) device_tree_add_found_uw_uw_u_u_c -(device *root, - const char *prefix, - const char *name, - unsigned_word uw1, - unsigned_word uw2, - unsigned u3, - unsigned u4, - const char *c5); +/* Relationships: -INLINE_DEVICE(device *) device_tree_add_found_uw_uw_u_u_u -(device *root, - const char *prefix, - const char *name, - unsigned_word uw1, - unsigned_word uw2, - unsigned u3, - unsigned u4, - unsigned u5); + A device is able to determine its relationship to other devices + within the tree. Operations include querying for a devices parent, + sibling, child, name, and path (from the root). + */ -/* Query the device tree, null is returned if the specified device is - not found */ +INLINE_DEVICE\ +(device *) device_parent +(device *me); -INLINE_DEVICE(device *) device_tree_find_device -(device *root, - const char *path); +INLINE_DEVICE\ +(device *) device_sibling +(device *me); +INLINE_DEVICE\ +(device *) device_child +(device *me); -/* traverse the device tree visiting all notes (either pre or post - fix) */ +INLINE_DEVICE\ +(const char *) device_name +(device *me); -typedef void (device_tree_traverse_function) - (device *device, - void *data); +INLINE_DEVICE\ +(const char *) device_path +(device *me); -INLINE_DEVICE(void) device_tree_traverse -(device *root, - device_tree_traverse_function *prefix, - device_tree_traverse_function *postfix, - void *data); +INLINE_DEVICE\ +(void *) device_data +(device *me); +INLINE_DEVICE\ +(psim *) device_system +(device *me); -/* dump a node, this can be passed to the device_tree_traverse() - function to dump out the entire device tree */ +typedef struct _device_unit { + int nr_cells; + unsigned32 cells[4]; /* unused cells are zero */ +} device_unit; -INLINE_DEVICE(void) device_tree_dump -(device *device, - void *ignore_data_argument); +INLINE_DEVICE\ +(const device_unit *) device_unit_address +(device *me); +/* Properties: - -/* Device Properties: + Attached to a device are a number of properties. Each property has + a size and type (both of which can be queried). A device is able + to iterate over or query and set a properties value. - Attached to a device (typically by open boot firmware) are - properties that profile the devices features. The below allow the - manipulation of device properties */ + */ -/* Each device can have associated properties. Internal to - psim those properties are strictly typed. Within the simulation, - no such control exists */ +/* The following are valid property types. The property `array' is a + for generic untyped data. */ typedef enum { - integer_property, + array_property, boolean_property, + ihandle_property, + integer_property, string_property, - array_property, - null_property, } device_property_type; typedef struct _device_property device_property; struct _device_property { device *owner; + const char *name; device_property_type type; unsigned sizeof_array; const void *array; + const device_property *original; + object_disposition disposition; }; -/* Basic operations used by software */ +/* iterate through the properties attached to a device */ + +INLINE_DEVICE\ +(const device_property *) device_next_property +(const device_property *previous); -INLINE_DEVICE(const char *) device_find_next_property +INLINE_DEVICE\ +(const device_property *) device_find_property (device *me, - const char *previous); + const char *property); /* NULL for first property */ + + +/* Manipulate the properties belonging to a given device. + + SET on the other hand will force the properties value. The + simulation is aborted if the property was present but of a + conflicting type. + + FIND returns the specified properties value, aborting the + simulation if the property is missing. Code locating a property + should first check its type (using device_find_property above) and + then obtain its value using the below. */ -/* INLINE_DEVICE void device_add_property - No such external function, all properties, when added are explictly - typed */ -INLINE_DEVICE(void) device_add_array_property +INLINE_DEVICE\ +(void) device_set_array_property (device *me, const char *property, const void *array, int sizeof_array); -INLINE_DEVICE(void) device_add_integer_property +INLINE_DEVICE\ +(const device_property *) device_find_array_property (device *me, - const char *property, - signed_word integer); + const char *property); + -INLINE_DEVICE(void) device_add_boolean_property +#if 0 +INLINE_DEVICE\ +(void) device_set_boolean_property (device *me, const char *property, int bool); +#endif -INLINE_DEVICE(void) device_add_null_property +INLINE_DEVICE\ +(int) device_find_boolean_property (device *me, const char *property); -INLINE_DEVICE(void) device_add_string_property + +#if 0 +INLINE_DEVICE\ +(void) device_set_ihandle_property (device *me, const char *property, - const char *string); - - -/* Locate a property returning its description. Return NULL if the - named property is not found */ + device_instance *ihandle); +#endif -INLINE_DEVICE(const device_property *) device_find_property +INLINE_DEVICE\ +(device_instance *) device_find_ihandle_property (device *me, const char *property); -/* Process all properties attached to the named device */ - -typedef void (device_traverse_property_function) - (device *me, - const char *name, - void *data); - -INLINE_DEVICE(void) device_traverse_properties +#if 0 +INLINE_DEVICE\ +(void) device_set_integer_property (device *me, - device_traverse_property_function *traverse, - void *data); - - -/* Similar to above except that the property *must* be in the device - tree and *must* be of the specified type. */ + const char *property, + signed_word integer); +#endif -INLINE_DEVICE(const device_property *) device_find_array_property +INLINE_DEVICE\ +(signed_word) device_find_integer_property (device *me, const char *property); -INLINE_DEVICE(signed_word) device_find_integer_property -(device *me, - const char *property); -INLINE_DEVICE(const char *) device_find_string_property +#if 0 +INLINE_DEVICE\ +(void) device_set_string_property (device *me, - const char *property); + const char *property, + const char *string); +#endif -INLINE_DEVICE(int) device_find_boolean_property +INLINE_DEVICE\ +(const char *) device_find_string_property (device *me, const char *property); - -/* Device Hardware: +/* Instances: - A device principaly is modeling real hardware that a processor can - directly interact with via load/stores dma's and interrupts. The - interface below is used by the hardware side of the device - model. */ - -/* Address access attributes that can be attached to a devices address - range */ -typedef enum _access_type { - access_invalid = 0, - access_read = 1, - access_write = 2, - access_read_write = 3, - access_exec = 4, - access_read_exec = 5, - access_write_exec = 6, - access_read_write_exec = 7, -} access_type; + As with IEEE1275, a device can be opened, creating an instance. + Instances provide more abstract interfaces to the underlying + hardware. For example, the instance methods for a disk may include + code that is able to interpret file systems found on disks. Such + methods would there for allow the manipulation of files on the + disks file system. The operations would be implemented using the + basic block I/O model provided by the disk. - -/* Address attachement types */ -typedef enum _attach_type { - attach_invalid, - attach_callback, - attach_default, - attach_raw_memory, -} attach_type; - - -/* Initialization: - - A device is made fully functional in two stages. - - 1. It is created. A device is created _before_ it is entered into - the device tree. During creation any permenant structures needed - by the device should be created/initialized. - - 2. It is initialized. Before a simulation run, each device in the - device tree is initialized in prefix order. As part of this - initialization, a device should (re)attach its self to its parent - as needed. + This model includes methods that faciliate the creation of device + instance and (should a given device support it) standard operations + on those instances. */ -INLINE_DEVICE(device *) device_create -(const char *name, - device *parent); - -/* some external functions want to create things */ -typedef struct _device_callbacks device_callbacks; +typedef struct _device_instance_callbacks device_instance_callbacks; -INLINE_DEVICE(device *) device_create_from -(const char *name, +INLINE_DEVICE\ +(device_instance *) device_create_instance_from +(device *me, /*OR*/ device_instance *parent, void *data, - const device_callbacks *callbacks, - device *parent); + const char *path, + const char *args, + const device_instance_callbacks *callbacks); -INLINE_DEVICE(void) device_init +INLINE_DEVICE\ +(device_instance *) device_create_instance (device *me, - psim *system); + const char *device_specifier); -/* initialize the entire tree */ +INLINE_DEVICE\ +(void) device_instance_delete +(device_instance *instance); -INLINE_DEVICE(void) device_tree_init -(device *root, - psim *system); +INLINE_DEVICE\ +(int) device_instance_read +(device_instance *instance, + void *addr, + unsigned_word len); +INLINE_DEVICE\ +(int) device_instance_write +(device_instance *instance, + const void *addr, + unsigned_word len); -/* Data transfers: +INLINE_DEVICE\ +(int) device_instance_seek +(device_instance *instance, + unsigned_word pos_hi, + unsigned_word pos_lo); - A device may permit the reading/writing (IO) of its registers in - one or more address spaces. For instance, a PCI device may have - config registers in its config space and control registers in both - the io and memory spaces of a PCI bus. +INLINE_DEVICE\ +(unsigned_word) device_instance_claim +(device_instance *instance, + unsigned_word address, + unsigned_word length, + unsigned_word alignment); - Similarly, a device may initiate a data transfer (DMA) by passing - such a request up to its parent. +INLINE_DEVICE\ +(void) device_instance_release +(device_instance *instance, + unsigned_word address, + unsigned_word length); - Init: +INLINE_DEVICE\ +(device *) device_instance_device +(device_instance *instance); - As part of its initialization (not creation) and possibly also as a - consequence of IO a device may attach its self to one or more of - the address spaces of its parent device. +INLINE_DEVICE\ +(const char *) device_instance_path +(device_instance *instance); - For instance, a PCI device, during initialization would attach its - config registers (space=0?, base=0, nr_bytes=64) to its parent PCI - bridge. Later, due to a write to this config space, the same - device may in turn find it necessary to also attach its self to - it's parent's `memory' or `io' space. +INLINE_DEVICE\ +(void *) device_instance_data +(device_instance *instance); - To perform these operations, a device will call upon its parent - using either device_attach_address or device_detach_address. - * Any address specified is according to what the device expects to - see. +/* Interrupts: - * Any detach operation must exactly match a previous attach. + */ - * included with the attach or detach is the devices name, the - parent may use this as part of determining how to map map between a - child's address + space and its own. +/* Interrupt Source - * at any time, at most one device can have a default mapping - registered. + A device drives its interrupt line using the call + */ - IO: +INLINE_DEVICE\ +(void) device_interrupt_event +(device *me, + int my_port, + int value, + cpu *processor, + unsigned_word cia); - A device receives requests to perform reads/writes to its registers - or memory either A. from a processor or B. from a parent device. +/* This interrupt event will then be propogated to any attached + interrupt destinations. - The device may then in turn either A. resolve the IO request - locally by processing the data or trigering an exception or - B. re-mapping the access onto one of its local address spaces and - then in turn passing that on to one of its children. + Any interpretation of PORT and VALUE is model dependant. However + as guidelines the following are recommended: PCI interrupts a-d + correspond to lines 0-3; level sensative interrupts be requested + with a value of one and withdrawn with a value of 0; edge sensative + interrupts always have a value of 1, the event its self is treated + as the interrupt. - * Any address passed is relative to the local device. Eg for PCI - config registers, the address would (normally) be in the range of 0 - to 63. - * Any exception situtation triggered by an IO operation (processor - != NULL) is handled in one of the following ways: 1. Machine check - (and similar): issued immediatly by restarting the cpu; 2. External - exception: issue delayed (using events.h) until the current - instruction execution cycle is completed; 3. Slave device (and - similar): the need for the interrupt is passed on to the devices - parent (which being an interrupt control unit will in turn take one - of the actions described here); 4. Forget it. + Interrupt Destinations - * Any exception situtation trigered by a non IO operation - (processor == NULL) is handled buy returning 0. + Attached to each interrupt line of a device can be zero or more + desitinations. These destinations consist of a device/port pair. + A destination is attached/detached to a device line using the + attach and detach calls. */ - * Transfers of size <= 8 and of a power of 2 *must* be correctly - aligned and should be treated as a `single cycle' transfer. +INLINE_DEVICE\ +(void) device_interrupt_attach +(device *me, + int my_port, + device *dest, + int dest_port, + object_disposition disposition); + +INLINE_DEVICE\ +(void) device_interrupt_detach +(device *me, + int my_port, + device *dest, + int dest_port); - DMA: +/* DESTINATION is attached (detached) to LINE of the device ME - A device initiates a DMA transfer by calling its parent with the - request. At the top level (if not done earlier) this is reflected - back down the tree as io read/writes to the target device. - This function is subject to change ... + Interrupt conversion - */ + Users refer to interrupt port numbers symbolically. For instance a + device may refer to its `INT' signal which is internally + represented by port 3. -INLINE_DEVICE(void) device_attach_address + To convert to/from the symbolic and internal representation of a + port name/number. The following functions are available. */ + +INLINE_DEVICE\ +(int) device_interrupt_decode (device *me, - const char *name, - attach_type attach, - int space, - unsigned_word addr, - unsigned nr_bytes, - access_type access, - device *who); /*callback/default*/ + const char *symbolic_name); -INLINE_DEVICE(void) device_detach_address +INLINE_DEVICE\ +(int) device_interrupt_encode (device *me, - const char *name, - attach_type attach, - int space, - unsigned_word addr, - unsigned nr_bytes, - access_type access, - device *who); /*callback/default*/ + int port_number, + char *buf, + int sizeof_buf); + -INLINE_DEVICE(unsigned) device_io_read_buffer +/* Hardware operations: + + */ + +INLINE_DEVICE\ +(unsigned) device_io_read_buffer (device *me, void *dest, int space, @@ -438,7 +417,8 @@ INLINE_DEVICE(unsigned) device_io_read_buffer cpu *processor, unsigned_word cia); -INLINE_DEVICE(unsigned) device_io_write_buffer +INLINE_DEVICE\ +(unsigned) device_io_write_buffer (device *me, const void *source, int space, @@ -447,14 +427,23 @@ INLINE_DEVICE(unsigned) device_io_write_buffer cpu *processor, unsigned_word cia); -INLINE_DEVICE(unsigned) device_dma_read_buffer + +/* Conversly, the device pci1000,1@1 my need to perform a dma transfer + into the cpu/memory core. Just as I/O moves towards the leaves, + dma transfers move towards the core via the initiating devices + parent nodes. The root device (special) converts the DMA transfer + into reads/writes to memory */ + +INLINE_DEVICE\ +(unsigned) device_dma_read_buffer (device *me, void *dest, int space, unsigned_word addr, unsigned nr_bytes); -INLINE_DEVICE(unsigned) device_dma_write_buffer +INLINE_DEVICE\ +(unsigned) device_dma_write_buffer (device *me, const void *source, int space, @@ -462,184 +451,180 @@ INLINE_DEVICE(unsigned) device_dma_write_buffer unsigned nr_bytes, int violate_read_only_section); +/* To avoid the need for an intermediate (bridging) node to ask each + of its child devices in turn if an IO access is intended for them, + parent nodes maintain a table mapping addresses directly to + specific devices. When a device is `connected' to its bus it + attaches its self to its parent. */ -/* Interrupts: +/* Address access attributes */ +typedef enum _access_type { + access_invalid = 0, + access_read = 1, + access_write = 2, + access_read_write = 3, + access_exec = 4, + access_read_exec = 5, + access_write_exec = 6, + access_read_write_exec = 7, +} access_type; - As mentioned above. Instead of handling an interrupt directly, a - device may instead pass the need to interrupt on to its parent. +/* Address attachement types */ +typedef enum _attach_type { + attach_invalid, + attach_raw_memory, + attach_callback, + /* ... */ +} attach_type; - Init: +INLINE_DEVICE\ +(void) device_attach_address +(device *me, + const char *name, + attach_type attach, + int space, + unsigned_word addr, + unsigned nr_bytes, + access_type access, + device *who); /*callback/default*/ - Before passing interrupts up to is parent, a device must first - attach its interrupt lines to the parent device. To do this, the - device uses the parents attach/detach calls. - - Interrupts: +INLINE_DEVICE\ +(void) device_detach_address +(device *me, + const char *name, + attach_type attach, + int space, + unsigned_word addr, + unsigned nr_bytes, + access_type access, + device *who); /*callback/default*/ - A child notifies a parent of a change in an interrupt lines status - using the interrupt call. Similarly, a parent may notify a child - of any `interrupt ack' sequence using the interrupt_ack call. +/* Utilities: */ -INLINE_DEVICE(void) device_attach_interrupt -(device *me, - device *who, - int interrupt_line, - const char *name); +/* IOCTL:: -INLINE_DEVICE(void) device_detach_interrupt -(device *me, - device *who, - int interrupt_line, - const char *name); + Often devices require `out of band' operations to be performed. + For instance a pal device may need to notify a PCI bridge device + that an interrupt ack cycle needs to be performed on the PCI bus. + Within PSIM such operations are performed by using the generic + ioctl call <>. -INLINE_DEVICE(void) device_interrupt + */ + +EXTERN_DEVICE\ +(int) device_ioctl (device *me, - device *who, - int interrupt_line, - int interrupt_status, cpu *processor, - unsigned_word cia); + unsigned_word cia, + ...); -INLINE_DEVICE(void) device_interrupt_ack -(device *me, - int interrupt_line, - int interrupt_status); +/* Error reporting:: -/* IOCTL: + So that errors originating from devices appear in a consistent + format, the <> function can be used. Formats and + outputs the error message before aborting the simulation - Very simply, a catch all for any thing that turns up that until now - either hasn't been thought of or doesn't justify an extra function. */ + Devices should use this function to abort the simulation except + when the abort reason leaves the simulation in a hazardous + condition (for instance a failed malloc). + + */ EXTERN_DEVICE\ -(void) device_ioctl +(void volatile) device_error (device *me, - psim *system, - cpu *processor, - unsigned_word cia, - ...); - + const char *fmt, + ...) __attribute__ ((format (printf, 2, 3))); - -/* Device software - the instance +/* Tree traversal:: - Under development + The entire device tree can be traversed using the + <> function. The traversal can be in + either pre- or postfix order. - In addition to the processor directly manipulating a device via - read/write operations. A program may manipulate a device - indirectly via OpenBoot calls. The following provide a higher - level software interface to the devices */ + */ -#if 0 -INLINE_DEVICE(device_instance *)device_instance_open -(device *me, - const char *device_specifier); +typedef void (device_tree_traverse_function) + (device *device, + void *data); -INLINE_DEVICE(void) device_instance_close -(device_instance *instance); +INLINE_DEVICE\ +(void) device_tree_traverse +(device *root, + device_tree_traverse_function *prefix, + device_tree_traverse_function *postfix, + void *data); -INLINE_DEVICE(int) device_instance_read -(device_instance *instance, - void *addr, - unsigned_word len); +/* Device description:: -INLINE_DEVICE(int) device_instance_write -(device_instance *instance, - const void *addr, - unsigned_word len); + */ -INLINE_DEVICE(int) device_instance_seek -(device_instance *instance, - unsigned_word pos_hi, - unsigned_word pos_lo); +INLINE_DEVICE\ +(void) device_tree_print_device +(device *device, + void *ignore_data_argument); -INLINE_DEVICE(device *) device_instance_device -(device_instance *instance); -INLINE_DEVICE(const char *) device_instance_name -(device_instance *instance); -#endif +/* Tree lookup:: + The function <> will attempt to locate + the specified device within the tree. If the device is not found a + NULL device is returned. + */ - -/* Device dregs... */ +INLINE_DEVICE\ +(device *) device_tree_find_device +(device *root, + const char *path); -/* Parse a device name, various formats: - uw: unsigned_word - u: unsigned - c: string */ +/* Device list or usage:: -INLINE_DEVICE(int) scand_c -(const char *name, - char *c1, - unsigned c1size); + The <> function outputs a list of all the devices + compiled into PSIM. The verbose option will result in additional + information being printed (for instance, the interrupt ports). -INLINE_DEVICE(int) scand_c_uw_u -(const char *name, - char *c1, - unsigned c1size, - unsigned_word *uw2, - unsigned *u3); - -INLINE_DEVICE(int) scand_uw -(const char *name, - unsigned_word *uw1); - -INLINE_DEVICE(int) scand_uw_c -(const char *name, - unsigned_word *uw1, - char *c2, - unsigned c2size); - -INLINE_DEVICE(int) scand_uw_u -(const char *name, - unsigned_word *uw1, - unsigned *u2); - -INLINE_DEVICE(int) scand_uw_u_u -(const char *name, - unsigned_word *uw1, - unsigned *u2, - unsigned *u3); - -INLINE_DEVICE(int) scand_uw_u_u_c -(const char *name, - unsigned_word *uw1, - unsigned *u2, - unsigned *u3, - char *c4, - unsigned c4size); - -INLINE_DEVICE(int) scand_uw_uw -(const char *name, - unsigned_word *uw1, - unsigned_word *uw2); - -INLINE_DEVICE(int) scand_uw_uw_u -(const char *name, - unsigned_word *uw1, - unsigned_word *uw2, - unsigned *u3); - -INLINE_DEVICE(int) scand_uw_uw_u_u_c -(const char *name, - unsigned_word *uw1, - unsigned_word *uw2, - unsigned *u3, - unsigned *u4, - char *c5, - unsigned c5size); - -INLINE_DEVICE(int) scand_uw_uw_u_u_u -(const char *name, - unsigned_word *uw1, - unsigned_word *uw2, - unsigned *u3, - unsigned *u4, - unsigned *u5); - -#endif /* _DEVICE_TREE_H_ */ + */ + +INLINE_DEVICE\ +(void) device_usage +(int verbose); + + +/* External representation: + + Both device nodes and device instances, in OpenBoot firmware have + an external representation (phandles and ihandles) and these values + are both stored in the device tree in property nodes and passed + between the client program and the simulator during emulation + calls. + + To limit the potential risk associated with trusing `data' from the + client program, the following mapping operators `safely' convert + between the two representations + + */ + +INLINE_DEVICE\ +(device *) external_to_device +(device *tree_member, + unsigned32 phandle); + +INLINE_DEVICE\ +(unsigned32) device_to_external +(device *me); + +INLINE_DEVICE\ +(device_instance *) external_to_device_instance +(device *tree_member, + unsigned32 ihandle); + +INLINE_DEVICE\ +(unsigned32) device_instance_to_external +(device_instance *me); + +#endif /* _DEVICE_H_ */ diff --git a/sim/ppc/device.maybe b/sim/ppc/device.maybe new file mode 100644 index 00000000000..b18ade1c6ab --- /dev/null +++ b/sim/ppc/device.maybe @@ -0,0 +1,876 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1996, Andrew Cagney + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#ifndef _DEVICE_H_ +#define _DEVICE_H_ + +#ifndef INLINE_DEVICE +#define INLINE_DEVICE +#endif + +/* declared in basics.h, this object is used everywhere */ +/* typedef struct _device device; */ + + +/* Device templates: + + *** THIS SECTION DESCRIBES HOW A DEVICE HAS A STATIC AND DYNAMIC + COMPONENT ** on the device in the tree is dynamic. ***** + + A device node is created from its template. The only valid + operation on a template is to create a device node from it: */ + +INLINE_DEVICE\ +(device *) device_template_create_device +(device *parent, + const char *name, + const char *unit_address, + const char *args); + +/* The create is paramaterized by both the devices unit address (a + string that is converted into numeric form by the devices parent) + and optionally extra argument information. + + The actual device node is constructed by a number of pieces provided + by the template function: */ + +typedef struct _device_callbacks device_callbacks; + +INLINE_DEVICE\ +(device *) device_create_from +(const char *name, + const device_unit *unit_address, + void *data, + const device_callbacks *callbacks, + device *parent); + +/* OpenBoot discusses the creation of packages (devices). */ + + +/* Devices: + + As with OpenBoot, all nodes in the device tree are considered to be + devices. Each node then has associated with it a number of methods + and properties (duscussed later). + + OpenBoot documentation refers to devices, device nodes, packages, + package instances, methods, static methods and properties. This + device implementation uses its own termonology. Where ever it + exists, the notes will indicate a correspondance between PSIM terms + and those found in OpenBoot. + + device: + + A device is the basic building block in this model. A device can + be further categorized into one of three classes - template, node + and instance. + + device-node (aka device): + + The device tree is constructed from device-nodes. Each node has + both local state (data), a relationship with the device nodes + around it and an address (unit-address) on the parents bus `bus' */ + +INLINE_DEVICE\ +(device *) device_parent +(device *me); + +INLINE_DEVICE\ +(device *) device_sibling +(device *me); + +INLINE_DEVICE\ +(device *) device_child +(device *me); + +INLINE_DEVICE\ +(const char *) device_name +(device *me); + +INLINE_DEVICE\ +(const char *) device_path +(device *me); + +INLINE_DEVICE\ +(void *) device_data +(device *me); + +INLINE_DEVICE\ +(psim *) device_system +(device *me); + +typedef struct _device_unit { + int nr_cells; + unsigned32 cells[4]; /* unused cells are zero */ +} device_unit; + +INLINE_DEVICE\ +(const device_unit *) device_unit_address +(device *me); + +/* Each device-node normally corresponds to a hardware component of + the system being modeled. Leaf nodes matching external devices and + intermediate nodes matching bridges and controllers. + + Device nodes also support methods that are an abstraction of the + transactions that occure in real hardware. These operations + (io/dma read/writes and interrupts) are discussed separatly. + + OpenBoot refers to device nodes by many names. The most common are + device, device node and package. */ + + +/* Properties: + + In IEEE1275 many of the the characteristics of a device are stored + in the device tree as properties. Each property consists of a name + and an associated (implicitly typed) value. A device will have a + list of properties attached to it. The user is able to manipulate + the list, adding and removing properties and set/modify the value + of each property. + + PSIM's device tree follows this model but with the addition of + strongly typing each property's value. The simulator will detect + at run time, the incorrect use of a property. + + In addition to the standard use of properties, Both PSIM and + individual devices will use properties to record simulation + configuration information. For instance, a disk device might store + in a string property called <> the name of the file that + contains the disk image to use. */ + +/* The following are valid property types. The property `array' is a + for generic untyped data. */ + +typedef enum { + array_property, + boolean_property, + ihandle_property, + integer_property, + string_property, +} device_property_type; + +typedef struct _device_property device_property; +struct _device_property { + device *owner; + const char *name; + device_property_type type; + unsigned sizeof_array; + const void *array; + const device_property *original; + object_disposition disposition; +}; + + +/* iterate through the properties attached to a device */ + +INLINE_DEVICE\ +(const device_property *) device_next_property +(const device_property *previous); + +INLINE_DEVICE\ +(const device_property *) device_find_property +(device *me, + const char *property); /* NULL for first property */ + + +/* Manipulate the properties belonging to a given device. + + SET on the other hand will force the properties value. The + simulation is aborted if the property was present but of a + conflicting type. + + FIND returns the specified properties value, aborting the + simulation if the property is missing. Code locating a property + should first check its type (using device_find_property above) and + then obtain its value using the below. */ + + +INLINE_DEVICE\ +(void) device_set_array_property +(device *me, + const char *property, + const void *array, + int sizeof_array); + +INLINE_DEVICE\ +(const device_property *) device_find_array_property +(device *me, + const char *property); + + +#if 0 +INLINE_DEVICE\ +(void) device_set_boolean_property +(device *me, + const char *property, + int bool); +#endif + +INLINE_DEVICE\ +(int) device_find_boolean_property +(device *me, + const char *property); + + +#if 0 +INLINE_DEVICE\ +(void) device_set_ihandle_property +(device *me, + const char *property, + device_instance *ihandle); +#endif + +INLINE_DEVICE\ +(device_instance *) device_find_ihandle_property +(device *me, + const char *property); + + +#if 0 +INLINE_DEVICE\ +(void) device_set_integer_property +(device *me, + const char *property, + signed_word integer); +#endif + +INLINE_DEVICE\ +(signed_word) device_find_integer_property +(device *me, + const char *property); + + +#if 0 +INLINE_DEVICE\ +(void) device_set_string_property +(device *me, + const char *property, + const char *string); +#endif + +INLINE_DEVICE\ +(const char *) device_find_string_property +(device *me, + const char *property); + + +/* Instances: + + As with IEEE1275, a device can be opened, creating an instance. + Instances provide more abstract interfaces to the underlying + hardware. For example, the instance methods for a disk may include + code that is able to interpret file systems found on disks. Such + methods would there for allow the manipulation of files on the + disks file system. The operations would be implemented using the + basic block I/O model provided by the disk. + + This model includes methods that faciliate the creation of device + instance and (should a given device support it) standard operations + on those instances. */ + + *** device-instance *** + + Devices support an abstract I/O model. A unique I/O instance can be + created from a device node and then this instance used to perform + I/O that is independant of other instances. */ + +typedef struct _device_instance_callbacks device_instance_callbacks; + +INLINE_DEVICE\ +(device_instance *) device_create_instance_from +(device *me, /*OR*/ device_instance *parent, + void *data, + const char *path, + const char *args, + const device_instance_callbacks *callbacks); + +INLINE_DEVICE\ +(device_instance *) device_create_instance +(device *me, + const char *device_specifier); + +INLINE_DEVICE\ +(void) device_instance_delete +(device_instance *instance); + +INLINE_DEVICE\ +(int) device_instance_read +(device_instance *instance, + void *addr, + unsigned_word len); + +INLINE_DEVICE\ +(int) device_instance_write +(device_instance *instance, + const void *addr, + unsigned_word len); + +INLINE_DEVICE\ +(int) device_instance_seek +(device_instance *instance, + unsigned_word pos_hi, + unsigned_word pos_lo); + +INLINE_DEVICE\ +(unsigned_word) device_instance_claim +(device_instance *instance, + unsigned_word address, + unsigned_word length, + unsigned_word alignment); + +INLINE_DEVICE\ +(void) device_instance_release +(device_instance *instance, + unsigned_word address, + unsigned_word length); + +INLINE_DEVICE\ +(device *) device_instance_device +(device_instance *instance); + +INLINE_DEVICE\ +(const char *) device_instance_path +(device_instance *instance); + +INLINE_DEVICE\ +(void *) device_instance_data +(device_instance *instance); + +/* A device instance can be marked (when created) as being permenant. + Such instances are assigned a reserved address and are *not* + deleted between simulation runs. + + OpenBoot refers to a device instace as a package instance */ + + +/* PIO: + + *** DESCRIBE HERE WHAT A PIO OPERATION IS and how, broadly it is + modeled **** + + + During initialization, each device attaches its self to is parent + registering the address spaces that it is interested in: + + a. The <> device attaches its self to its parent <> + device at address <<0x3f8>> through to address <<0x3f8 + 16>>. + + b. The <> has in turn attached its self to addresses + <<0xf0000000 .. 0xf0100000>>. + + During the execution of the simulation propper, the following then + occure: + + 1. After any virtual to physical translation, the processor + passes the address to be read (or written to the core device). + (eg address 0xf00003f8). + + 2. The core device then looks up the specified addresses in its + address to device map, determines that in this case the address + belongs to the phb and passes it down. + + 3. The <> in turn determines that the address belongs to the + serial port and passes to that device the request for an access + to location <<0x3f8>>. + + @figure mio + + */ + +/* Device Hardware + + This model assumes that the data paths of the system being modeled + have a tree topology. That is, one or more processors sit at the + top of a tree. That tree containing leaf nodes (real devices) and + branch nodes (bridges). + + For instance, consider the tree: + + /pci # PCI-HOST bridge + /pci/pci1000,1@1 # A pci controller + /pci/isa8086 # PCI-ISA bridge + /pci/isa8086/fdc@300 # floppy disk controller on ISA bus + + A processor needing to access the device fdc@300 on the ISA bus + would do so using a data path that goes through the pci-host bridge + (pci)and the isa-pci bridge (isa8086) to finally reach the device + fdc@300. As the data transfer passes through each intermediate + bridging node that bridge device is able to (just like with real + hardware) manipulate either the address or data involved in the + transfer. */ + +INLINE_DEVICE\ +(unsigned) device_io_read_buffer +(device *me, + void *dest, + int space, + unsigned_word addr, + unsigned nr_bytes, + cpu *processor, + unsigned_word cia); + +INLINE_DEVICE\ +(unsigned) device_io_write_buffer +(device *me, + const void *source, + int space, + unsigned_word addr, + unsigned nr_bytes, + cpu *processor, + unsigned_word cia); + +/* To avoid the need for an intermediate (bridging) node to ask each + of its child devices in turn if an IO access is intended for them, + parent nodes maintain a table mapping addresses directly to + specific devices. When a device is `connected' to its bus it + attaches its self to its parent. */ + +/* Address access attributes */ +typedef enum _access_type { + access_invalid = 0, + access_read = 1, + access_write = 2, + access_read_write = 3, + access_exec = 4, + access_read_exec = 5, + access_write_exec = 6, + access_read_write_exec = 7, +} access_type; + +/* Address attachement types */ +typedef enum _attach_type { + attach_invalid, + attach_raw_memory, + attach_callback, + /* ... */ +} attach_type; + +INLINE_DEVICE\ +(void) device_attach_address +(device *me, + const char *name, + attach_type attach, + int space, + unsigned_word addr, + unsigned nr_bytes, + access_type access, + device *who); /*callback/default*/ + +INLINE_DEVICE\ +(void) device_detach_address +(device *me, + const char *name, + attach_type attach, + int space, + unsigned_word addr, + unsigned nr_bytes, + access_type access, + device *who); /*callback/default*/ + +/* where the attached address space can be any of + + callback - all accesses to that range of addresses are past on to + the attached child device. The callback addresses are ordered + according to the callback level (attach_callback, .. + 1, .. + 2, + ...). Lower levels are searched first. This facilitates the + implementation of more unusual addressing schema such as + subtractive decoding (as seen on the PCI bus). Within a given + callback level addresses must not overlap. + + memory - the specified address space contains RAM, the node that is + having the ram attached is responsible for allocating space for and + maintaining that space. The device initiating the attach will not + be notified of accesses to such an attachement. + + The memory attachment is very important. By giving the parent node + the responsability (and freedom) of managing the RAM, that node is + able to implement memory spaces more efficiently. For instance it + could `cache' accesses or merge adjacent memory areas. + + + In addition to I/O and DMA, devices interact with the rest of the + system via interrupts. Interrupts are discussed separatly. */ + + +/* DMA: + + *** DESCRIBE HERE WHAT A DMA OPERATION IS AND HOW IT IS MODELED, + include an interation of an access being reflected back down *** + + */ + +/* Conversly, the device pci1000,1@1 my need to perform a dma transfer + into the cpu/memory core. Just as I/O moves towards the leaves, + dma transfers move towards the core via the initiating devices + parent nodes. The root device (special) converts the DMA transfer + into reads/writes to memory */ + +INLINE_DEVICE\ +(unsigned) device_dma_read_buffer +(device *me, + void *dest, + int space, + unsigned_word addr, + unsigned nr_bytes); + +INLINE_DEVICE\ +(unsigned) device_dma_write_buffer +(device *me, + const void *source, + int space, + unsigned_word addr, + unsigned nr_bytes, + int violate_read_only_section); + + +/* Interrupts: + + *** DESCRIBE HERE THE INTERRUPT NETWORK *** + + PSIM models interrupts and their wiring as a directed graph of + connections between interrupt sources and destinations. The source + and destination are both a tupple consisting of a port number and + device. Both multiple destinations attached to a single source and + multiple sources attached to a single destination are allowed. + + When a device drives an interrupt port with multiple destinations a + broadcast of that interrupt event (message to all destinations) + occures. Each of those destination (device/port) are able to + further propogate the interrupt until it reaches its ultimate + destination. + + Normally an interrupt source would be a model of a real device + (such as a keyboard) while an interrupt destination would be an + interrupt controller. The facility that allows an interrupt to be + delivered to multiple devices and to be propogated from device to + device was designed to support the requirements specified by + OpenPIC (ISA interrupts go to both OpenPIC and 8259), CHRP (8259 + connected to OpenPIC) and hardware designs such as PCI-PCI + bridges. */ + + +/* Interrupting a processor + + The cpu object provides methods for delivering external interrupts + to a given processor. + + The problem of synchronizing external interrupt delivery with the + execution of the cpu is handled internally by the processor object. */ + + + +/* Interrupt Source + + A device drives its interrupt line using the call: */ + +INLINE_DEVICE\ +(void) device_interrupt_event +(device *me, + int my_port, + int value, + cpu *processor, + unsigned_word cia); + +/* This interrupt event will then be propogated to any attached + interrupt destinations. + + Any interpretation of PORT and VALUE is model dependant. However + as guidelines the following are recommended: PCI interrupts a-d + correspond to lines 0-3; level sensative interrupts be requested + with a value of one and withdrawn with a value of 0; edge sensative + interrupts always have a value of 1, the event its self is treated + as the interrupt. + + + Interrupt Destinations + + Attached to each interrupt line of a device can be zero or more + desitinations. These destinations consist of a device/port pair. + A destination is attached/detached to a device line using the + attach and detach calls. */ + +INLINE_DEVICE\ +(void) device_interrupt_attach +(device *me, + int my_port, + device *dest, + int dest_port, + object_disposition disposition); + +INLINE_DEVICE\ +(void) device_interrupt_detach +(device *me, + int my_port, + device *dest, + int dest_port); + +/* DESTINATION is attached (detached) to LINE of the device ME + + + Interrupt conversion + + Users refer to interrupt port numbers symbolically. For instance a + device may refer to its `INT' signal which is internally + represented by port 3. + + To convert to/from the symbolic and internal representation of a + port name/number. The following functions are available. */ + +INLINE_DEVICE\ +(int) device_interrupt_decode +(device *me, + const char *symbolic_name); + +INLINE_DEVICE\ +(int) device_interrupt_encode +(device *me, + int port_number, + char *buf, + int sizeof_buf); + + + +/* Initialization: + + In PSIM, the device tree is created and then initialized in stages. + When using devices it is important to be clear what initialization + the simulator assumes is being performed during each of these + stages. + + Firstly, each device is created in isolation (using the create from + template method). Only after it has been created will a device be + inserted into the tree ready for initialization. + + Once the tree is created, it is initialized as follows: + + 1. All properties (apart from those containing instances) + are (re)initialized + + 2. Any interrupts addeded as part of the simulation run + are removed. + + 4. The initialize address method of each device (in top + down order) is called. At this stage the device + is expected to: + + o Clear address maps and delete allocated memory + associated with the devices children. + + o (Re)attach its own addresses to its parent device. + + o Ensure that it is otherwize sufficiently + initialized such that it is ready for a + device instance create call. + + 5. All properties containing an instance of + a device are (re)initialized + + 6. The initialize data method for each device is called (in + top down) order. At this stage the device is expected to: + + o Perform any needed data transfers. Such + transfers would include the initialization + of memory created during the address initialization + stage using DMA. + + */ + +INLINE_DEVICE\ +(void) device_tree_init +(device *root, + psim *system); + + + +/* IOCTL: + + Very simply, a catch all for any thing that turns up that until now + either hasn't been thought of or doesn't justify an extra function. */ + +EXTERN_DEVICE\ +(int) device_ioctl +(device *me, + cpu *processor, + unsigned_word cia, + ...); + + +/* External communcation: + + Devices interface to the external environment */ + +/* device_error() reports the problem to the console and aborts the + simulation. The error message is prefixed with the name of the + reporting device. */ + +EXTERN_DEVICE\ +(void volatile) device_error +(device *me, + const char *fmt, + ...) __attribute__ ((format (printf, 2, 3))); + + +/* Tree utilities: + + In addition to the standard method of creating a device from a + device template, the following sortcuts can be used. + + Create a device or property from a textual representation */ + +EXTERN_DEVICE\ +(device *) device_tree_add_parsed +(device *current, + const char *fmt, + ...) __attribute__ ((format (printf, 2, 3))); + +/* where FMT,... once formatted (using vsprintf) is used to locate and + create either a device or property. Its syntax is almost identical + to that used in OpenBoot documentation - the only extension is in + allowing properties and their values to be specified vis: + + "/pci/pci1000,1@1/disk@0,0" + + Path: + + The path to a device or property can either be absolute (leading + `/') or relative (leading `.' or `..'). Relative paths start from + the CURRENT node. The new current node is returned as the result. + In addition, a path may start with a leading alias (resolved by + looking in /aliases). + + Device name: + + "@" [ ":" ] + + Where is the name of the template device, is a + textual specification of the devices unit address (that is + converted into a numeric form by the devices parent) and are + optional additional information to be passed to the device-template + when it creates the device. + + Properties: + + Properties are specified in a similar way to devices except that + the last element on the path (which would have been the device) is + the property name. This path is then followed by the property + value. Unlike OpenBoot, the property values in the device tree are + strongly typed. + + String property: + + " " + " " "\"" + + Boolean property: + + " " [ "true" | "false" ] + Integer property or integer array property: + + " " { } + + Phandle property: + + " " "&" + + Ihandle property: + + " " "*" + + Duplicate existing property: + + " " "!" + + + In addition to properties, the wiring of interrupts can be + specified: + + Attach interrupt of to : + + " " ">" + + + Once created, a device tree can be traversed in various orders: */ + +typedef void (device_tree_traverse_function) + (device *device, + void *data); + +INLINE_DEVICE\ +(void) device_tree_traverse +(device *root, + device_tree_traverse_function *prefix, + device_tree_traverse_function *postfix, + void *data); + +/* Or dumped out in a format that can be read back in using + device_add_parsed() */ + +INLINE_DEVICE\ +(void) device_tree_print_device +(device *device, + void *ignore_data_argument); + +/* Individual nodes can be located using */ + +INLINE_DEVICE\ +(device *) device_tree_find_device +(device *root, + const char *path); + +/* And the current list of devices can be listed */ + +INLINE_DEVICE\ +(void) device_usage +(int verbose); + + +/* ihandles and phandles: + + Both device nodes and device instances, in OpenBoot firmware have + an external representation (phandles and ihandles) and these values + are both stored in the device tree in property nodes and passed + between the client program and the simulator during emulation + calls. + + To limit the potential risk associated with trusing `data' from the + client program, the following mapping operators `safely' convert + between the two representations: */ + +INLINE_DEVICE\ +(device *) external_to_device +(device *tree_member, + unsigned32 phandle); + +INLINE_DEVICE\ +(unsigned32) device_to_external +(device *me); + +INLINE_DEVICE\ +(device_instance *) external_to_device_instance +(device *tree_member, + unsigned32 ihandle); + +INLINE_DEVICE\ +(unsigned32) device_instance_to_external +(device_instance *me); + +#endif /* _DEVICE_H_ */ diff --git a/sim/ppc/device_table.h b/sim/ppc/device_table.h new file mode 100644 index 00000000000..3e2a158f9c9 --- /dev/null +++ b/sim/ppc/device_table.h @@ -0,0 +1,306 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1996, Andrew Cagney + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#ifndef _DEVICE_TABLE_H_ +#define _DEVICE_TABLE_H_ + +#include + +#include "basics.h" +#include "device.h" + +#ifdef HAVE_STRING_H +#include +#else +#ifdef HAVE_STRINGS_H +#include +#endif +#endif + + +typedef struct _device_callbacks device_callbacks; + + +/* The creator, returns a pointer to any data that should be allocated + once during (multiple) simulation runs */ + +typedef void *(device_creator) + (const char *name, + const device_unit *unit_address, + const char *args); + + +/* two stages of initialization */ + +typedef void (device_init_callback) + (device *me); + +typedef struct _device_init_callbacks { + device_init_callback *address; /* NULL - ignore */ + device_init_callback *data; /* NULL - ignore */ +} device_init_callbacks; + + +/* attaching/detaching a devices address space to its parent */ + +typedef void (device_address_callback) + (device *me, + const char *name, + attach_type attach, + int space, + unsigned_word addr, + unsigned nr_bytes, + access_type access, + device *who); /*callback/default*/ + +typedef struct _device_address_callbacks { + device_address_callback *attach; + device_address_callback *detach; +} device_address_callbacks; + + +/* I/O operations - from parent */ + +typedef unsigned (device_io_read_buffer_callback) + (device *me, + void *dest, + int space, + unsigned_word addr, + unsigned nr_bytes, + cpu *processor, + unsigned_word cia); + +typedef unsigned (device_io_write_buffer_callback) + (device *me, + const void *source, + int space, + unsigned_word addr, + unsigned nr_bytes, + cpu *processor, + unsigned_word cia); + +typedef struct _device_io_callbacks { /* NULL - error */ + device_io_read_buffer_callback *read_buffer; + device_io_write_buffer_callback *write_buffer; +} device_io_callbacks; + + +/* DMA transfers by a device via its parent */ + +typedef unsigned (device_dma_read_buffer_callback) + (device *me, + void *dest, + int space, + unsigned_word addr, + unsigned nr_bytes); + +typedef unsigned (device_dma_write_buffer_callback) + (device *me, + const void *source, + int space, + unsigned_word addr, + unsigned nr_bytes, + int violate_read_only_section); + +typedef struct _device_dma_callbacks { /* NULL - error */ + device_dma_read_buffer_callback *read_buffer; + device_dma_write_buffer_callback *write_buffer; +} device_dma_callbacks; + + +/* Interrupts */ + +typedef void (device_interrupt_event_callback) + (device *me, + int my_port, + device *source, + int source_port, + int level, + cpu *processor, + unsigned_word cia); + +typedef void (device_child_interrupt_event_callback) + (device *me, + device *parent, + device *source, + int source_port, + int level, + cpu *processor, + unsigned_word cia); + +typedef struct _device_interrupt_port_descriptor { + const char *name; + int number; + int bound; +} device_interrupt_port_descriptor; + +typedef struct _device_interrupt_callbacks { + device_interrupt_event_callback *event; + device_child_interrupt_event_callback *child_event; + const device_interrupt_port_descriptor *ports; +} device_interrupt_callbacks; + + +/* symbolic value decoding */ + +typedef int (device_unit_decode_callback) + (device *me, + const char *unit, + device_unit *address); + +typedef int (device_unit_encode_callback) + (device *me, + const device_unit *unit_address, + char *buf, + int sizeof_buf); + +typedef struct _device_convert_callbacks { + device_unit_decode_callback *decode_unit; + device_unit_encode_callback *encode_unit; +} device_convert_callbacks; + + +/* instances */ + +typedef void (device_instance_delete_callback) + (device_instance *instance); + +typedef int (device_instance_read_callback) + (device_instance *instance, + void *buf, + unsigned_word len); + +typedef int (device_instance_write_callback) + (device_instance *instance, + const void *buf, + unsigned_word len); + +typedef int (device_instance_seek_callback) + (device_instance *instance, + unsigned_word pos_hi, + unsigned_word pos_lo); + +typedef unsigned_word (device_instance_claim_callback) + (device_instance *instance, + unsigned_word address, + unsigned_word length, + unsigned_word alignment); + +typedef void (device_instance_release_callback) + (device_instance *instance, + unsigned_word address, + unsigned_word length); + +struct _device_instance_callbacks { /* NULL - error */ + device_instance_delete_callback *delete; + device_instance_read_callback *read; + device_instance_write_callback *write; + device_instance_seek_callback *seek; + device_instance_claim_callback *claim; + device_instance_release_callback *release; +}; + +typedef device_instance *(device_create_instance_callback) + (device *me, + const char *path, + const char *args); + +typedef device_instance *(package_create_instance_callback) + (device_instance *parent, + const char *args); + + +/* all else fails */ + +typedef int (device_ioctl_callback) + (device *me, + cpu *processor, + unsigned_word cia, + va_list ap); + +typedef void (device_usage_callback) + (int verbose); + + +/* the callbacks */ + +struct _device_callbacks { + + /* initialization */ + device_init_callbacks init; + + /* address/data config - from child */ + device_address_callbacks address; + + /* address/data transfer - from parent */ + device_io_callbacks io; + + /* address/data transfer - from child */ + device_dma_callbacks dma; + + /* interrupt signalling */ + device_interrupt_callbacks interrupt; + + /* bus address decoding */ + device_convert_callbacks convert; + + /* instances */ + device_create_instance_callback *instance_create; + + /* back door to anything we've forgot */ + device_ioctl_callback *ioctl; + device_usage_callback *usage; +}; + + +/* Table of all the devices and a function to lookup/create a device + from its name */ + +typedef struct _device_descriptor device_descriptor; +struct _device_descriptor { + const char *name; + device_creator *creator; + const device_callbacks *callbacks; +}; + +extern const device_descriptor *const device_table[]; +#include "hw.h" + + +/* Pass through, ignore and generic callback functions. A call going + towards the root device are passed on up, local calls are ignored + and call downs abort */ + +extern device_address_callback passthrough_device_address_attach; +extern device_address_callback passthrough_device_address_detach; +extern device_dma_read_buffer_callback passthrough_device_dma_read_buffer; +extern device_dma_write_buffer_callback passthrough_device_dma_write_buffer; + +extern device_unit_decode_callback ignore_device_unit_decode; + +extern device_init_callback generic_device_init_address; +extern device_unit_decode_callback generic_device_unit_decode; +extern device_unit_encode_callback generic_device_unit_encode; + + +extern const device_callbacks passthrough_device_callbacks; + +#endif /* _DEVICE_TABLE_H_ */ diff --git a/sim/ppc/emul_bugapi.c b/sim/ppc/emul_bugapi.c index 9a33da11836..4c1e9ba7324 100644 --- a/sim/ppc/emul_bugapi.c +++ b/sim/ppc/emul_bugapi.c @@ -45,7 +45,7 @@ #define _READLN 0x004 /* Input line (pointer / count format) */ #define _CHKBRK 0x005 /* Check for break */ #define _DSKRD 0x010 /* Disk read */ -#define _DKSWR 0x011 /* Disk write */ +#define _DSKWR 0x011 /* Disk write */ #define _DSKCFIG 0x012 /* Disk configure */ #define _DSKFMT 0x014 /* Disk format */ #define _DSKCTRL 0x015 /* Disk control */ @@ -104,7 +104,7 @@ static const struct bug_map bug_mapping[] = { { _READLN, ".READLN -- Input line (pointer / count format)" }, { _CHKBRK, ".CHKBRK -- Check for break" }, { _DSKRD, ".DSKRD -- Disk read" }, - { _DKSWR, ".DKSWR -- Disk write" }, + { _DSKWR, ".DSKWR -- Disk write" }, { _DSKCFIG, ".DSKCFIG -- Disk configure" }, { _DSKFMT, ".DSKFMT -- Disk format" }, { _DSKCTRL, ".DSKCTRL -- Disk control" }, @@ -151,13 +151,14 @@ static const struct bug_map bug_mapping[] = { { _SYMBOLDA, ".SYMBOLDA -- Detach symbol table" }, }; -#ifndef OEA_START_ADDRESS -#define OEA_START_ADDRESS 0x100000 +#ifndef BUGAPI_END_ADDRESS +#define BUGAPI_END_ADDRESS 0x100000 #endif struct _os_emul_data { + device *root; unsigned_word memory_size; unsigned_word top_of_stack; int interrupt_prefix; @@ -169,6 +170,7 @@ struct _os_emul_data { /* I/O devices */ device_instance *output; device_instance *input; + device_instance *disk; }; @@ -188,7 +190,7 @@ emul_bugapi_create(device *root, return NULL; if (image != NULL && name == NULL - && bfd_get_start_address(image) > OEA_START_ADDRESS) + && bfd_get_start_address(image) >= BUGAPI_END_ADDRESS) return NULL; bugapi = ZALLOC(os_emul_data); @@ -203,6 +205,8 @@ emul_bugapi_create(device *root, /* add some real hardware */ emul_add_tree_hardware(root); + bugapi->root = root; + bugapi->memory_size = device_find_integer_property(root, "/openprom/options/oea-memory-size"); bugapi->interrupt_prefix = @@ -217,10 +221,8 @@ emul_bugapi_create(device *root, = device_find_boolean_property(root, "/options/little-endian?"); bugapi->floating_point_available = device_find_boolean_property(root, "/openprom/options/floating-point?"); - bugapi->input - = device_find_ihandle_property(root, "/chosen/stdin"); - bugapi->output - = device_find_ihandle_property(root, "/chosen/stdout"); + bugapi->input = NULL; + bugapi->output = NULL; /* initialization */ device_tree_add_parsed(root, "/openprom/init/register/0.pc 0x%lx", @@ -268,7 +270,7 @@ emul_bugapi_create(device *root, (unsigned long)emul_loop_instruction); device_tree_add_parsed(root, "/openprom/init/stack/stack-type %s", - elf_binary ? "elf" : "aix"); + elf_binary ? "ppc-elf" : "ppc-xcoff"); device_tree_add_parsed(root, "/openprom/init/load-binary/file-name \"%s", bfd_get_filename(image)); @@ -277,10 +279,14 @@ emul_bugapi_create(device *root, } static void -emul_bugapi_init(os_emul_data *emul_data, +emul_bugapi_init(os_emul_data *bugapi, int nr_cpus) { - /* nothing happens here */ + /* get the current input/output devices that were created during + device tree initialization */ + bugapi->input = device_find_ihandle_property(bugapi->root, "/chosen/stdin"); + bugapi->output = device_find_ihandle_property(bugapi->root, "/chosen/stdout"); + bugapi->disk = device_find_ihandle_property(bugapi->root, "/chosen/disk"); } static const char * @@ -336,6 +342,61 @@ emul_bugapi_do_read(os_emul_data *bugapi, return status; } +static void +emul_bugapi_do_diskio(os_emul_data *bugapi, + cpu *processor, + unsigned_word cia, + unsigned_word descriptor_addr, + int call_id) +{ + struct dskio_descriptor { + unsigned_1 ctrl_lun; + unsigned_1 dev_lun; + unsigned_2 status; + unsigned_word pbuffer; + unsigned_4 blk_num; + unsigned_2 blk_cnt; + unsigned_1 flag; +#define BUG_FILE_MARK 0x80 +#define IGNORE_FILENUM 0x02 +#define END_OF_FILE 0x01 + unsigned_1 addr_mod; + } descriptor; + int block; + emul_read_buffer(&descriptor, descriptor_addr, sizeof(descriptor), + processor, cia); + T2H(descriptor.ctrl_lun); + T2H(descriptor.dev_lun); + T2H(descriptor.status); + T2H(descriptor.pbuffer); + T2H(descriptor.blk_num); + T2H(descriptor.blk_cnt); + T2H(descriptor.flag); + T2H(descriptor.addr_mod); + for (block = 0; block < descriptor.blk_cnt; block++) { + unsigned_1 buf[512]; /*????*/ + unsigned_word block_nr = descriptor.blk_num + block; + unsigned_word byte_nr = block_nr * sizeof(buf); + unsigned_word block_addr = descriptor.pbuffer + block*sizeof(buf); + if (device_instance_seek(bugapi->disk, 0, byte_nr) < 0) + error("emul_bugapi_do_diskio: bad seek\n"); + switch (call_id) { + case _DSKRD: + if (device_instance_read(bugapi->disk, buf, sizeof(buf)) != sizeof(buf)) + error("emul_bugapi_do_diskio: bad read\n"); + emul_write_buffer(buf, block_addr, sizeof(buf), processor, cia); + break; + case _DSKWR: + emul_read_buffer(buf, block_addr, sizeof(buf), processor, cia); + if (device_instance_write(bugapi->disk, buf, sizeof(buf)) != sizeof(buf)) + error("emul_bugapi_do_diskio: bad write\n"); + break; + default: + error("emul_bugapi_do_diskio: bad switch\n"); + } + } +} + static void emul_bugapi_do_write(os_emul_data *bugapi, cpu *processor, @@ -382,13 +443,14 @@ emul_bugapi_instruction_call(cpu *processor, os_emul_data *bugapi) { const int call_id = cpu_registers(processor)->gpr[10]; - const char *my_prefix UNUSED = "bugapi"; unsigned char uc; - ITRACE (trace_os_emul,(" 0x%x %s, r3 = 0x%lx, r4 = 0x%lx\n", - call_id, emul_bugapi_instruction_name (call_id), - (long)cpu_registers(processor)->gpr[3], - (long)cpu_registers(processor)->gpr[4]));; +#define MY_INDEX itable_instruction_call + ITRACE (trace_os_emul, + (" 0x%x %s, r3 = 0x%lx, r4 = 0x%lx\n", + call_id, emul_bugapi_instruction_name (call_id), + (long)cpu_registers(processor)->gpr[3], + (long)cpu_registers(processor)->gpr[4]));; /* check that this isn't an invalid instruction */ if (cia != bugapi->system_call_address) @@ -440,9 +502,17 @@ emul_bugapi_instruction_call(cpu *processor, case _PCRLF: device_instance_write(bugapi->output, "\n", 1); break; - /* return to ppcbug monitor */ + /* read/write blocks of data to/from the disk */ + case _DSKWR: + case _DSKRD: + emul_bugapi_do_diskio(bugapi, processor, cia, + cpu_registers(processor)->gpr[3], + call_id); + break; + /* return to ppcbug monitor (exiting with gpr[3] as status is not + part of the bug monitor) */ case _RETURN: - cpu_halt(processor, cia, was_exited, 0); /* always succeeds */ + cpu_halt(processor, cia, was_exited, cpu_registers(processor)->gpr[3]); break; } return 1; diff --git a/sim/ppc/emul_generic.c b/sim/ppc/emul_generic.c index 3883d0316e2..73209f56422 100644 --- a/sim/ppc/emul_generic.c +++ b/sim/ppc/emul_generic.c @@ -290,6 +290,11 @@ emul_add_tree_options(device *tree, model_name[WITH_DEFAULT_MODEL]); device_tree_add_parsed(tree, "/openprom/options/model-issue %d", MODEL_ISSUE_IGNORE); + + /* useful options */ + /* FIXME - need to check the OpenBoot powerpc bindings to see if + this is still used and if so what it should be */ + device_tree_add_parsed(tree, "/options/load-base 0x80000"); } INLINE_EMUL_GENERIC void @@ -298,6 +303,11 @@ emul_add_tree_hardware(device *root) int i; int nr_cpus = device_find_integer_property(root, "/openprom/options/smp"); + /* sanity check the number of processors */ + if (nr_cpus > MAX_NR_PROCESSORS) + error("Specified number of processors (%d) exceeds the number configured (%d).\n", + nr_cpus, MAX_NR_PROCESSORS); + /* add some memory */ if (device_tree_find_device(root, "/memory") == NULL) { unsigned_word memory_size = @@ -315,21 +325,29 @@ emul_add_tree_hardware(device *root) /* a fake eeprom - need to be able to write to it */ device_tree_add_parsed(root, "/openprom/memory@0xfff00000/reg { 0xfff00000 0x3000"); + /* A local bus containing basic devices */ device_tree_add_parsed(root, "/iobus@0xf0000000/reg { 0xf0000000 0x0f000000"); + + /* NVRAM with clock */ device_tree_add_parsed(root, "/iobus/nvram@0x0/reg { 0 0x1000"); - device_tree_add_parsed(root, "/iobus/nvram/timezone 600"); + device_tree_add_parsed(root, "/iobus/nvram/timezone 0"); /* the debugging pal. Wire interrupts up directly */ device_tree_add_parsed(root, "/iobus/pal@0x0x1000/reg { 0x1000 32"); for (i = 0; i < nr_cpus; i++) { - device_tree_add_parsed(root, "/iobus/pal > %d int /cpus/cpu@%d", i, i); + device_tree_add_parsed(root, "/iobus/pal > int%d int /cpus/cpu@%d", i, i); } + /* a disk containing zero's */ + device_tree_add_parsed(root, "/iobus/disk@0x2000/reg { 0x2000 0x1000"); + device_tree_add_parsed(root, "/iobus/disk/file \"/dev/zero"); + /* chosen etc */ device_tree_add_parsed(root, "/chosen/stdin */iobus/pal"); device_tree_add_parsed(root, "/chosen/stdout !/chosen/stdin"); device_tree_add_parsed(root, "/chosen/memory */memory"); + device_tree_add_parsed(root, "/chosen/disk */iobus/disk"); } #endif /* _EMUL_GENERIC_C_ */ diff --git a/sim/ppc/filter.c b/sim/ppc/filter.c new file mode 100644 index 00000000000..c901a1777f1 --- /dev/null +++ b/sim/ppc/filter.c @@ -0,0 +1,150 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995, Andrew Cagney + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#include + +#include "config.h" + +#ifdef HAVE_STRING_H +#include +#else +#ifdef HAVE_STRINGS_H +#include +#endif +#endif + +#include "misc.h" +#include "filter.h" + +struct _filter { + char *flag; + filter *next; +}; + + +filter * +new_filter(const char *filt, + filter *filters) +{ + while (strlen(filt) > 0) { + filter *new_filter; + /* break up the filt list */ + char *end = strchr(filt, ','); + char *next; + int len; + if (end == NULL) { + end = strchr(filt, '\0'); + next = end; + } + else { + next = end + 1; + } + len = end - filt; + /* add to filter list */ + new_filter = ZALLOC(filter); + new_filter->flag = (char*)zalloc(len + 1); + strncpy(new_filter->flag, filt, len); + new_filter->next = filters; + filters = new_filter; + filt = next; + } + return filters; +} + + +int +is_filtered_out(const char *flags, + filter *filters) +{ + while (strlen(flags) > 0) { + int present; + filter *filt = filters; + /* break the string up */ + char *end = strchr(flags, ','); + char *next; + int len; + if (end == NULL) { + end = strchr(flags, '\0'); + next = end; + } + else { + next = end + 1; + } + len = end - flags; + /* check that it is present */ + present = 0; + filt = filters; + while (filt != NULL) { + if (strncmp(flags, filt->flag, len) == 0 + && strlen(filt->flag) == len) { + present = 1; + break; + } + filt = filt->next; + } + if (!present) + return 1; + flags = next; + } + return 0; +} + + +int +it_is(const char *flag, + const char *flags) +{ + int flag_len = strlen(flag); + while (*flags != '\0') { + if (!strncmp(flags, flag, flag_len) + && (flags[flag_len] == ',' || flags[flag_len] == '\0')) + return 1; + while (*flags != ',') { + if (*flags == '\0') + return 0; + flags++; + } + flags++; + } + return 0; +} + + +#ifdef MAIN +int +main(int argc, char **argv) +{ + filter *filters = NULL; + int i; + if (argc < 2) { + printf("Usage: filter ...\n"); + exit (1); + } + /* load the filter up */ + for (i = 2; i < argc; i++) + filters = new_filter(argv[i], filters); + if (is_filtered_out(argv[1], filters)) + printf("fail\n"); + else + printf("pass\n"); + return 0; +} +#endif diff --git a/sim/ppc/filter.h b/sim/ppc/filter.h new file mode 100644 index 00000000000..814f704f8d2 --- /dev/null +++ b/sim/ppc/filter.h @@ -0,0 +1,43 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995, Andrew Cagney + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +typedef struct _filter filter; + + +/* append the filter onto the end of the list */ + +extern filter *new_filter +(const char *filt, + filter *filters); + + +/* returns true if the flags are non empty and some are missing from the filter list */ + +extern int is_filtered_out +(const char *flags, + filter *filters); + +/* true if the flag is in the list */ + +extern int it_is +(const char *flag, + const char *flags); + diff --git a/sim/ppc/gen-icache.c b/sim/ppc/gen-icache.c new file mode 100644 index 00000000000..7f5e5e182ae --- /dev/null +++ b/sim/ppc/gen-icache.c @@ -0,0 +1,595 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995, Andrew Cagney + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#include "misc.h" +#include "lf.h" +#include "table.h" + +#include "filter.h" + +#include "ld-decode.h" +#include "ld-cache.h" +#include "ld-insn.h" + +#include "igen.h" + +#include "gen-semantics.h" +#include "gen-idecode.h" +#include "gen-icache.h" + + + +static void +print_icache_function_header(lf *file, + const char *basename, + insn_bits *expanded_bits, + int is_function_definition) +{ + lf_printf(file, "\n"); + lf_print_function_type(file, ICACHE_FUNCTION_TYPE, "EXTERN_ICACHE", " "); + print_function_name(file, + basename, + expanded_bits, + function_name_prefix_icache); + lf_printf(file, "\n(%s)", ICACHE_FUNCTION_FORMAL); + if (!is_function_definition) + lf_printf(file, ";"); + lf_printf(file, "\n"); +} + + +void +print_icache_declaration(insn_table *entry, + lf *file, + void *data, + insn *instruction, + int depth) +{ + if (generate_expanded_instructions) { + ASSERT(entry->nr_insn == 1); + print_icache_function_header(file, + entry->insns->file_entry->fields[insn_name], + entry->expanded_bits, + 0/* is not function definition */); + } + else { + print_icache_function_header(file, + instruction->file_entry->fields[insn_name], + NULL, + 0/* is not function definition */); + } +} + + + +static void +print_icache_extraction(lf *file, + insn *instruction, + char *field_name, + char *field_type, + char *field_expression, + const char *file_name, + int line_nr, + insn_field *cur_field, + insn_bits *bits, + int use_defines, + int get_value_from_cache, + int put_value_in_cache) +{ + ASSERT(field_name != NULL); + if (use_defines && put_value_in_cache) { + /* We've finished with the value - destory it */ + lf_indent_suppress(file); + lf_printf(file, "#undef %s\n", field_name); + return; + } + else if (use_defines && get_value_from_cache) { + lf_indent_suppress(file); + lf_printf(file, "#define %s ", field_name); + } + else { + lf_print__external_reference(file, line_nr, file_name); + lf_printf(file, "%s const %s __attribute__((__unused__)) = ", + field_type == NULL ? "unsigned" : field_type, + field_name); + } + + if (bits != NULL + && ((bits->opcode->is_boolean + && bits->value == 0) + || !bits->opcode->is_boolean) + && strcmp(field_name, cur_field->val_string) == 0) { + /* The field has been made constant (as a result of expanding + instructions or similar) - define a constant variable with the + corresponding value. */ + ASSERT(bits->field == cur_field); + ASSERT(field_type == NULL); + if (bits->opcode->is_boolean) + lf_printf(file, "%d", bits->opcode->boolean_constant); + else if (bits->opcode->last < bits->field->last) + lf_printf(file, "%d", + bits->value << (bits->field->last - bits->opcode->last)); + else + lf_printf(file, "%d", bits->value); + } + else { + /* put the field in the local variable, possibly also enter it + into the cache */ + /* getting it from the cache */ + if (get_value_from_cache || put_value_in_cache) { + lf_printf(file, "cache_entry->crack.%s.%s", + instruction->file_entry->fields[insn_form], + field_name); + if (put_value_in_cache) /* also put it in the cache? */ + lf_printf(file, " = "); + } + if (!get_value_from_cache) { + if (strcmp(field_name, cur_field->val_string) == 0) + lf_printf(file, "EXTRACTED32(instruction, %d, %d)", + i2target(hi_bit_nr, cur_field->first), + i2target(hi_bit_nr, cur_field->last)); + else if (field_expression != NULL) + lf_printf(file, "%s", field_expression); + else + lf_printf(file, "eval_%s", field_name); + } + } + + if (use_defines && get_value_from_cache) + lf_printf(file, "\n"); + else + lf_printf(file, ";\n"); +} + + +void +print_icache_body(lf *file, + insn *instruction, + insn_bits *expanded_bits, + cache_table *cache_rules, + int use_defines, + int get_value_from_cache, + int put_value_in_cache) +{ + insn_field *cur_field; + + /* extract instruction fields */ + lf_printf(file, "/* extraction: %s defines=%d get-value=%d put-value=%d */\n", + instruction->file_entry->fields[insn_format], + use_defines, get_value_from_cache, put_value_in_cache); + + for (cur_field = instruction->fields->first; + cur_field->first < insn_bit_size; + cur_field = cur_field->next) { + if (cur_field->is_string) { + insn_bits *bits; + int found_rule = 0; + /* find any corresponding value */ + for (bits = expanded_bits; + bits != NULL; + bits = bits->last) { + if (bits->field == cur_field) + break; + } + /* try the cache rule table for what to do */ + if (get_value_from_cache || put_value_in_cache) { + cache_table *cache_rule; + for (cache_rule = cache_rules; + cache_rule != NULL; + cache_rule = cache_rule->next) { + if (strcmp(cur_field->val_string, cache_rule->old_name) == 0) { + found_rule = 1; + if (cache_rule->type == compute_value + && put_value_in_cache + && !use_defines) + print_icache_extraction(file, + instruction, + cache_rule->new_name, + cache_rule->type_def, + cache_rule->expression, + cache_rule->file_entry->file_name, + cache_rule->file_entry->line_nr, + cur_field, + bits, + 0 /*use_defines*/, + 0 /*get-value-from-cache*/, + 0 /*put-value-in-cache*/); + else if (cache_rule->type == cache_value) + print_icache_extraction(file, + instruction, + cache_rule->new_name, + cache_rule->type_def, + cache_rule->expression, + cache_rule->file_entry->file_name, + cache_rule->file_entry->line_nr, + cur_field, + bits, + use_defines, + get_value_from_cache, + put_value_in_cache); + } + } + } + if (found_rule == 0) + print_icache_extraction(file, + instruction, + cur_field->val_string, + 0, + 0, + instruction->file_entry->file_name, + instruction->file_entry->line_nr, + cur_field, + bits, + use_defines, + get_value_from_cache, + put_value_in_cache); + /* if any (XXX == 0), output a corresponding test */ + if (instruction->file_entry->annex != NULL) { + char *field_name = cur_field->val_string; + char *is_0_ptr = instruction->file_entry->annex; + int field_len = strlen(field_name); + if (strlen(is_0_ptr) >= (strlen("_is_0") + field_len)) { + is_0_ptr += field_len; + while ((is_0_ptr = strstr(is_0_ptr, "_is_0")) != NULL) { + if (strncmp(is_0_ptr - field_len, field_name, field_len) == 0 + && !isalpha(is_0_ptr[ - field_len - 1])) { + if (!use_defines || (use_defines && get_value_from_cache)) { + if (use_defines) { + lf_indent_suppress(file); + lf_printf(file, "#define %s_is_0 ", field_name); + } + else { + table_entry_print_cpp_line_nr(file, instruction->file_entry); + lf_printf(file, "const unsigned %s_is_0 __attribute__((__unused__)) = ", + field_name); + } + if (bits != NULL) + lf_printf(file, "(%d == 0)", bits->value); + else + lf_printf(file, "(%s == 0)", field_name); + if (use_defines) + lf_printf(file, "\n"); + else + lf_printf(file, ";\n"); + } + else if (use_defines && put_value_in_cache) { + lf_indent_suppress(file); + lf_printf(file, "#undef %s_is_0\n", field_name); + } + break; + } + is_0_ptr += strlen("_is_0"); + } + } + } + /* any thing else ... */ + } + } + lf_print__internal_reference(file); +} + + + +typedef struct _icache_tree icache_tree; +struct _icache_tree { + char *name; + icache_tree *next; + icache_tree *children; +}; + +static icache_tree * +icache_tree_insert(icache_tree *tree, + char *name) +{ + icache_tree *new_tree; + /* find it */ + icache_tree **ptr_to_cur_tree = &tree->children; + icache_tree *cur_tree = *ptr_to_cur_tree; + while (cur_tree != NULL + && strcmp(cur_tree->name, name) < 0) { + ptr_to_cur_tree = &cur_tree->next; + cur_tree = *ptr_to_cur_tree; + } + ASSERT(cur_tree == NULL + || strcmp(cur_tree->name, name) >= 0); + /* already in the tree */ + if (cur_tree != NULL + && strcmp(cur_tree->name, name) == 0) + return cur_tree; + /* missing, insert it */ + ASSERT(cur_tree == NULL + || strcmp(cur_tree->name, name) > 0); + new_tree = ZALLOC(icache_tree); + new_tree->name = name; + new_tree->next = cur_tree; + *ptr_to_cur_tree = new_tree; + return new_tree; +} + + +static icache_tree * +insn_table_cache_fields(insn_table *table) +{ + icache_tree *tree = ZALLOC(icache_tree); + insn *instruction; + for (instruction = table->insns; + instruction != NULL; + instruction = instruction->next) { + insn_field *field; + icache_tree *form = + icache_tree_insert(tree, + instruction->file_entry->fields[insn_form]); + for (field = instruction->fields->first; + field != NULL; + field = field->next) { + if (field->is_string) + icache_tree_insert(form, field->val_string); + } + } + return tree; +} + + + +extern void +print_icache_struct(insn_table *instructions, + cache_table *cache_rules, + lf *file) +{ + icache_tree *tree = insn_table_cache_fields(instructions); + + lf_printf(file, "#define WITH_IDECODE_CACHE_SIZE %d\n", + (code & generate_with_icache) ? icache_size : 0); + lf_printf(file, "\n"); + + /* create an instruction cache if being used */ + if ((code & generate_with_icache)) { + icache_tree *form; + lf_printf(file, "typedef struct _idecode_cache {\n"); + lf_printf(file, " unsigned_word address;\n"); + lf_printf(file, " void *semantic;\n"); + lf_printf(file, " union {\n"); + for (form = tree->children; + form != NULL; + form = form->next) { + icache_tree *field; + lf_printf(file, " struct {\n"); + for (field = form->children; + field != NULL; + field = field->next) { + cache_table *cache_rule; + int found_rule = 0; + for (cache_rule = cache_rules; + cache_rule != NULL; + cache_rule = cache_rule->next) { + if (strcmp(field->name, cache_rule->old_name) == 0) { + found_rule = 1; + if (cache_rule->new_name != NULL) + lf_printf(file, " %s %s; /* %s */\n", + (cache_rule->type_def == NULL + ? "unsigned" + : cache_rule->type_def), + cache_rule->new_name, + cache_rule->old_name); + } + } + if (!found_rule) + lf_printf(file, " unsigned %s;\n", field->name); + } + lf_printf(file, " } %s;\n", form->name); + } + lf_printf(file, " } crack;\n"); + lf_printf(file, "} idecode_cache;\n"); + } + else { + /* alernativly, since no cache, #define the fields to be + extractions from the instruction variable. Emit a dummy + definition for idecode_cache to allow model_issue to not + be #ifdefed at the call level */ + cache_table *cache_rule; + lf_printf(file, "\n"); + lf_printf(file, "typedef void idecode_cache;\n"); + lf_printf(file, "\n"); + for (cache_rule = cache_rules; + cache_rule != NULL; + cache_rule = cache_rule->next) { + if (cache_rule->expression != NULL + && strlen(cache_rule->expression) > 0) + lf_printf(file, "#define %s %s\n", + cache_rule->new_name, cache_rule->expression); + } + } +} + + + +static void +print_icache_function(lf *file, + insn *instruction, + insn_bits *expanded_bits, + opcode_field *opcodes, + cache_table *cache_rules) +{ + int indent; + + /* generate code to enter decoded instruction into the icache */ + lf_printf(file, "\n"); + lf_print_function_type(file, ICACHE_FUNCTION_TYPE, "EXTERN_ICACHE", "\n"); + indent = print_function_name(file, + instruction->file_entry->fields[insn_name], + expanded_bits, + function_name_prefix_icache); + lf_indent(file, +indent); + lf_printf(file, "(%s)\n", ICACHE_FUNCTION_FORMAL); + lf_indent(file, -indent); + + /* function header */ + lf_printf(file, "{\n"); + lf_indent(file, +2); + + print_define_my_index(file, instruction->file_entry); + print_itrace(file, instruction->file_entry, 1/*putting-value-in-cache*/); + + print_idecode_validate(file, instruction, opcodes); + + lf_printf(file, "\n"); + lf_printf(file, "{\n"); + lf_indent(file, +2); + print_icache_body(file, + instruction, + expanded_bits, + cache_rules, + 0/*use_defines*/, + 0/*get_value_from_cache*/, + 1/*put_value_in_cache*/); + + if ((code & generate_with_semantic_icache)) { + lf_printf(file, "unsigned_word nia;\n"); + lf_printf(file, "cache_entry->address = cia;\n"); + lf_printf(file, "cache_entry->semantic = "); + print_function_name(file, + instruction->file_entry->fields[insn_name], + expanded_bits, + function_name_prefix_semantics); + lf_printf(file, ";\n"); + print_semantic_body(file, + instruction, + expanded_bits, + opcodes); + lf_printf(file, "\n"); + lf_printf(file, "return nia;\n"); + } + lf_indent(file, -2); + lf_printf(file, "}\n"); + + if (!(code & generate_with_semantic_icache)) { + /* return the function propper (main sorts this one out) */ + lf_printf(file, "\n"); + lf_printf(file, "/* semantic routine */\n"); + table_entry_print_cpp_line_nr(file, instruction->file_entry); + lf_printf(file, "return "); + print_function_name(file, + instruction->file_entry->fields[insn_name], + expanded_bits, + function_name_prefix_semantics); + lf_printf(file, ";\n"); + lf_print__internal_reference(file); + } + + lf_indent(file, -2); + lf_printf(file, "}\n"); +} + + +void +print_icache_definition(insn_table *entry, + lf *file, + void *data, + insn *instruction, + int depth) +{ + cache_table *cache_rules = (cache_table*)data; + if (generate_expanded_instructions) { + ASSERT(entry->nr_insn == 1 + && entry->opcode == NULL + && entry->parent != NULL + && entry->parent->opcode != NULL); + ASSERT(entry->nr_insn == 1 + && entry->opcode == NULL + && entry->parent != NULL + && entry->parent->opcode != NULL + && entry->parent->opcode_rule != NULL); + print_icache_function(file, + entry->insns, + entry->expanded_bits, + entry->opcode, + cache_rules); + } + else { + print_icache_function(file, + instruction, + NULL, + NULL, + cache_rules); + } +} + + + +void +print_icache_internal_function_declaration(insn_table *table, + lf *file, + void *data, + table_entry *function) +{ + ASSERT((code & generate_with_icache) != 0); + if (it_is("internal", function->fields[insn_flags])) { + lf_printf(file, "\n"); + lf_print_function_type(file, ICACHE_FUNCTION_TYPE, "INLINE_ICACHE", + "\n"); + print_function_name(file, + function->fields[insn_name], + NULL, + function_name_prefix_icache); + lf_printf(file, "\n(%s);\n", ICACHE_FUNCTION_FORMAL); + } +} + + +void +print_icache_internal_function_definition(insn_table *table, + lf *file, + void *data, + table_entry *function) +{ + ASSERT((code & generate_with_icache) != 0); + if (it_is("internal", function->fields[insn_flags])) { + lf_printf(file, "\n"); + lf_print_function_type(file, ICACHE_FUNCTION_TYPE, "INLINE_ICACHE", + "\n"); + print_function_name(file, + function->fields[insn_name], + NULL, + function_name_prefix_icache); + lf_printf(file, "\n(%s)\n", ICACHE_FUNCTION_FORMAL); + lf_printf(file, "{\n"); + lf_indent(file, +2); + lf_printf(file, "/* semantic routine */\n"); + table_entry_print_cpp_line_nr(file, function); + if ((code & generate_with_semantic_icache)) { + lf_print__c_code(file, function->annex); + lf_printf(file, "error(\"Internal function must longjump\\n\");\n"); + lf_printf(file, "return 0;\n"); + } + else { + lf_printf(file, "return "); + print_function_name(file, + function->fields[insn_name], + NULL, + function_name_prefix_semantics); + lf_printf(file, ";\n"); + } + + lf_print__internal_reference(file); + lf_indent(file, -2); + lf_printf(file, "}\n"); + } +} diff --git a/sim/ppc/gen-icache.h b/sim/ppc/gen-icache.h new file mode 100644 index 00000000000..70f24b5c17d --- /dev/null +++ b/sim/ppc/gen-icache.h @@ -0,0 +1,56 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995, Andrew Cagney + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + + +/* Output code to manipulate the instruction cache: either create it + or reference it */ + +extern void print_icache_body +(lf *file, + insn *instruction, + insn_bits *expanded_bits, + cache_table *cache_rules, + int use_defines, + int get_value_from_cache, + int put_value_in_cache); + + +/* Output an instruction cache decode function */ + +extern insn_handler print_icache_declaration; +extern insn_handler print_icache_definition; + + +/* Output an instruction cache support function */ + +extern function_handler print_icache_internal_function_declaration; +extern function_handler print_icache_internal_function_definition; + + +/* Output the instruction cache table data structure */ + +extern void print_icache_struct +(insn_table *instructions, + cache_table *cache_rules, + lf *file); + + +/* Output a single instructions decoder */ diff --git a/sim/ppc/gen-idecode.c b/sim/ppc/gen-idecode.c new file mode 100644 index 00000000000..1c4c6bf58a5 --- /dev/null +++ b/sim/ppc/gen-idecode.c @@ -0,0 +1,1282 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995, Andrew Cagney + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + +#include "misc.h" +#include "lf.h" +#include "table.h" + +#include "filter.h" + +#include "ld-decode.h" +#include "ld-cache.h" +#include "ld-insn.h" + +#include "igen.h" + +#include "gen-idecode.h" +#include "gen-icache.h" +#include "gen-semantics.h" + + + +static void +lf_print_opcodes(lf *file, + insn_table *table) +{ + if (table != NULL) { + while (1) { + lf_printf(file, "_%d_%d", + table->opcode->first, + table->opcode->last); + if (table->parent == NULL) break; + lf_printf(file, "__%d", table->opcode_nr); + table = table->parent; + } + } +} + +/****************************************************************/ + + +static void +lf_print_table_name(lf *file, + insn_table *table) +{ + lf_printf(file, "idecode_table"); + lf_print_opcodes(file, table); +} + + + +static void +print_idecode_table(lf *file, + insn_table *entry, + const char *result) +{ + /* int can_assume_leaf; */ + decode_table *opcode_rule; + + /* have a look at the rule table, if all table rules follow all + switch rules, I can assume that all end points are leaves */ + opcode_rule = entry->opcode_rule; + while (opcode_rule != NULL + && (opcode_rule->gen == switch_gen + || opcode_rule->gen == padded_switch_gen)) + opcode_rule = opcode_rule->next; + +#if 0 + /* FIXME: I don't get this bit! */ + while (opcode_rule != NULL + && (opcode_rule->gen == switch_gen + || opcode_rule->gen == padded_switch_gen) + && opcode_rule->type != normal_decode_rule) + opcode_rule = opcode_rule->next; + can_assume_leaf = opcode_rule == NULL; +#endif + + lf_printf(file, "idecode_table_entry *table = "); + lf_print_table_name(file, entry); + lf_printf(file, ";\n"); + lf_printf(file, "int opcode = EXTRACTED32(instruction, %d, %d);\n", + i2target(hi_bit_nr, entry->opcode->first), + i2target(hi_bit_nr, entry->opcode->last)); + lf_printf(file, "idecode_table_entry *table_entry = table + opcode;\n"); + lf_printf(file, "while (1) {\n"); + lf_indent(file, +2); + { + lf_printf(file, "/* nonzero mask -> another table */\n"); + lf_printf(file, "while (table_entry->shift >= 0) {\n"); + lf_indent(file, +2); + { + lf_printf(file, "table = ((idecode_table_entry*)\n"); + lf_printf(file, " table_entry->function_or_table);\n"); + lf_printf(file, "opcode = ((instruction & table_entry->mask)\n"); + lf_printf(file, " >> table_entry->shift);\n"); + lf_printf(file, "table_entry = table + opcode;\n"); + } + lf_indent(file, -2); + lf_printf(file, "}\n"); + lf_printf(file, "ASSERT(table_entry->shift < 0);\n"); + lf_printf(file, "/* found the leaf */\n"); + lf_printf(file, "if (table_entry->shift == table_function_entry) {\n"); + lf_indent(file, +2); + if ((code & generate_jumps)) { + lf_printf(file, "goto *table_entry->function_or_table;\n"); + } + else { + lf_printf(file, "%s ", result); + if ((code & generate_with_icache)) { + lf_printf(file, "(((idecode_icache*)table_entry->function_or_table)\n"); + lf_printf(file, " (%s));\n", ICACHE_FUNCTION_ACTUAL); + } + else { + lf_printf(file, "((idecode_semantic*)table_entry->function_or_table)\n"); + lf_printf(file, " (%s);\n", SEMANTIC_FUNCTION_ACTUAL); + } + } + lf_printf(file, "break;\n"); + lf_indent(file, -2); + lf_printf(file, "}\n"); + lf_printf(file, "/* must be a boolean */\n"); + lf_printf(file, "opcode = (((instruction << table_entry->left)\n"); + lf_printf(file, " >> table_entry->right)\n"); + lf_printf(file, " != table_entry->mask);\n"); + lf_printf(file, "table = ((idecode_table_entry*)\n"); + lf_printf(file, " table_entry->function_or_table);\n"); + lf_printf(file, "table_entry = table + opcode;\n"); + } + lf_indent(file, -2); + lf_printf(file, "}\n"); +} + + +static void +print_idecode_table_start(insn_table *table, + lf *file, + void *data, + int depth) +{ + ASSERT(depth == 0); + /* start of the table */ + if (table->opcode_rule->gen == array_gen) { + lf_printf(file, "\n"); + lf_printf(file, "static idecode_table_entry "); + lf_print_table_name(file, table); + lf_printf(file, "[] = {\n"); + } +} + +static void +print_idecode_table_leaf(insn_table *entry, + lf *file, + void *data, + insn *instruction, + int depth) +{ + ASSERT(entry->parent != NULL); + ASSERT(depth == 0); + + /* add an entry to the table */ + if (entry->parent->opcode_rule->gen == array_gen) { + if (entry->opcode == NULL) { + /* table leaf entry */ + lf_printf(file, " /*%d*/ { table_function_entry, 0, 0, 0, ", entry->opcode_nr); + if ((code & generate_jumps)) + lf_printf(file, "&&"); + print_function_name(file, + entry->insns->file_entry->fields[insn_name], + entry->expanded_bits, + ((code & generate_with_icache) + ? function_name_prefix_icache + : function_name_prefix_semantics)); + lf_printf(file, " },\n"); + } + else if (entry->opcode_rule->gen == switch_gen + || entry->opcode_rule->gen == padded_switch_gen) { + /* table calling switch statement */ + lf_printf(file, " /*%d*/ { table_function_entry, 0, 0, 0, ", + entry->opcode_nr); + if ((code & generate_jumps)) + lf_printf(file, "&&"); + lf_print_table_name(file, entry); + lf_printf(file, " },\n"); + } + else { + /* table `calling' another table */ + lf_printf(file, " /*%d*/ { ", entry->opcode_nr); + if (entry->opcode->is_boolean) + lf_printf(file, "table_boolean_entry, %d, %d, %d, ", + entry->opcode->first, + insn_bit_size - entry->opcode->last + entry->opcode->first - 1, + entry->opcode->boolean_constant); + else + lf_printf(file, "%d, 0, 0, MASK32(%d,%d), ", + insn_bit_size - entry->opcode->last - 1, + i2target(hi_bit_nr, entry->opcode->first), + i2target(hi_bit_nr, entry->opcode->last)); + lf_print_table_name(file, entry); + lf_printf(file, " },\n"); + } + } +} + +static void +print_idecode_table_end(insn_table *table, + lf *file, + void *data, + int depth) +{ + ASSERT(depth == 0); + if (table->opcode_rule->gen == array_gen) { + lf_printf(file, "};\n"); + } +} + +static void +print_idecode_table_padding(insn_table *table, + lf *file, + void *data, + int depth, + int opcode_nr) +{ + ASSERT(depth == 0); + if (table->opcode_rule->gen == array_gen) { + lf_printf(file, " /*%d*/ { table_function_entry, 0, 0, 0, ", opcode_nr); + if ((code & generate_jumps)) + lf_printf(file, "&&"); + lf_printf(file, "%s_illegal },\n", + ((code & generate_with_icache) ? "icache" : "semantic")); + } +} + + +/****************************************************************/ + + +void print_idecode_switch +(lf *file, + insn_table *table, + const char *result); + + +static void +idecode_switch_start(insn_table *table, + lf *file, + void *data, + int depth) +{ + /* const char *result = data; */ + ASSERT(depth == 0); + ASSERT(table->opcode_rule->gen == switch_gen + || table->opcode_rule->gen == padded_switch_gen + || table->opcode_rule->gen == goto_gen); + + switch (table->opcode_rule->gen) { + default: + lf_printf(file, "switch (EXTRACTED32(instruction, %d, %d)) {\n", + i2target(hi_bit_nr, table->opcode->first), + i2target(hi_bit_nr, table->opcode->last)); + break; + } +} + + +static void +idecode_switch_leaf(insn_table *entry, + lf *file, + void *data, + insn *instruction, + int depth) +{ + const char *result = data; + ASSERT(entry->parent != NULL); + ASSERT(depth == 0); + ASSERT(entry->parent->opcode_rule->gen == switch_gen + || entry->parent->opcode_rule->gen == padded_switch_gen); + ASSERT(entry->parent->opcode); + + if (entry->parent->opcode->is_boolean + && entry->opcode_nr == 0) + lf_printf(file, "case %d:\n", entry->parent->opcode->boolean_constant); + else if (!entry->parent->opcode->is_boolean) + lf_printf(file, "case %d:\n", entry->opcode_nr); + else + lf_printf(file, "default:\n"); + lf_indent(file, +2); + { + if (entry->opcode == NULL) { + /* switch calling leaf */ + if ((code & generate_jumps)) + lf_printf(file, "goto "); + if ((code & generate_calls)) + lf_printf(file, "%s ", result); + print_function_name(file, + entry->insns->file_entry->fields[insn_name], + entry->expanded_bits, + ((code & generate_with_icache) + ? function_name_prefix_icache + : function_name_prefix_semantics)); + if ((code & generate_calls)) + lf_printf(file, "(%s)", SEMANTIC_FUNCTION_ACTUAL); + lf_printf(file, ";\n"); + } + else if (entry->opcode_rule->gen == switch_gen + || entry->opcode_rule->gen == padded_switch_gen) { + /* switch calling switch */ + print_idecode_switch(file, entry, result); + } + else { + /* switch looking up a table */ + lf_printf(file, "{\n"); + lf_indent(file, -2); + print_idecode_table(file, entry, result); + lf_indent(file, -2); + lf_printf(file, "}\n"); + } + lf_printf(file, "break;\n"); + } + lf_indent(file, -2); +} + + +static void +print_idecode_switch_illegal(lf *file, + const char *result) +{ + lf_indent(file, +2); + print_idecode_illegal(file, result); + /*lf_printf(file, "break;\n");*/ + lf_indent(file, -2); +} + +static void +idecode_switch_end(insn_table *table, + lf *file, + void *data, + int depth) +{ + const char *result = data; + ASSERT(depth == 0); + ASSERT(table->opcode_rule->gen == switch_gen + || table->opcode_rule->gen == padded_switch_gen + || table->opcode_rule->gen == goto_gen); + ASSERT(table->opcode); + + if (!table->opcode->is_boolean) { + lf_printf(file, "default:\n"); + switch (table->opcode_rule->gen) { + case switch_gen: + print_idecode_switch_illegal(file, result); + break; + case padded_switch_gen: + lf_printf(file, " error(\"Internal error - bad switch generated\\n\");\n"); + lf_printf(file, " break;\n"); + break; + default: + error("idecode_switch_end - unknown switch type\n"); + } + } + lf_printf(file, "}\n"); +} + +static void +idecode_switch_padding(insn_table *table, + lf *file, + void *data, + int depth, + int opcode_nr) +{ + const char *result = data; + ASSERT(depth == 0); + ASSERT(table->opcode_rule->gen == switch_gen + || table->opcode_rule->gen == padded_switch_gen); + + if (table->opcode_rule->gen == padded_switch_gen) { + lf_printf(file, "case %d:\n", opcode_nr); + print_idecode_switch_illegal(file, result); + } + else if (table->opcode_rule->gen == goto_gen) { + lf_printf(file, "goto_%d:\n", opcode_nr); + print_idecode_switch_illegal(file, result); + } +} + + +void +print_idecode_switch(lf *file, + insn_table *table, + const char *result) +{ + insn_table_traverse_tree(table, + file, (void*)result, + 0, + idecode_switch_start, + idecode_switch_leaf, + idecode_switch_end, + idecode_switch_padding); +} + + +static void +print_idecode_switch_function_header(lf *file, + insn_table *table, + int is_function_definition) +{ + lf_printf(file, "\n"); + if ((code & generate_calls)) { + lf_printf(file, "static "); + if ((code & generate_with_icache)) + lf_printf(file, "idecode_semantic *"); + else + lf_printf(file, "unsigned_word"); + if (is_function_definition) + lf_printf(file, "\n"); + else + lf_printf(file, " "); + lf_print_table_name(file, table); + lf_printf(file, "\n(%s)", ICACHE_FUNCTION_FORMAL); + if (!is_function_definition) + lf_printf(file, ";"); + lf_printf(file, "\n"); + } + if ((code & generate_jumps) && is_function_definition) { + lf_indent(file, -1); + lf_print_table_name(file, table); + lf_printf(file, ":\n"); + lf_indent(file, +1); + } +} + + +static void +idecode_declare_if_switch(insn_table *table, + lf *file, + void *data, + int depth) +{ + if ((table->opcode_rule->gen == switch_gen + || table->opcode_rule->gen == padded_switch_gen) + && table->parent != NULL /* don't declare the top one yet */ + && table->parent->opcode_rule->gen == array_gen) { + print_idecode_switch_function_header(file, + table, + 0/*isnt function definition*/); + } +} + + +static void +idecode_expand_if_switch(insn_table *table, + lf *file, + void *data, + int depth) +{ + if ((table->opcode_rule->gen == switch_gen + || table->opcode_rule->gen == padded_switch_gen) + && table->parent != NULL /* don't expand the top one yet */ + && table->parent->opcode_rule->gen == array_gen) { + print_idecode_switch_function_header(file, + table, + 1/*is function definition*/); + if ((code & generate_calls)) { + lf_printf(file, "{\n"); + lf_indent(file, +2); + } + print_idecode_switch(file, table, "return"); + if ((code & generate_calls)) { + lf_indent(file, -2); + lf_printf(file, "}\n"); + } + } +} + + +/****************************************************************/ + + +static void +print_idecode_lookups(lf *file, + insn_table *table, + cache_table *cache_rules) +{ + int depth; + + /* output switch function declarations where needed by tables */ + insn_table_traverse_tree(table, + file, NULL, + 1, + idecode_declare_if_switch, /* START */ + NULL, NULL, NULL); + + /* output tables where needed */ + for (depth = insn_table_depth(table); + depth > 0; + depth--) { + insn_table_traverse_tree(table, + file, NULL, + 1-depth, + print_idecode_table_start, + print_idecode_table_leaf, + print_idecode_table_end, + print_idecode_table_padding); + } + + /* output switch functions where needed */ + insn_table_traverse_tree(table, + file, NULL, + 1, + idecode_expand_if_switch, /* START */ + NULL, NULL, NULL); +} + + +static void +print_idecode_body(lf *file, + insn_table *table, + const char *result, + const char *indent) +{ + lf_indent(file, +strlen(indent)); + lf_putstr(file, "{\n"); + lf_indent(file, +2); + if (table->opcode_rule->gen == switch_gen + || table->opcode_rule->gen == padded_switch_gen) + print_idecode_switch(file, table, result); + else + print_idecode_table(file, table, result); + lf_indent(file, -2); + lf_putstr(file, "}\n"); + lf_indent(file, -strlen(indent)); +} + + +/****************************************************************/ + + +static void +print_run_until_stop_body(lf *file, + insn_table *table, + int can_stop) +{ + /* Output the function to execute real code: + + Unfortunatly, there are multiple cases to consider vis: + + X X X X ... + + Consequently this function is written in multiple different ways */ + + lf_putstr(file, "{\n"); + lf_indent(file, +2); + if (!can_stop) + lf_putstr(file, "int *keep_running = NULL;\n"); + lf_putstr(file, "jmp_buf halt;\n"); + lf_putstr(file, "jmp_buf restart;\n"); + lf_putstr(file, "cpu *processor = NULL;\n"); + lf_putstr(file, "unsigned_word cia = -1;\n"); + lf_putstr(file, "instruction_word instruction = 0;\n"); + if (generate_smp) { + lf_putstr(file, "int current_cpu = -1;\n"); + } + if ((code & generate_with_icache)) { + lf_putstr(file, "idecode_cache *cache_entry = NULL;\n"); + } + + if ((code & generate_with_icache)) { + lf_putstr(file, "\n"); + lf_putstr(file, "{\n"); + lf_putstr(file, " int cpu_nr;\n"); + lf_putstr(file, " for (cpu_nr = 0; cpu_nr < nr_cpus; cpu_nr++)\n"); + lf_putstr(file, " cpu_flush_icache(processors[cpu_nr]);\n"); + lf_putstr(file, "}\n"); + } + + lf_putstr(file, "\n"); + lf_putstr(file, "psim_set_halt_and_restart(system, &halt, &restart);\n"); + + lf_putstr(file, "\n"); + lf_putstr(file, "if (setjmp(halt))\n"); + lf_putstr(file, " return;\n"); + + lf_putstr(file, "\n"); + lf_putstr(file, "setjmp(restart);\n"); + + if (!generate_smp) { + + lf_putstr(file, " +/* CASE 1: NO SMP (with or with out instruction cache). + + In this case, we can take advantage of the fact that the current + instruction address does not need to be returned to the cpu object + after every execution of an instruction. Instead it only needs to + be saved when either A. the main loop exits or B. A cpu-halt or + cpu-restart call forces the loop to be re-enered. The later + functions always save the current cpu instruction address. + + Two subcases also exist that with and that without an instruction + cache. */"); + + lf_putstr(file, "\n\n"); + + lf_putstr(file, "processor = processors[0];\n"); + lf_putstr(file, "cia = cpu_get_program_counter(processor);\n"); + lf_putstr(file, "while (1) {\n"); + lf_indent(file, +2); + lf_putstr(file, "if (WITH_EVENTS) {\n"); + lf_putstr(file, " if (event_queue_tick(events)) {\n"); + lf_putstr(file, " cpu_set_program_counter(processor, cia);\n"); + lf_putstr(file, " event_queue_process(events);\n"); + lf_putstr(file, " cia = cpu_get_program_counter(processor);\n"); + lf_putstr(file, " }\n"); + lf_putstr(file, "}\n"); + + if (!(code & generate_with_icache)) { + lf_putstr(file, "instruction = vm_instruction_map_read(cpu_instruction_map(processor), processor, cia);\n"); + print_idecode_body(file, table, "cia =", ""); + } + + if ((code & generate_with_icache)) { + lf_putstr(file, "cache_entry = cpu_icache_entry(processor, cia);\n"); + lf_putstr(file, "if (cache_entry->address == cia) {\n"); + lf_putstr(file, " /* cache hit */\n"); + lf_putstr(file, " idecode_semantic *const semantic = cache_entry->semantic;\n"); + lf_putstr(file, " cia = semantic(processor, cache_entry, cia);\n"); + lf_putstr(file, "}\n"); + lf_putstr(file, "else {\n"); + lf_putstr(file, " /* cache miss */\n"); + if (!(code & generate_with_semantic_icache)) { + lf_indent(file, +2); + lf_putstr(file, "idecode_semantic *semantic;\n"); + lf_indent(file, -2); + } + lf_putstr(file, " instruction = vm_instruction_map_read(cpu_instruction_map(processor), processor, cia);\n"); + lf_putstr(file, " if (WITH_MON != 0)\n"); + lf_putstr(file, " mon_event(mon_event_icache_miss, processor, cia);\n"); + if ((code & generate_with_semantic_icache)) { + print_idecode_body(file, table, "cia =", " "); + } + else { + print_idecode_body(file, table, "semantic =", " "); + lf_putstr(file, " cia = semantic(processor, cache_entry, cia);\n"); + } + lf_putstr(file, "}\n"); + } + + lf_putstr(file, "if (keep_running != NULL && !*keep_running)\n"); + lf_putstr(file, " cpu_halt(processor, cia, was_continuing, 0/*ignore*/);\n"); + lf_indent(file, -2); + lf_putstr(file, "}\n"); + } + + if (generate_smp) { + + lf_putstr(file, " +/* CASE 2: SMP (With or without ICACHE) + + The complexity here comes from needing to correctly restart the + system when it is aborted. In particular if cpu0 requests a + restart, the next cpu is still cpu1. Cpu0 being restarted after + all the other CPU's and the event queue have been processed */"); + + lf_putstr(file, "\n\n"); + + lf_putstr(file, "current_cpu = psim_last_cpu(system);\n"); + lf_putstr(file, "while (1) {\n"); + lf_indent(file, +2); + lf_putstr(file, "if (WITH_EVENTS) {\n"); + lf_putstr(file, " current_cpu += 1;\n"); + lf_putstr(file, " if (current_cpu == nr_cpus) {\n"); + lf_putstr(file, " if (event_queue_tick(events)) {\n"); + lf_putstr(file, " event_queue_process(events);\n"); + lf_putstr(file, " }\n"); + lf_putstr(file, " current_cpu = 0;\n"); + lf_putstr(file, " }\n"); + lf_putstr(file, "}\n"); + lf_putstr(file, "else {\n"); + lf_putstr(file, " current_cpu = (current_cpu + 1) % nr_cpus;\n"); + lf_putstr(file, "}\n"); + lf_putstr(file, "processor = processors[current_cpu];\n"); + lf_putstr(file, "cia = cpu_get_program_counter(processor);\n"); + + if (!(code & generate_with_icache)) { + lf_putstr(file, "instruction = vm_instruction_map_read(cpu_instruction_map(processor), processor, cia);\n"); + print_idecode_body(file, table, "cia =", ""); + } + + if ((code & generate_with_icache)) { + lf_putstr(file, "cache_entry = cpu_icache_entry(processor, cia);\n"); + lf_putstr(file, "if (cache_entry->address == cia) {\n"); + lf_putstr(file, " /* cache hit */\n"); + lf_putstr(file, " idecode_semantic *semantic = cache_entry->semantic;\n"); + lf_putstr(file, " cia = semantic(processor, cache_entry, cia);\n"); + lf_putstr(file, "}\n"); + lf_putstr(file, "else {\n"); + lf_putstr(file, " /* cache miss */\n"); + if (!(code & generate_with_semantic_icache)) { + lf_indent(file, +2); + lf_putstr(file, " idecode_semantic *semantic;\n"); + lf_indent(file, -2); + } + lf_putstr(file, " instruction =\n"); + lf_putstr(file, " vm_instruction_map_read(cpu_instruction_map(processor), processor, cia);\n"); + lf_putstr(file, " if (WITH_MON != 0)\n"); + lf_putstr(file, " mon_event(mon_event_icache_miss, processors[current_cpu], cia);\n"); + if ((code & generate_with_semantic_icache)) { + print_idecode_body(file, table, "cia =", " "); + } + else { + print_idecode_body(file, table, "semantic = ", " "); + lf_indent(file, +2); + lf_putstr(file, "cia = semantic(processor, cache_entry, cia));\n"); + lf_indent(file, -2); + } + lf_putstr(file, "}\n"); + } + + lf_putstr(file, "if (keep_running != NULL && !*keep_running)\n"); + lf_putstr(file, " cpu_halt(processor, cia, was_continuing, 0/*ignore*/);\n"); + lf_putstr(file, "cpu_set_program_counter(processor, cia);\n"); + lf_indent(file, -2); + lf_putstr(file, "}\n"); + } + + + lf_indent(file, -2); + lf_putstr(file, "}\n"); +} + + +/****************************************************************/ + +static void +print_jump(lf *file, + int is_tail) +{ + if (is_tail) { + lf_putstr(file, "if (keep_running != NULL && !*keep_running)\n"); + lf_putstr(file, " cpu_halt(processor, nia, was_continuing, 0/*na*/);\n"); + } + + if (!generate_smp) { + lf_putstr(file, "if (WITH_EVENTS) {\n"); + lf_putstr(file, " if (event_queue_tick(events)) {\n"); + lf_putstr(file, " cpu_set_program_counter(processor, nia);\n"); + lf_putstr(file, " event_queue_process(events);\n"); + lf_putstr(file, " nia = cpu_get_program_counter(processor);\n"); + lf_putstr(file, " }\n"); + lf_putstr(file, "}\n"); + } + + if (generate_smp) { + lf_putstr(file, "cpu_set_program_counter(processor, nia);\n"); + lf_putstr(file, "if (WITH_EVENTS) {\n"); + lf_putstr(file, " current_cpu += 1;\n"); + lf_putstr(file, " if (current_cpu == nr_cpus) {\n"); + lf_putstr(file, " if (event_queue_tick(events)) {\n"); + lf_putstr(file, " event_queue_process(events);\n"); + lf_putstr(file, " }\n"); + lf_putstr(file, " current_cpu = 0;\n"); + lf_putstr(file, " }\n"); + lf_putstr(file, "}\n"); + lf_putstr(file, "else {\n"); + lf_putstr(file, " current_cpu = (current_cpu + 1) % nr_cpus;\n"); + lf_putstr(file, "}\n"); + lf_putstr(file, "processor = processors[current_cpu];\n"); + lf_putstr(file, "nia = cpu_get_program_counter(processor);\n"); + } + + if ((code & generate_with_icache)) { + lf_putstr(file, "cache_entry = cpu_icache_entry(processor, nia);\n"); + lf_putstr(file, "if (cache_entry->address == nia) {\n"); + lf_putstr(file, " /* cache hit */\n"); + lf_putstr(file, " goto *cache_entry->semantic;\n"); + lf_putstr(file, "}\n"); + if (is_tail) { + lf_putstr(file, "goto cache_miss;\n"); + } + } + + if (!(code & generate_with_icache)) { + lf_printf(file, "goto idecode;\n"); + } + +} + + + + + +static void +print_jump_insn(lf *file, + insn *instruction, + insn_bits *expanded_bits, + opcode_field *opcodes, + cache_table *cache_rules) +{ + + /* what we are for the moment */ + lf_printf(file, "\n"); + print_define_my_index(file, instruction->file_entry); + + /* output the icache entry */ + if ((code & generate_with_icache)) { + lf_printf(file, "\n"); + lf_indent(file, -1); + print_function_name(file, + instruction->file_entry->fields[insn_name], + expanded_bits, + function_name_prefix_icache); + lf_printf(file, ":\n"); + lf_indent(file, +1); + lf_printf(file, "{\n"); + lf_indent(file, +2); + lf_putstr(file, "const unsigned_word cia = nia;\n"); + print_itrace(file, instruction->file_entry, 1/*putting-value-in-cache*/); + print_idecode_validate(file, instruction, opcodes); + lf_printf(file, "\n"); + lf_printf(file, "{\n"); + lf_indent(file, +2); + print_icache_body(file, + instruction, + expanded_bits, + cache_rules, + 0, + 0/*get_value_from_cache*/, + 1/*put_value_in_cache*/); + lf_printf(file, "cache_entry->address = nia;\n"); + lf_printf(file, "cache_entry->semantic = &&"); + print_function_name(file, + instruction->file_entry->fields[insn_name], + expanded_bits, + function_name_prefix_semantics); + lf_printf(file, ";\n"); + if ((code & generate_with_semantic_icache)) { + print_semantic_body(file, + instruction, + expanded_bits, + opcodes); + print_jump(file, 1/*is-tail*/); + } + else { + lf_printf(file, "/* goto "); + print_function_name(file, + instruction->file_entry->fields[insn_name], + expanded_bits, + function_name_prefix_semantics); + lf_printf(file, "; */\n"); + } + lf_indent(file, -2); + lf_putstr(file, "}\n"); + lf_indent(file, -2); + lf_printf(file, "}\n"); + } + + /* print the semantics */ + lf_printf(file, "\n"); + lf_indent(file, -1); + print_function_name(file, + instruction->file_entry->fields[insn_name], + expanded_bits, + function_name_prefix_semantics); + lf_printf(file, ":\n"); + lf_indent(file, +1); + lf_printf(file, "{\n"); + lf_indent(file, +2); + lf_putstr(file, "const unsigned_word cia = nia;\n"); + print_icache_body(file, + instruction, + expanded_bits, + cache_rules, + (code & generate_with_direct_access_icache), + (code & generate_with_icache)/*get_value_from_cache*/, + 0/*put_value_in_cache*/); + print_semantic_body(file, + instruction, + expanded_bits, + opcodes); + print_jump(file, 1/*is tail*/); + lf_indent(file, -2); + lf_printf(file, "}\n"); +} + +static void +print_jump_definition(insn_table *entry, + lf *file, + void *data, + insn *instruction, + int depth) +{ + cache_table *cache_rules = (cache_table*)data; + if (generate_expanded_instructions) { + ASSERT(entry->nr_insn == 1 + && entry->opcode == NULL + && entry->parent != NULL + && entry->parent->opcode != NULL); + ASSERT(entry->nr_insn == 1 + && entry->opcode == NULL + && entry->parent != NULL + && entry->parent->opcode != NULL + && entry->parent->opcode_rule != NULL); + print_jump_insn(file, + entry->insns, + entry->expanded_bits, + entry->opcode, + cache_rules); + } + else { + print_jump_insn(file, + instruction, + NULL, + NULL, + cache_rules); + } +} + + +static void +print_jump_internal_function(insn_table *table, + lf *file, + void *data, + table_entry *function) +{ + if (it_is("internal", function->fields[insn_flags])) { + lf_printf(file, "\n"); + table_entry_print_cpp_line_nr(file, function); + lf_indent(file, -1); + print_function_name(file, + function->fields[insn_name], + NULL, + ((code & generate_with_icache) + ? function_name_prefix_icache + : function_name_prefix_semantics)); + lf_printf(file, ":\n"); + lf_indent(file, +1); + lf_printf(file, "{\n"); + lf_indent(file, +2); + lf_printf(file, "const unsigned_word cia = nia;\n"); + lf_print__c_code(file, function->annex); + lf_print__internal_reference(file); + lf_printf(file, "error(\"Internal function must longjump\\n\");\n"); + lf_indent(file, -2); + lf_printf(file, "}\n"); + } +} + +static void +print_jump_until_stop_body(lf *file, + insn_table *table, + cache_table *cache_rules, + int can_stop) +{ + lf_printf(file, "{\n"); + lf_indent(file, +2); + if (!can_stop) + lf_printf(file, "int *keep_running = NULL;\n"); + lf_putstr(file, "jmp_buf halt;\n"); + lf_putstr(file, "jmp_buf restart;\n"); + lf_putstr(file, "cpu *processor = NULL;\n"); + lf_putstr(file, "unsigned_word nia = -1;\n"); + lf_putstr(file, "instruction_word instruction = 0;\n"); + if ((code & generate_with_icache)) { + lf_putstr(file, "idecode_cache *cache_entry = NULL;\n"); + } + if (generate_smp) { + lf_putstr(file, "int current_cpu = -1;\n"); + } + + /* all the switches and tables - they know about jumping */ + print_idecode_lookups(file, table, cache_rules); + + /* start the simulation up */ + if ((code & generate_with_icache)) { + lf_putstr(file, "\n"); + lf_putstr(file, "{\n"); + lf_putstr(file, " int cpu_nr;\n"); + lf_putstr(file, " for (cpu_nr = 0; cpu_nr < nr_cpus; cpu_nr++)\n"); + lf_putstr(file, " cpu_flush_icache(processors[cpu_nr]);\n"); + lf_putstr(file, "}\n"); + } + + lf_putstr(file, "\n"); + lf_putstr(file, "psim_set_halt_and_restart(system, &halt, &restart);\n"); + + lf_putstr(file, "\n"); + lf_putstr(file, "if (setjmp(halt))\n"); + lf_putstr(file, " return;\n"); + + lf_putstr(file, "\n"); + lf_putstr(file, "setjmp(restart);\n"); + + lf_putstr(file, "\n"); + if (!generate_smp) { + lf_putstr(file, "processor = processors[0];\n"); + lf_putstr(file, "nia = cpu_get_program_counter(processor);\n"); + } + else { + lf_putstr(file, "current_cpu = psim_last_cpu(system);\n"); + } + + if (!(code & generate_with_icache)) { + lf_printf(file, "\n"); + lf_indent(file, -1); + lf_printf(file, "idecode:\n"); + lf_indent(file, +1); + } + + print_jump(file, 0/*is_tail*/); + + if ((code & generate_with_icache)) { + lf_indent(file, -1); + lf_printf(file, "cache_miss:\n"); + lf_indent(file, +1); + } + + lf_putstr(file, "instruction\n"); + lf_putstr(file, " = vm_instruction_map_read(cpu_instruction_map(processor),\n"); + lf_putstr(file, " processor, nia);\n"); + print_idecode_body(file, table, "/*IGORE*/", ""); + + /* print out a table of all the internals functions */ + insn_table_traverse_function(table, + file, NULL, + print_jump_internal_function); + + /* print out a table of all the instructions */ + if (generate_expanded_instructions) + insn_table_traverse_tree(table, + file, cache_rules, + 1, + NULL, /* start */ + print_jump_definition, /* leaf */ + NULL, /* end */ + NULL); /* padding */ + else + insn_table_traverse_insn(table, + file, cache_rules, + print_jump_definition); + lf_indent(file, -2); + lf_printf(file, "}\n"); +} + + +/****************************************************************/ + + + +static void +print_idecode_floating_point_unavailable(lf *file) +{ + if ((code & generate_jumps)) + lf_printf(file, "goto %s_floating_point_unavailable;\n", (code & generate_with_icache) ? "icache" : "semantic"); + else if ((code & generate_with_icache)) + lf_printf(file, "return icache_floating_point_unavailable(%s);\n", + ICACHE_FUNCTION_ACTUAL); + else + lf_printf(file, "return semantic_floating_point_unavailable(%s);\n", + SEMANTIC_FUNCTION_ACTUAL); +} + + +/* Output code to do any final checks on the decoded instruction. + This includes things like verifying any on decoded fields have the + correct value and checking that (for floating point) floating point + hardware isn't disabled */ + +void +print_idecode_validate(lf *file, + insn *instruction, + opcode_field *opcodes) +{ + /* Validate: unchecked instruction fields + + If any constant fields in the instruction were not checked by the + idecode tables, output code to check that they have the correct + value here */ + { + unsigned check_mask = 0; + unsigned check_val = 0; + insn_field *field; + opcode_field *opcode; + + /* form check_mask/check_val containing what needs to be checked + in the instruction */ + for (field = instruction->fields->first; + field->first < insn_bit_size; + field = field->next) { + + check_mask <<= field->width; + check_val <<= field->width; + + /* is it a constant that could need validating? */ + if (!field->is_int && !field->is_slash) + continue; + + /* has it been checked by a table? */ + for (opcode = opcodes; opcode != NULL; opcode = opcode->parent) { + if (field->first >= opcode->first + && field->last <= opcode->last) + break; + } + if (opcode != NULL) + continue; + + check_mask |= (1 << field->width)-1; + check_val |= field->val_int; + } + + /* if any bits not checked by opcode tables, output code to check them */ + if (check_mask) { + lf_printf(file, "\n"); + lf_printf(file, "/* validate: %s */\n", + instruction->file_entry->fields[insn_format]); + lf_printf(file, "if (WITH_RESERVED_BITS && (instruction & 0x%x) != 0x%x)\n", + check_mask, check_val); + lf_indent(file, +2); + print_idecode_illegal(file, "return"); + lf_indent(file, -2); + } + } + + /* Validate floating point hardware + + If the simulator is being built with out floating point hardware + (different to it being disabled in the MSR) then floating point + instructions are invalid */ + { + if (it_is("f", instruction->file_entry->fields[insn_flags])) { + lf_printf(file, "\n"); + lf_printf(file, "/* Validate: FP hardware exists */\n"); + lf_printf(file, "if (CURRENT_FLOATING_POINT != HARD_FLOATING_POINT)\n"); + lf_indent(file, +2); + print_idecode_illegal(file, "return"); + lf_indent(file, -2); + } + } + + /* Validate: Floating Point available + + If floating point is not available, we enter a floating point + unavailable interrupt into the cache instead of the instruction + proper. + + The PowerPC spec requires a CSI after MSR[FP] is changed and when + ever a CSI occures we flush the instruction cache. */ + + { + if (it_is("f", instruction->file_entry->fields[insn_flags])) { + lf_printf(file, "\n"); + lf_printf(file, "/* Validate: FP available according to MSR[FP] */\n"); + lf_printf(file, "if (!IS_FP_AVAILABLE(processor))\n"); + lf_indent(file, +2); + print_idecode_floating_point_unavailable(file); + lf_indent(file, -2); + } + } +} + + +/****************************************************************/ + + +static void +print_idecode_run_function_header(lf *file, + int can_stop, + int is_definition) +{ + int indent; + lf_printf(file, "\n"); + lf_print_function_type(file, "void", "INLINE_IDECODE", (is_definition ? " " : "\n")); + indent = lf_putstr(file, (can_stop ? "idecode_run_until_stop" : "idecode_run")); + if (is_definition) + lf_putstr(file, "\n"); + else + lf_indent(file, +indent); + lf_putstr(file, "(psim *system,\n"); + if (can_stop) + lf_putstr(file, " volatile int *keep_running,\n"); + lf_printf(file, " event_queue *events,\n"); + lf_putstr(file, " cpu *const processors[],\n"); + lf_putstr(file, " const int nr_cpus)"); + if (is_definition) + lf_putstr(file, ";"); + else + lf_indent(file, -indent); + lf_putstr(file, "\n"); +} + + +void +gen_idecode_h(lf *file, + insn_table *table, + cache_table *cache_rules) +{ + lf_printf(file, "/* The idecode_*.h functions shall move to support */\n"); + lf_printf(file, "#include \"idecode_expression.h\"\n"); + lf_printf(file, "#include \"idecode_fields.h\"\n"); + lf_printf(file, "#include \"idecode_branch.h\"\n"); + lf_printf(file, "\n"); + print_icache_struct(table, cache_rules, file); + lf_printf(file, "\n"); + lf_printf(file, "#define WITH_IDECODE_SMP %d\n", generate_smp); + lf_printf(file, "\n"); + print_idecode_run_function_header(file, 0/*can stop*/, 1/*is definition*/); + print_idecode_run_function_header(file, 1/*can stop*/, 1/*is definition*/); +} + + +void +gen_idecode_c(lf *file, + insn_table *table, + cache_table *cache_rules) +{ + /* the intro */ + lf_printf(file, "#include \"inline.c\"\n"); + lf_printf(file, "\n"); + lf_printf(file, "#include \"cpu.h\"\n"); + lf_printf(file, "#include \"idecode.h\"\n"); + lf_printf(file, "#include \"semantics.h\"\n"); + lf_printf(file, "#include \"icache.h\"\n"); + lf_printf(file, "#include \"support.h\"\n"); + lf_printf(file, "\n"); + lf_printf(file, "#include \n"); + lf_printf(file, "\n"); + lf_printf(file, "/* encodings for a negative shift field */\n"); + lf_printf(file, "enum {\n"); + lf_printf(file, " table_boolean_entry = -2,\n"); + lf_printf(file, " table_function_entry = -1,\n"); + lf_printf(file, "};\n"); + lf_printf(file, "\n"); + lf_printf(file, "typedef struct _idecode_table_entry {\n"); + lf_printf(file, " signed short shift; /* shift >= 0: t[(i & mask) >> shift] */\n"); + lf_printf(file, " unsigned char left; /* shift == -2: */\n"); + lf_printf(file, " unsigned char right; /* t[((i << left) >> right) != mask] */\n"); + lf_printf(file, " unsigned mask; /* else (shift == -1): function() */\n"); + lf_printf(file, " void *function_or_table;\n"); + lf_printf(file, "} idecode_table_entry;\n"); + lf_printf(file, "\n"); + lf_printf(file, "\n"); + + if ((code & generate_calls)) { + + print_idecode_lookups(file, table, cache_rules); + + /* output the main idecode routine */ + print_idecode_run_function_header(file, 0/*can stop*/, 0/*is definition*/); + print_run_until_stop_body(file, table, 0/* have stop argument */); + + print_idecode_run_function_header(file, 1/*can stop*/, 0/*is definition*/); + print_run_until_stop_body(file, table, 1/* no stop argument */); + + } + else if ((code & generate_jumps)) { + + print_idecode_run_function_header(file, 0/*can stop*/, 0/*is definition*/); + print_jump_until_stop_body(file, table, cache_rules, 0 /* have stop argument */); + + print_idecode_run_function_header(file, 1/*can stop*/, 0/*is definition*/); + print_jump_until_stop_body(file, table, cache_rules, 1/* have stop argument */); + + } + else { + error("Something is wrong!\n"); + } +} + + diff --git a/sim/ppc/gen-idecode.h b/sim/ppc/gen-idecode.h new file mode 100644 index 00000000000..f46376bf9ed --- /dev/null +++ b/sim/ppc/gen-idecode.h @@ -0,0 +1,40 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995, Andrew Cagney + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + +extern void gen_idecode_h +(lf *file, + insn_table *table, + cache_table *cache_rules); + +extern void gen_idecode_c +(lf *file, + insn_table *table, + cache_table *cache_rules); + + +/* Output code to do any final checks on the decoded instruction. + This includes things like verifying any on decoded fields have the + correct value and checking that (for floating point) floating point + hardware isn't disabled */ + +extern void print_idecode_validate +(lf *file, + insn *instruction, + opcode_field *opcodes); diff --git a/sim/ppc/gen-itable.c b/sim/ppc/gen-itable.c new file mode 100644 index 00000000000..132aa291e08 --- /dev/null +++ b/sim/ppc/gen-itable.c @@ -0,0 +1,122 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995, Andrew Cagney + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + + +#include "misc.h" +#include "lf.h" +#include "table.h" + +#include "filter.h" + +#include "ld-decode.h" +#include "ld-insn.h" + +#include "igen.h" +#include "gen-itable.h" + +#ifndef NULL +#define NULL 0 +#endif + + + +static void +itable_h_insn(insn_table *entry, + lf *file, + void *data, + insn *instruction, + int depth) +{ + lf_printf(file, " "); + print_function_name(file, + instruction->file_entry->fields[insn_name], + NULL, + function_name_prefix_itable); + lf_printf(file, ",\n"); +} + + +extern void +gen_itable_h(insn_table *table, lf *file) +{ + /* output an enumerated type for each instruction */ + lf_printf(file, "typedef enum {\n"); + insn_table_traverse_insn(table, + file, NULL, + itable_h_insn); + lf_printf(file, " nr_itable_entries,\n"); + lf_printf(file, "} itable_index;\n"); + lf_printf(file, "\n"); + + /* output the table that contains the actual instruction info */ + lf_printf(file, "typedef struct _itable_instruction_info {\n"); + lf_printf(file, " itable_index nr;\n"); + lf_printf(file, " char *format;\n"); + lf_printf(file, " char *form;\n"); + lf_printf(file, " char *flags;\n"); + lf_printf(file, " char *mnemonic;\n"); + lf_printf(file, " char *name;\n"); + lf_printf(file, " char *file;\n"); + lf_printf(file, " int line_nr;\n"); + lf_printf(file, "} itable_info;\n"); + lf_printf(file, "\n"); + lf_printf(file, "extern itable_info itable[nr_itable_entries];\n"); +} + +/****************************************************************/ + +static void +itable_c_insn(insn_table *entry, + lf *file, + void *data, + insn *instruction, + int depth) +{ + char **fields = instruction->file_entry->fields; + lf_printf(file, " { "); + print_function_name(file, + instruction->file_entry->fields[insn_name], + NULL, + function_name_prefix_itable); + lf_printf(file, ",\n"); + lf_printf(file, " \"%s\",\n", fields[insn_format]); + lf_printf(file, " \"%s\",\n", fields[insn_form]); + lf_printf(file, " \"%s\",\n", fields[insn_flags]); + lf_printf(file, " \"%s\",\n", fields[insn_mnemonic]); + lf_printf(file, " \"%s\",\n", fields[insn_name]); + lf_printf(file, " \"%s\",\n", filter_filename (instruction->file_entry->file_name)); + lf_printf(file, " %d,\n", instruction->file_entry->line_nr); + lf_printf(file, " },\n"); +} + + +extern void +gen_itable_c(insn_table *table, lf *file) +{ + /* output the table that contains the actual instruction info */ + lf_printf(file, "#include \"itable.h\"\n"); + lf_printf(file, "\n"); + lf_printf(file, "itable_info itable[nr_itable_entries] = {\n"); + insn_table_traverse_insn(table, + file, NULL, + itable_c_insn); + lf_printf(file, "};\n"); +} diff --git a/sim/ppc/gen-itable.h b/sim/ppc/gen-itable.h new file mode 100644 index 00000000000..341dc678547 --- /dev/null +++ b/sim/ppc/gen-itable.h @@ -0,0 +1,28 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995, Andrew Cagney + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +extern void gen_itable_h +(insn_table *table, + lf *file); + +extern void gen_itable_c +(insn_table *table, + lf *file); diff --git a/sim/ppc/gen-model.h b/sim/ppc/gen-model.h new file mode 100644 index 00000000000..b465a75abf8 --- /dev/null +++ b/sim/ppc/gen-model.h @@ -0,0 +1,30 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995, Andrew Cagney + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + + +extern void gen_model_h +(insn_table *table, + lf *file); + + +extern void gen_model_c +(insn_table *table, + lf *file); diff --git a/sim/ppc/gen-semantics.c b/sim/ppc/gen-semantics.c new file mode 100644 index 00000000000..5fda23a995a --- /dev/null +++ b/sim/ppc/gen-semantics.c @@ -0,0 +1,253 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995, Andrew Cagney + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + + +#include "misc.h" +#include "lf.h" +#include "table.h" +#include "filter.h" + +#include "ld-decode.h" +#include "ld-cache.h" +#include "ld-insn.h" + +#include "igen.h" + +#include "gen-semantics.h" +#include "gen-icache.h" +#include "gen-idecode.h" + + +static void +print_semantic_function_header(lf *file, + const char *basename, + insn_bits *expanded_bits, + int is_function_definition) +{ + int indent; + lf_printf(file, "\n"); + lf_print_function_type(file, SEMANTIC_FUNCTION_TYPE, "EXTERN_SEMANTICS", + (is_function_definition ? "\n" : " ")); + indent = print_function_name(file, + basename, + expanded_bits, + function_name_prefix_semantics); + if (is_function_definition) + lf_indent(file, +indent); + else + lf_printf(file, "\n"); + lf_printf(file, "(%s)", SEMANTIC_FUNCTION_FORMAL); + if (is_function_definition) + lf_indent(file, -indent); + else + lf_printf(file, ";"); + lf_printf(file, "\n"); +} + +void +print_semantic_declaration(insn_table *entry, + lf *file, + void *data, + insn *instruction, + int depth) +{ + if (generate_expanded_instructions) { + ASSERT(entry->nr_insn == 1); + print_semantic_function_header(file, + instruction->file_entry->fields[insn_name], + entry->expanded_bits, + 0/* is not function definition*/); + } + else { + print_semantic_function_header(file, + instruction->file_entry->fields[insn_name], + NULL, + 0/* is not function definition*/); + } +} + + + +/* generate the semantics.c file */ + + +void +print_idecode_illegal(lf *file, + const char *result) +{ + if ((code & generate_jumps)) + lf_printf(file, "goto %s_illegal;\n", (code & generate_with_icache) ? "icache" : "semantic"); + else if ((code & generate_with_icache)) + lf_printf(file, "%s icache_illegal(%s);\n", result, ICACHE_FUNCTION_ACTUAL); + else + lf_printf(file, "%s semantic_illegal(%s);\n", result, SEMANTIC_FUNCTION_ACTUAL); +} + + +void +print_semantic_body(lf *file, + insn *instruction, + insn_bits *expanded_bits, + opcode_field *opcodes) +{ + print_itrace(file, instruction->file_entry, 0/*put_value_in_cache*/); + + /* validate the instruction, if a cache this has already been done */ + if (!(code & generate_with_icache)) + print_idecode_validate(file, instruction, opcodes); + + /* generate the profiling call - this is delayed until after the + instruction has been verified */ + lf_printf(file, "\n"); + lf_printf(file, "/* monitoring: */\n"); + lf_printf(file, "if (WITH_MON & MONITOR_INSTRUCTION_ISSUE) {\n"); + lf_printf(file, " mon_issue("); + print_function_name(file, + instruction->file_entry->fields[insn_name], + NULL, + function_name_prefix_itable); + lf_printf(file, ", processor, cia);\n"); + lf_printf(file, "}\n"); + + /* generate the code (or at least something */ + lf_printf(file, "\n"); + lf_printf(file, "/* semantics: */\n"); + lf_printf(file, "nia = cia + %d;\n", insn_bit_size / 8); + if (instruction->file_entry->annex != NULL) { + /* true code */ + table_entry_print_cpp_line_nr(file, instruction->file_entry); + lf_printf(file, "{\n"); + lf_indent(file, +2); + lf_print__c_code(file, instruction->file_entry->annex); + lf_indent(file, -2); + lf_printf(file, "}\n"); + lf_print__internal_reference(file); + } + else if (it_is("nop", instruction->file_entry->fields[insn_flags])) { + lf_print__internal_reference(file); + } + else if (it_is("f", instruction->file_entry->fields[insn_flags])) { + /* unimplemented floating point instruction - call for assistance */ + lf_printf(file, "/* unimplemented floating point instruction - call for assistance */\n"); + table_entry_print_cpp_line_nr(file, instruction->file_entry); + lf_putstr(file, "floating_point_assist_interrupt(processor, cia);\n"); + lf_print__internal_reference(file); + } + else { + /* abort so it is implemented now */ + table_entry_print_cpp_line_nr(file, instruction->file_entry); + lf_putstr(file, "error(\"%s:%d:0x%08lx:%s unimplemented\\n\",\n"); + lf_printf(file, " itable[MY_INDEX].file, itable[MY_INDEX].line_nr, (long)cia, itable[MY_INDEX].name);\n"); + lf_print__internal_reference(file); + } +} + +static void +print_c_semantic(lf *file, + insn *instruction, + insn_bits *expanded_bits, + opcode_field *opcodes, + cache_table *cache_rules) +{ + + lf_printf(file, "{\n"); + lf_indent(file, +2); + + print_define_my_index(file, instruction->file_entry); + lf_printf(file, "\n"); + print_icache_body(file, + instruction, + expanded_bits, + cache_rules, + (code & generate_with_direct_access_icache), + (code & generate_with_icache)/*get_value_from_cache*/, + 0/*put_value_in_cache*/); + + lf_printf(file, "unsigned_word nia;\n"); + print_semantic_body(file, + instruction, + expanded_bits, + opcodes); + lf_printf(file, "return nia;\n"); + + /* generate something to clean up any #defines created for the cache */ + if ((code & generate_with_direct_access_icache)) + print_icache_body(file, + instruction, + expanded_bits, + cache_rules, + 1/*use_defines*/, + 0/*get_value_from_cache*/, + 1/*put_value_in_cache*/); + + lf_indent(file, -2); + lf_printf(file, "}\n"); +} + +static void +print_c_semantic_function(lf *file, + insn *instruction, + insn_bits *expanded_bits, + opcode_field *opcodes, + cache_table *cache_rules) +{ + /* build the semantic routine to execute the instruction */ + print_semantic_function_header(file, + instruction->file_entry->fields[insn_name], + expanded_bits, + 1/*is-function-definition*/); + print_c_semantic(file, + instruction, + expanded_bits, + opcodes, + cache_rules); +} + +void +print_semantic_definition(insn_table *entry, + lf *file, + void *data, + insn *instruction, + int depth) +{ + cache_table *cache_rules = (cache_table*)data; + if (generate_expanded_instructions) { + ASSERT(entry->nr_insn == 1 + && entry->opcode == NULL + && entry->parent != NULL + && entry->parent->opcode != NULL); + ASSERT(entry->nr_insn == 1 + && entry->opcode == NULL + && entry->parent != NULL + && entry->parent->opcode != NULL + && entry->parent->opcode_rule != NULL); + print_c_semantic_function(file, + entry->insns, + entry->expanded_bits, + entry->parent->opcode, + cache_rules); + } + else { + print_c_semantic_function(file, instruction, + NULL, NULL, + cache_rules); + } +} diff --git a/sim/ppc/gen-semantics.h b/sim/ppc/gen-semantics.h new file mode 100644 index 00000000000..2c25715f7c7 --- /dev/null +++ b/sim/ppc/gen-semantics.h @@ -0,0 +1,81 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995, Andrew Cagney + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +/* Creates the files semantics.[hc]. + + The generated file semantics contains functions that implement the + operations required to model a single target processor instruction. + + Several different variations on the semantics file can be created: + + o uncached + + No instruction cache exists. The semantic function + needs to generate any required values locally. + + o cached - separate cracker and semantic + + Two independant functions are created. Firstly the + function that cracks an instruction entering it into a + cache and secondly the semantic function propper that + uses the cache. + + o cached - semantic + cracking semantic + + The function that cracks the instruction and enters + all values into the cache also contains a copy of the + semantic code (avoiding the need to call both the + cracker and the semantic function when there is a + cache miss). + + For each of these general forms, several refinements can occure: + + o do/don't duplicate/expand semantic functions + + As a consequence of decoding an instruction, the + decoder, as part of its table may have effectivly made + certain of the variable fields in an instruction + constant. Separate functions for each of the + alternative values for what would have been treated as + a variable part can be created. + + o use cache struct directly. + + When a cracking cache is present, the semantic + functions can be generated to either hold intermediate + cache values in local variables or always refer to the + contents of the cache directly. */ + + + +extern insn_handler print_semantic_declaration; +extern insn_handler print_semantic_definition; + +extern void print_idecode_illegal +(lf *file, + const char *result); + +extern void print_semantic_body +(lf *file, + insn *instruction, + insn_bits *expanded_bits, + opcode_field *opcodes); + diff --git a/sim/ppc/gen-support.c b/sim/ppc/gen-support.c new file mode 100644 index 00000000000..0f76fe40f09 --- /dev/null +++ b/sim/ppc/gen-support.c @@ -0,0 +1,128 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995, Andrew Cagney + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + +#include "misc.h" +#include "lf.h" +#include "table.h" +#include "filter.h" + +#include "ld-decode.h" +#include "ld-cache.h" +#include "ld-insn.h" + +#include "igen.h" + +#include "gen-semantics.h" +#include "gen-support.h" + +static void +print_support_function_name(lf *file, + table_entry *function, + int is_function_definition) +{ + if (it_is("internal", function->fields[insn_flags])) { + lf_print_function_type(file, SEMANTIC_FUNCTION_TYPE, "INLINE_SUPPORT", + (is_function_definition ? "\n" : " ")); + print_function_name(file, + function->fields[function_name], + NULL, + function_name_prefix_semantics); + lf_printf(file, "\n(%s)", SEMANTIC_FUNCTION_FORMAL); + if (!is_function_definition) + lf_printf(file, ";"); + lf_printf(file, "\n"); + } + else { + lf_print_function_type(file, + function->fields[function_type], + "INLINE_SUPPORT", + (is_function_definition ? "\n" : " ")); + lf_printf(file, "%s\n(%s)%s", + function->fields[function_name], + function->fields[function_param], + (is_function_definition ? "\n" : ";\n")); + } +} + + +static void +support_h_function(insn_table *entry, + lf *file, + void *data, + table_entry *function) +{ + ASSERT(function->fields[function_type] != NULL); + ASSERT(function->fields[function_param] != NULL); + print_support_function_name(file, + function, + 0/*!is_definition*/); + lf_printf(file, "\n"); +} + + +extern void +gen_support_h(insn_table *table, + lf *file) +{ + /* output a declaration for all functions */ + insn_table_traverse_function(table, + file, NULL, + support_h_function); +} + +static void +support_c_function(insn_table *table, + lf *file, + void *data, + table_entry *function) +{ + ASSERT(function->fields[function_type] != NULL); + print_support_function_name(file, + function, + 1/*!is_definition*/); + table_entry_print_cpp_line_nr(file, function); + lf_printf(file, "{\n"); + lf_indent(file, +2); + lf_print__c_code(file, function->annex); + if (it_is("internal", function->fields[insn_flags])) { + lf_printf(file, "error(\"Internal function must longjump\\n\");\n"); + lf_printf(file, "return 0;\n"); + } + lf_indent(file, -2); + lf_printf(file, "}\n"); + lf_print__internal_reference(file); + lf_printf(file, "\n"); +} + + +void +gen_support_c(insn_table *table, + lf *file) +{ + lf_printf(file, "#include \"cpu.h\"\n"); + lf_printf(file, "#include \"idecode.h\"\n"); + lf_printf(file, "#include \"support.h\"\n"); + lf_printf(file, "\n"); + + /* output a definition (c-code) for all functions */ + insn_table_traverse_function(table, + file, NULL, + support_c_function); +} diff --git a/sim/ppc/gen-support.h b/sim/ppc/gen-support.h new file mode 100644 index 00000000000..70862d76881 --- /dev/null +++ b/sim/ppc/gen-support.h @@ -0,0 +1,29 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995, Andrew Cagney + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +extern void gen_support_h +(insn_table *table, + lf *file); + +extern void gen_support_c +(insn_table *table, + lf *file); + diff --git a/sim/ppc/hw_core.c b/sim/ppc/hw_core.c new file mode 100644 index 00000000000..8dba11b9323 --- /dev/null +++ b/sim/ppc/hw_core.c @@ -0,0 +1,142 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1996, Andrew Cagney + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#ifndef _HW_CORE_C_ +#define _HW_CORE_C_ + +#include "device_table.h" + +#include "corefile.h" + + +/* DEVICE + + core - root of the device tree + + DESCRIPTION + + The core device positioned at the root of the device tree appears + to its child devices as a normal device just like every other + device in the tree. + + Internally it is implemented using a core object. Requests to + attach (or detach) address spaces are passed to that core object. + Requests to transfer (DMA) data are reflected back down the device + tree using the core_map data transfer methods. + + PROPERTIES + + None. + + */ + + +static void +hw_core_init_address_callback(device *me) +{ + core *memory = (core*)device_data(me); + core_init(memory); +} + + +static void +hw_core_attach_address_callback(device *me, + const char *name, + attach_type attach, + int space, + unsigned_word addr, + unsigned nr_bytes, + access_type access, + device *who) /*callback/default*/ +{ + core *memory = (core*)device_data(me); + if (space != 0) + error("core_attach_address_callback() invalid address space\n"); + core_attach(memory, + attach, + space, + access, + addr, + nr_bytes, + who); +} + + +static unsigned +hw_core_dma_read_buffer_callback(device *me, + void *dest, + int space, + unsigned_word addr, + unsigned nr_bytes) +{ + core *memory = (core*)device_data(me); + return core_map_read_buffer(core_readable(memory), + dest, + addr, + nr_bytes); +} + + +static unsigned +hw_core_dma_write_buffer_callback(device *me, + const void *source, + int space, + unsigned_word addr, + unsigned nr_bytes, + int violate_read_only_section) +{ + core *memory = (core*)device_data(me); + core_map *map = (violate_read_only_section + ? core_readable(memory) + : core_writeable(memory)); + return core_map_write_buffer(map, + source, + addr, + nr_bytes); +} + +static device_callbacks const hw_core_callbacks = { + { hw_core_init_address_callback, }, + { hw_core_attach_address_callback, }, + { NULL, }, /* IO */ + { hw_core_dma_read_buffer_callback, + hw_core_dma_write_buffer_callback, }, + { NULL, }, /* interrupt */ + { generic_device_unit_decode, + generic_device_unit_encode, } +}; + + +static void * +hw_core_create(const char *name, + const device_unit *unit_address, + const char *args) +{ + core *memory = core_create(); + return memory; +} + +const device_descriptor hw_core_device_descriptor[] = { + { "core", hw_core_create, &hw_core_callbacks }, + { NULL }, +}; + +#endif /* _HW_CORE_C_ */ diff --git a/sim/ppc/hw_memory.c b/sim/ppc/hw_memory.c new file mode 100644 index 00000000000..7e4204d0651 --- /dev/null +++ b/sim/ppc/hw_memory.c @@ -0,0 +1,316 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1996, Andrew Cagney + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#ifndef _HW_MEMORY_C_ +#define _HW_MEMORY_C_ + +#ifndef STATIC_INLINE_HW_MEMORY +#define STATIC_INLINE_HW_MEMORY STATIC_INLINE +#endif + +#include "device_table.h" + +/* DEVICE + + memory - description of system memory + + DESCRIPTION + + This device describes the size and location of the banks of + physical memory within the simulation. + + In addition, this device supports the "claim" and "release" methods + that can be used by OpenBoot client programs to manage the + allocation of physical memory. + + PROPERTIES + + reg = {
} (required) + + Each pair specify one bank of memory. + + available = {
} (automatic) + + Each pair specifies a block of memory that is currently unallocated. + + */ + +typedef struct _memory_reg_spec { + unsigned32 base; + unsigned32 size; +} memory_reg_spec; + +typedef struct _hw_memory_chunk hw_memory_chunk; +struct _hw_memory_chunk { + unsigned_word address; + unsigned_word size; + unsigned_word alloc_address; + unsigned_word alloc_size; + int available; + hw_memory_chunk *next; +}; + +typedef struct _hw_memory_device { + hw_memory_chunk *heap; +} hw_memory_device; + + +static void * +hw_memory_create(const char *name, + const device_unit *unit_address, + const char *args) +{ + hw_memory_device *hw_memory = ZALLOC(hw_memory_device); + return hw_memory; +} + + +static void +hw_memory_set_available(device *me, + hw_memory_device *hw_memory) +{ + hw_memory_chunk *chunk = NULL; + memory_reg_spec *available = NULL; + int nr_available = 0; + int curr = 0; + int sizeof_available = 0; + /* determine the nr of available chunks */ + chunk = hw_memory->heap; + nr_available = 0; + while (chunk != NULL) { + if (chunk->available) + nr_available += 1; + chunk = chunk->next; + } + /* now create the available struct */ + ASSERT(nr_available > 0); + sizeof_available = sizeof(memory_reg_spec) * nr_available; + available = zalloc(sizeof_available); + chunk = hw_memory->heap; + curr = 0; + while (chunk != NULL) { + if (chunk->available) { + available[curr].base = H2BE_4(chunk->address); + available[curr].size = H2BE_4(chunk->size); + curr += 1; + } + chunk = chunk->next; + } + /* update */ + device_set_array_property(me, "available", available, sizeof_available); + zfree(available); +} + + +static void +hw_memory_init_address(device *me) +{ + hw_memory_device *hw_memory = (hw_memory_device*)device_data(me); + const device_property *reg = device_find_array_property(me, "reg"); + const memory_reg_spec *spec = reg->array; + int nr_entries = reg->sizeof_array / sizeof(*spec); + + /* sanity check reg property */ + if ((reg->sizeof_array % sizeof(*spec)) != 0) + error("devices/%s reg property of incorrect size\n", device_name(me)); + + /* free up any previous structures */ + { + hw_memory_chunk *curr_chunk = hw_memory->heap; + hw_memory->heap = NULL; + while (curr_chunk != NULL) { + hw_memory_chunk *dead_chunk = curr_chunk; + curr_chunk = dead_chunk->next; + dead_chunk->next = NULL; + zfree(dead_chunk); + } + } + + /* count/allocate memory entries */ + { + hw_memory_chunk **curr_chunk = &hw_memory->heap; + while (nr_entries > 0) { + hw_memory_chunk *new_chunk = ZALLOC(hw_memory_chunk); + new_chunk->address = BE2H_4(spec->base); + new_chunk->size = BE2H_4(spec->size); + new_chunk->available = 1; + device_attach_address(device_parent(me), + device_name(me), + attach_raw_memory, + 0 /*address space*/, + new_chunk->address, + new_chunk->size, + access_read_write_exec, + me); + spec++; + nr_entries--; + *curr_chunk = new_chunk; + curr_chunk = &new_chunk->next; + } + } + + /* initialize the alloc property for this device */ + hw_memory_set_available(me, hw_memory); +} + +static void +hw_memory_instance_delete(device_instance *instance) +{ + return; +} + +static unsigned_word +hw_memory_instance_claim(device_instance *instance, + unsigned_word address, + unsigned_word size, + unsigned_word alignment) +{ + hw_memory_device *hw_memory = device_instance_data(instance); + hw_memory_chunk *chunk = NULL; + DTRACE(memory, ("claim - address=0x%lx size=0x%lx alignment=%d\n", + (unsigned long)address, + (unsigned long)size, + (int)alignment)); + /* find a chunk candidate, either according to address or alignment */ + if (alignment == 0) { + chunk = hw_memory->heap; + while (chunk != NULL + && (address+size) > (chunk->address+chunk->size)) + chunk = chunk->next; + if (chunk == NULL || address < chunk->address || !chunk->available) + error("hw_memory_instance_claim: failed to allocate @0x%lx, size %ld\n", + (unsigned long)address, (unsigned long)size); + } + else { + chunk = hw_memory->heap; + while (chunk != NULL && chunk->size < size) + chunk = chunk->next; + if (chunk == NULL || FLOOR_PAGE(alignment-1) > 0) + error("hw_memory_instance_claim: failed to allocate %ld, align %ld\n", + (unsigned long)size, (unsigned long)size); + address = chunk->address; + } + /* break of a part before this memory if needed */ + ASSERT(address >= chunk->address); + if (FLOOR_PAGE(address) > chunk->address) { + hw_memory_chunk *last_chunk = chunk; + /* insert a new earlier chunk */ + chunk = ZALLOC(hw_memory_chunk); + chunk->next = last_chunk->next; + last_chunk->next = chunk; + /* adjust the address/size */ + chunk->address = FLOOR_PAGE(address); + chunk->size = last_chunk->size - (chunk->address - last_chunk->address); + last_chunk->size = chunk->address - last_chunk->address; + } + ASSERT(FLOOR_PAGE(address) == chunk->address); + /* break of a bit after this chunk if needed */ + if (ALIGN_PAGE(address+size) < chunk->address + chunk->size) { + hw_memory_chunk *next_chunk = ZALLOC(hw_memory_chunk); + /* insert it in to the list */ + next_chunk->next = chunk->next; + chunk->next = next_chunk; + next_chunk->available = 1; + /* adjust the address/size */ + next_chunk->address = ALIGN_PAGE(address+size); + next_chunk->size = chunk->address + chunk->size - next_chunk->address; + chunk->size = next_chunk->address - chunk->address; + } + ASSERT(ALIGN_PAGE(address+size) == chunk->address + chunk->size); + /* now allocate it */ + chunk->alloc_address = address; + chunk->alloc_size = size; + chunk->available = 0; + hw_memory_set_available(device_instance_device(instance), hw_memory); + return address; +} + +static void +hw_memory_instance_release(device_instance *instance, + unsigned_word address, + unsigned_word length) +{ + hw_memory_device *hw_memory = device_instance_data(instance); + hw_memory_chunk *chunk = hw_memory->heap; + while (chunk != NULL) { + if (chunk->alloc_address == address + && chunk->alloc_size == length + && chunk->available == 0) { + /* free this chunk */ + chunk->available = 1; + /* check for merge */ + chunk = hw_memory->heap; + while (chunk != NULL) { + if (chunk->available + && chunk->next != NULL && chunk->next->available) { + /* adjacent */ + hw_memory_chunk *delete = chunk->next; + ASSERT(chunk->address + chunk->size == delete->address); + chunk->size += delete->size; + chunk->next = delete->next; + zfree(delete); + } + } + /* update the corresponding property */ + hw_memory_set_available(device_instance_device(instance), hw_memory); + return; + } + chunk = chunk->next; + } + error("hw_memory_instance_release: Address 0x%lx, size %ld not found\n", + (unsigned long)address, (unsigned long)length); + /* FIXME - dump allocated */ + /* FIXME - dump arguments */ +} + +static device_instance_callbacks const hw_memory_instance_callbacks = { + hw_memory_instance_delete, + NULL /*read*/, NULL /*write*/, NULL /*seek*/, + hw_memory_instance_claim, hw_memory_instance_release +}; + +static device_instance * +hw_memory_create_instance(device *me, + const char *path, + const char *args) +{ + return device_create_instance_from(me, NULL, + device_data(me), /* nothing better */ + path, args, + &hw_memory_instance_callbacks); +} + +static device_callbacks const hw_memory_callbacks = { + { hw_memory_init_address, }, + { NULL, }, /* address */ + { NULL, }, /* IO */ + { NULL, }, /* DMA */ + { NULL, }, /* interrupt */ + { NULL, }, /* unit */ + hw_memory_create_instance, +}; + +const device_descriptor hw_memory_device_descriptor[] = { + { "memory", hw_memory_create, &hw_memory_callbacks }, + { NULL }, +}; + +#endif /* _HW_MEMORY_C_ */ diff --git a/sim/ppc/hw_pal.c b/sim/ppc/hw_pal.c index 429f4576384..64a56f80aad 100644 --- a/sim/ppc/hw_pal.c +++ b/sim/ppc/hw_pal.c @@ -27,18 +27,12 @@ #endif #include "device_table.h" -#include "cpu.h" +#include "cpu.h" #include #include -#if 0 -#ifdef HAVE_TIME_H -#include -#endif -#endif - #ifdef HAVE_STRING_H #include #else @@ -59,31 +53,65 @@ #define WITH_STDIO DO_USE_STDIO #endif -/* Device: - - pal@
+/* DEVICE + pal - glue logic device containing assorted junk - Description: + DESCRIPTION Typical hardware dependant hack. This device allows the firmware to gain access to all the things the firmware needs (but the OS - doesn't). All registers are little endian (byte 0 is the least - significant) and must be accessed correctly aligned. - -
+ 0: write - halts simulation with exit code byte[0]. - -
+ 4: read - processor nr in byte[0]. - -
+ 8: write - send interrupt message to port byte[0] with - value byte[1]. + doesn't). + + The pal contains the following registers. Except for the interrupt + level register, each of the below is 8 bytes in size and must be + accessed using correct alignment. For 16 and 32 bit accesses the + bytes not directed to the register are ignored: -
+ 12: read - nr processors in byte[0]. + |0 reset register (write) + |4 processor id register (read) + |8 interrupt port (write) + |9 interrupt level (write) + |12 processor count register (read) + |16 tty input fifo register (read) + |20 tty input status register (read) + |24 tty output fifo register (write) + |28 tty output status register (read) + + Reset register (write) halts the simulator exiting with the + value written. + Processor id register (read) returns the processor number (0 + .. N-1) of the processor performing the read. - Properties: + The interrupt registers should be accessed as a pair (using a 16 or + 32 bit store). The low byte specifies the interrupt port while the + high byte specifies the level to drive that port at. By + convention, the pal's interrupt ports (int0, int1, ...) are wired + up to the corresponding processor's level sensative external + interrupt pin. Eg: A two byte write to address 8 of 0x0102 + (big-endian) will result in processor 2's external interrupt pin to + be asserted. + + Processor count register (read) returns the total number of + processors active in the current simulation. + + TTY input fifo register (read), if the TTY input status register + indicates a character is available by being nonzero, returns the + next available character from the pal's tty input port. + + Similarly, the TTY output fifo register (write), if the TTY output + status register indicates the output fifo is not full by being + nonzero, outputs the character written to the tty's output port. + + PROPERTIES - NONE. */ + reg =
(required) + + Specify the address (within the parent bus) that this device is to + live. + + */ enum { @@ -259,13 +287,6 @@ hw_pal_io_write_buffer_callback(device *me, /* instances of the hw_pal device */ -static void * -hw_pal_instance_create_callback(device *me, - const char *args) -{ - /* make life easier, attach the hw_pal data to the instance */ - return device_data(me); -} static void hw_pal_instance_delete_callback(device_instance *instance) @@ -306,26 +327,45 @@ hw_pal_instance_write_callback(device_instance *instance, return i; } +static const device_instance_callbacks hw_pal_instance_callbacks = { + hw_pal_instance_delete_callback, + hw_pal_instance_read_callback, + hw_pal_instance_write_callback, +}; + +static device_instance * +hw_pal_create_instance(device *me, + const char *path, + const char *args) +{ + return device_create_instance_from(me, NULL, + device_data(me), + path, args, + &hw_pal_instance_callbacks); +} + +static const device_interrupt_port_descriptor hw_pal_interrupt_ports[] = { + { "int", 0, MAX_NR_PROCESSORS }, + { NULL } +}; + + static device_callbacks const hw_pal_callbacks = { { generic_device_init_address, }, { NULL, }, /* address */ { hw_pal_io_read_buffer_callback, hw_pal_io_write_buffer_callback, }, { NULL, }, /* DMA */ - { NULL, }, /* interrupt */ + { NULL, NULL, hw_pal_interrupt_ports }, /* interrupt */ { NULL, }, /* unit */ - { hw_pal_instance_create_callback, - hw_pal_instance_delete_callback, - hw_pal_instance_read_callback, - hw_pal_instance_write_callback, }, + hw_pal_create_instance, }; static void * hw_pal_create(const char *name, const device_unit *unit_address, - const char *args, - device *parent) + const char *args) { /* create the descriptor */ hw_pal_device *hw_pal = ZALLOC(hw_pal_device); diff --git a/sim/ppc/idecode_expression.h b/sim/ppc/idecode_expression.h index 4248716b0a7..eb4442b0c01 100644 --- a/sim/ppc/idecode_expression.h +++ b/sim/ppc/idecode_expression.h @@ -1,6 +1,6 @@ /* This file is part of the program psim. - Copyright (C) 1994-1995, Andrew Cagney + Copyright (C) 1994-1996, Andrew Cagney This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -86,8 +86,8 @@ else \ XER &= (~xer_carry); */ \ } \ - ITRACE(trace_alu, (" Result = %ld (0x%lx), XER = %ld\n", \ - (long)alu_result, (long)alu_result, (long)XER)); \ + TRACE(trace_alu, (" Result = %ld (0x%lx), XER = %ld\n", \ + (long)alu_result, (long)alu_result, (long)XER)); \ /* Update the Result Conditions if needed */ \ CR0_COMPARE(alu_result, 0, Rc); \ /* assign targ same */ \ @@ -281,9 +281,9 @@ do { \ do { \ if (Rc) { \ CR_COMPARE(0, LHS, RHS); \ - ITRACE(trace_alu, \ - ("CR=0x%08lx, LHS=%ld, RHS=%ld\n", \ - (unsigned long)CR, (long)LHS, (long)RHS)); \ + TRACE(trace_alu, \ + ("CR=0x%08lx, LHS=%ld, RHS=%ld\n", \ + (unsigned long)CR, (long)LHS, (long)RHS)); \ } \ } while (0) diff --git a/sim/ppc/igen.c b/sim/ppc/igen.c index 44c3f776f34..471c97bc1a5 100644 --- a/sim/ppc/igen.c +++ b/sim/ppc/igen.c @@ -18,3310 +18,287 @@ */ -#include -#include + + #include #include "misc.h" #include "lf.h" -#include "table.h" -#include "config.h" - -#ifdef HAVE_STRING_H -#include -#else -#ifdef HAVE_STRINGS_H -#include -#endif -#endif - -#ifdef HAVE_STDLIB_H -#include -#endif - - - -/****************************************************************/ - -enum { - max_insn_size = 32, -}; - -static int hi_bit_nr = 0; -static int insn_size = max_insn_size; -static int idecode_expand_semantics = 0; -static int idecode_cache = 0; -static int semantics_use_cache_struct = 0; -static int number_lines = 1; - - -/****************************************************************/ - - -static char *cache_idecode_formal = -"cpu *processor,\n\ - instruction_word instruction,\n\ - unsigned_word cia,\n\ - idecode_cache *cache_entry"; - -static char *cache_idecode_actual = "processor, instruction, cia, cache_entry"; - -static char *cache_semantic_formal = -"cpu *processor,\n\ - idecode_cache *cache_entry,\n\ - unsigned_word cia"; - -static char *semantic_formal = -"cpu *processor,\n\ - instruction_word instruction,\n\ - unsigned_word cia"; - -static char *semantic_actual = "processor, instruction, cia"; - - - -/****************************************************************/ - - -typedef struct _filter filter; -struct _filter { - char *flag; - filter *next; -}; -static filter *filters = NULL; - - -/****************************************************************/ - - -typedef struct _cache_rules cache_rules; -struct _cache_rules { - int valid; - char *old_name; - char *new_name; - char *type; - char *expression; - cache_rules *next; -}; -static cache_rules *cache_table; - - -enum { - ca_valid, - ca_old_name, - ca_new_name, - ca_type, - ca_expression, - nr_cache_rule_fields, -}; - -static cache_rules * -load_cache_rules(char *file_name) -{ - table *file = table_open(file_name, nr_cache_rule_fields, 0); - table_entry *entry; - cache_rules *table = NULL; - cache_rules **curr_rule = &table; - while ((entry = table_entry_read(file)) != NULL) { - cache_rules *new_rule = ZALLOC(cache_rules); - new_rule->valid = target_a2i(hi_bit_nr, entry->fields[ca_valid]); - new_rule->old_name = entry->fields[ca_old_name]; - new_rule->new_name = entry->fields[ca_new_name]; - new_rule->type = (strlen(entry->fields[ca_type]) - ? entry->fields[ca_type] - : NULL); - new_rule->expression = (strlen(entry->fields[ca_expression]) > 0 - ? entry->fields[ca_expression] - : NULL); - *curr_rule = new_rule; - curr_rule = &new_rule->next; - } - return table; -} - - - -static void -dump_cache_rule(cache_rules* rule, - int indent) -{ - dumpf(indent, "((cache_rules*)0x%x\n", rule); - dumpf(indent, " (valid %d)\n", rule->valid); - dumpf(indent, " (old_name \"%s\")\n", rule->old_name); - dumpf(indent, " (new_name \"%s\")\n", rule->new_name); - dumpf(indent, " (type \"%s\")\n", rule->type); - dumpf(indent, " (expression \"%s\")\n", rule->expression); - dumpf(indent, " (next 0x%x)\n", rule->next); - dumpf(indent, " )\n"); -} - - -static void -dump_cache_rules(cache_rules* rule, int indent) -{ - while (rule) { - dump_cache_rule(rule, indent); - rule = rule->next; - } -} - - -/****************************************************************/ - - -typedef struct _opcode_rules opcode_rules; -struct _opcode_rules { - int first; - int last; - int force_first; - int force_last; - int force_slash; - char *force_expansion; - int use_switch; - unsigned special_mask; - unsigned special_value; - unsigned special_rule; - opcode_rules *next; -}; -static opcode_rules *opcode_table; - - -enum { - op_first, - op_last, - op_force_first, - op_force_last, - op_force_slash, - op_force_expansion, - op_use_switch, - op_special_mask, - op_special_value, - op_special_rule, - nr_opcode_fields, -}; - - -static opcode_rules * -load_opcode_rules(char *file_name) -{ - table *file = table_open(file_name, nr_opcode_fields, 0); - table_entry *entry; - opcode_rules *table = NULL; - opcode_rules **curr_rule = &table; - while ((entry = table_entry_read(file)) != NULL) { - opcode_rules *new_rule = ZALLOC(opcode_rules); - new_rule->first = target_a2i(hi_bit_nr, entry->fields[op_first]); - new_rule->last = target_a2i(hi_bit_nr, entry->fields[op_last]); - new_rule->force_first = target_a2i(hi_bit_nr, entry->fields[op_force_first]); - new_rule->force_last = target_a2i(hi_bit_nr, entry->fields[op_force_last]); - new_rule->force_slash = a2i(entry->fields[op_force_slash]); - new_rule->force_expansion = entry->fields[op_force_expansion]; - new_rule->use_switch = a2i(entry->fields[op_use_switch]); - new_rule->special_mask = a2i(entry->fields[op_special_mask]); - new_rule->special_value = a2i(entry->fields[op_special_value]); - new_rule->special_rule = a2i(entry->fields[op_special_rule]); - *curr_rule = new_rule; - curr_rule = &new_rule->next; - } - return table; -} - - -static void -dump_opcode_rule(opcode_rules *rule, - int indent) -{ - dumpf(indent, "((opcode_rules*)%p\n", rule); - if (rule) { - dumpf(indent, " (first %d)\n", rule->first); - dumpf(indent, " (last %d)\n", rule->last); - dumpf(indent, " (force_first %d)\n", rule->force_first); - dumpf(indent, " (force_last %d)\n", rule->force_last); - dumpf(indent, " (force_slash %d)\n", rule->force_slash); - dumpf(indent, " (force_expansion \"%s\")\n", rule->force_expansion); - dumpf(indent, " (use_switch %d)\n", rule->use_switch); - dumpf(indent, " (special_mask 0x%x)\n", rule->special_mask); - dumpf(indent, " (special_value 0x%x)\n", rule->special_value); - dumpf(indent, " (special_rule 0x%x)\n", rule->special_rule); - dumpf(indent, " (next 0x%x)\n", rule->next); - } - dumpf(indent, " )\n"); -} - - -static void -dump_opcode_rules(opcode_rules *rule, - int indent) -{ - while (rule) { - dump_opcode_rule(rule, indent); - rule = rule->next; - } -} - - -/****************************************************************/ - -typedef struct _insn_field insn_field; -struct _insn_field { - int first; - int last; - int width; - int is_int; - int is_slash; - int is_string; - int val_int; - char *pos_string; - char *val_string; - insn_field *next; - insn_field *prev; -}; - -typedef struct _insn_fields insn_fields; -struct _insn_fields { - insn_field *bits[max_insn_size]; - insn_field *first; - insn_field *last; - unsigned value; -}; - -static insn_fields * -parse_insn_format(table_entry *entry, - char *format) -{ - char *chp; - insn_fields *fields = ZALLOC(insn_fields); - - /* create a leading sentinal */ - fields->first = ZALLOC(insn_field); - fields->first->first = -1; - fields->first->last = -1; - fields->first->width = 0; - - /* and a trailing sentinal */ - fields->last = ZALLOC(insn_field); - fields->last->first = insn_size; - fields->last->last = insn_size; - fields->last->width = 0; - - /* link them together */ - fields->first->next = fields->last; - fields->last->prev = fields->first; - - /* now work through the formats */ - chp = format; - - while (*chp != '\0') { - char *start_pos; - char *start_val; - int strlen_val; - int strlen_pos; - insn_field *new_field; - - /* sanity check */ - if (!isdigit(*chp)) { - error("%s:%d: missing position field at `%s'\n", - entry->file_name, entry->line_nr, chp); - } - - /* break out the bit position */ - start_pos = chp; - while (isdigit(*chp)) - chp++; - strlen_pos = chp - start_pos; - if (*chp == '.' && strlen_pos > 0) - chp++; - else { - error("%s:%d: missing field value at %s\n", - entry->file_name, entry->line_nr, chp); - break; - } - - /* break out the value */ - start_val = chp; - while ((*start_val == '/' && *chp == '/') - || (isdigit(*start_val) && isdigit(*chp)) - || (isalpha(*start_val) && (isalnum(*chp) || *chp == '_'))) - chp++; - strlen_val = chp - start_val; - if (*chp == ',') - chp++; - else if (*chp != '\0' || strlen_val == 0) { - error("%s:%d: missing field terminator at %s\n", - entry->file_name, entry->line_nr, chp); - break; - } - - /* create a new field and insert it */ - new_field = ZALLOC(insn_field); - new_field->next = fields->last; - new_field->prev = fields->last->prev; - new_field->next->prev = new_field; - new_field->prev->next = new_field; - - /* the value */ - new_field->val_string = (char*)zalloc(strlen_val+1); - strncpy(new_field->val_string, start_val, strlen_val); - if (isdigit(*new_field->val_string)) { - new_field->val_int = a2i(new_field->val_string); - new_field->is_int = 1; - } - else if (new_field->val_string[0] == '/') { - new_field->is_slash = 1; - } - else { - new_field->is_string = 1; - } - - /* the pos */ - new_field->pos_string = (char*)zalloc(strlen_pos+1); - strncpy(new_field->pos_string, start_pos, strlen_pos); - new_field->first = target_a2i(hi_bit_nr, new_field->pos_string); - new_field->last = new_field->next->first - 1; /* guess */ - new_field->width = new_field->last - new_field->first + 1; /* guess */ - new_field->prev->last = new_field->first-1; /*fix*/ - new_field->prev->width = new_field->first - new_field->prev->first; /*fix*/ - } - - /* fiddle first/last so that the sentinals `disapear' */ - ASSERT(fields->first->last < 0); - ASSERT(fields->last->first >= insn_size); - fields->first = fields->first->next; - fields->last = fields->last->prev; - - /* now go over this again, pointing each bit position at a field - record */ - { - int i; - insn_field *field; - field = fields->first; - for (i = 0; i < insn_size; i++) { - while (field->last < i) - field = field->next; - fields->bits[i] = field; - } - } - - /* go over each of the fields, and compute a `value' for the insn */ - { - insn_field *field; - fields->value = 0; - for (field = fields->first; - field->last < insn_size; - field = field->next) { - fields->value <<= field->width; - if (field->is_int) - fields->value |= field->val_int; - } - } - return fields; -} - - -typedef enum { - field_constant_int = 1, - field_constant_slash = 2, - field_constant_string = 3 -} constant_field_types; - - -static int -insn_field_is_constant(insn_field *field, - opcode_rules *rule) -{ - /* field is an integer */ - if (field->is_int) - return field_constant_int; - /* field is `/' and treating that as a constant */ - if (field->is_slash && rule->force_slash) - return field_constant_slash; - /* field, though variable is on the list */ - if (field->is_string && rule->force_expansion != NULL) { - char *forced_fields = rule->force_expansion; - while (*forced_fields != '\0') { - int field_len; - char *end = strchr(forced_fields, ','); - if (end == NULL) - field_len = strlen(forced_fields); - else - field_len = end-forced_fields; - if (strncmp(forced_fields, field->val_string, field_len) == 0 - && field->val_string[field_len] == '\0') - return field_constant_string; - forced_fields += field_len; - if (*forced_fields == ',') - forced_fields++; - } - } - return 0; -} - - -static void -dump_insn_field(insn_field *field, - int indent) -{ - - printf("(insn_field*)0x%x\n", (unsigned)field); - - dumpf(indent, "(first %d)\n", field->first); - - dumpf(indent, "(last %d)\n", field->last); - - dumpf(indent, "(width %d)\n", field->width); - - if (field->is_int) - dumpf(indent, "(is_int %d)\n", field->val_int); - - if (field->is_slash) - dumpf(indent, "(is_slash)\n"); - - if (field->is_string) - dumpf(indent, "(is_string `%s')\n", field->val_string); - - dumpf(indent, "(next 0x%x)\n", field->next); - - dumpf(indent, "(prev 0x%x)\n", field->prev); - - -} - -static void -dump_insn_fields(insn_fields *fields, - int indent) -{ - int i; - - printf("(insn_fields*)%p\n", fields); - - dumpf(indent, "(first 0x%x)\n", fields->first); - dumpf(indent, "(last 0x%x)\n", fields->last); - - dumpf(indent, "(value 0x%x)\n", fields->value); - - for (i = 0; i < insn_size; i++) { - dumpf(indent, "(bits[%d] ", i, fields->bits[i]); - dump_insn_field(fields->bits[i], indent+1); - dumpf(indent, " )\n"); - } - -} - - -/****************************************************************/ - -typedef struct _opcode_field opcode_field; -struct _opcode_field { - int first; - int last; - int is_boolean; - opcode_field *parent; -}; - -static void -dump_opcode_field(opcode_field *field, int indent, int levels) -{ - printf("(opcode_field*)%p\n", field); - if (levels && field != NULL) { - dumpf(indent, "(first %d)\n", field->first); - dumpf(indent, "(last %d)\n", field->last); - dumpf(indent, "(is_boolean %d)\n", field->is_boolean); - dumpf(indent, "(parent "); - dump_opcode_field(field->parent, indent, levels-1); - } -} - - -/****************************************************************/ - -typedef struct _insn_bits insn_bits; -struct _insn_bits { - int is_expanded; - int value; - insn_field *field; - opcode_field *opcode; - insn_bits *last; -}; - - -static void -dump_insn_bits(insn_bits *bits, int indent, int levels) -{ - printf("(insn_bits*)%p\n", bits); - - if (levels && bits != NULL) { - dumpf(indent, "(value %d)\n", bits->value); - dumpf(indent, "(opcode "); - dump_opcode_field(bits->opcode, indent+1, 0); - dumpf(indent, " )\n"); - dumpf(indent, "(field "); - dump_insn_field(bits->field, indent+1); - dumpf(indent, " )\n"); - dumpf(indent, "(last "); - dump_insn_bits(bits->last, indent+1, levels-1); - } -} - - -/****************************************************************/ - - -typedef enum { - insn_format, - insn_form, - insn_flags, - insn_mnemonic, - insn_name, - insn_comment, - nr_insn_table_fields -} insn_table_fields; - -typedef enum { - function_type = insn_format, - function_name = insn_name, - function_param = insn_comment -} function_table_fields; - -typedef enum { - model_name = insn_mnemonic, - model_identifer = insn_name, - model_default = insn_comment, -} model_table_fields; - -typedef struct _insn insn; -struct _insn { - table_entry *file_entry; - insn_fields *fields; - insn *next; -}; - -typedef struct _insn_undef insn_undef; -struct _insn_undef { - insn_undef *next; - char *name; -}; - -static insn_undef *first_undef, *last_undef; - -typedef struct _model model; -struct _model { - model *next; - char *name; - char *printable_name; - char *insn_default; - table_model_entry *func_unit_start; - table_model_entry *func_unit_end; -}; - -typedef struct _insn_table insn_table; -struct _insn_table { - int opcode_nr; - insn_bits *expanded_bits; - int nr_insn; - insn *insns; - insn *functions; - insn *last_function; - opcode_rules *opcode_rule; - opcode_field *opcode; - int nr_entries; - insn_table *entries; - insn_table *sibling; - insn_table *parent; -}; - -typedef enum { - insn_model_name, - insn_model_fields, - nr_insn_model_table_fields -} insn_model_table_fields; - -static model *models; -static model *last_model; - -static insn *model_macros; -static insn *last_model_macro; - -static insn *model_functions; -static insn *last_model_function; - -static insn *model_internal; -static insn *last_model_internal; - -static insn *model_static; -static insn *last_model_static; - -static insn *model_data; -static insn *last_model_data; - -static int max_model_fields_len; - -static void -insn_table_insert_function(insn_table *table, - table_entry *file_entry) -{ - /* create a new function */ - insn *new_function = ZALLOC(insn); - new_function->file_entry = file_entry; - - /* append it to the end of the function list */ - if (table->last_function) - table->last_function->next = new_function; - else - table->functions = new_function; - table->last_function = new_function; -} - -static void -insn_table_insert_insn(insn_table *table, - table_entry *file_entry, - insn_fields *fields) -{ - insn **ptr_to_cur_insn = &table->insns; - insn *cur_insn = *ptr_to_cur_insn; - table_model_entry *insn_model_ptr; - model *model_ptr; - - /* create a new instruction */ - insn *new_insn = ZALLOC(insn); - new_insn->file_entry = file_entry; - new_insn->fields = fields; - - /* Check out any model information returned to make sure the model - is correct. */ - for(insn_model_ptr = file_entry->model_first; insn_model_ptr; insn_model_ptr = insn_model_ptr->next) { - char *name = insn_model_ptr->fields[insn_model_name]; - int len = strlen (insn_model_ptr->fields[insn_model_fields]); - - while (len > 0 && isspace(*insn_model_ptr->fields[insn_model_fields])) { - len--; - insn_model_ptr->fields[insn_model_fields]++; - } - - if (max_model_fields_len < len) - max_model_fields_len = len; - - for(model_ptr = models; model_ptr; model_ptr = model_ptr->next) { - if (strcmp(name, model_ptr->printable_name) == 0) { - - /* Replace the name field with that of the global model, so that when we - want to print it out, we can just compare pointers. */ - insn_model_ptr->fields[insn_model_name] = model_ptr->printable_name; - break; - } - } - - if (!model_ptr) - error("%s:%d: machine model `%s' was not known about\n", - file_entry->file_name, file_entry->line_nr, name); - } - - /* insert it according to the order of the fields */ - while (cur_insn != NULL - && new_insn->fields->value >= cur_insn->fields->value) { - ptr_to_cur_insn = &cur_insn->next; - cur_insn = *ptr_to_cur_insn; - } - - new_insn->next = cur_insn; - *ptr_to_cur_insn = new_insn; - - table->nr_insn++; -} - - -static opcode_field * -insn_table_find_opcode_field(insn *insns, - opcode_rules *rule, - int string_only) -{ - opcode_field *curr_opcode = ZALLOC(opcode_field); - insn *entry; - ASSERT(rule); - - curr_opcode->first = insn_size; - curr_opcode->last = -1; - for (entry = insns; entry != NULL; entry = entry->next) { - insn_fields *fields = entry->fields; - opcode_field new_opcode; - - /* find a start point for the opcode field */ - new_opcode.first = rule->first; - while (new_opcode.first <= rule->last - && (!string_only - || insn_field_is_constant(fields->bits[new_opcode.first], - rule) != field_constant_string) - && (string_only - || !insn_field_is_constant(fields->bits[new_opcode.first], - rule))) - new_opcode.first = fields->bits[new_opcode.first]->last + 1; - ASSERT(new_opcode.first > rule->last - || (string_only - && insn_field_is_constant(fields->bits[new_opcode.first], - rule) == field_constant_string) - || (!string_only - && insn_field_is_constant(fields->bits[new_opcode.first], - rule))); - - /* find the end point for the opcode field */ - new_opcode.last = rule->last; - while (new_opcode.last >= rule->first - && (!string_only - || insn_field_is_constant(fields->bits[new_opcode.last], - rule) != field_constant_string) - && (string_only - || !insn_field_is_constant(fields->bits[new_opcode.last], - rule))) - new_opcode.last = fields->bits[new_opcode.last]->first - 1; - ASSERT(new_opcode.last < rule->first - || (string_only - && insn_field_is_constant(fields->bits[new_opcode.last], - rule) == field_constant_string) - || (!string_only - && insn_field_is_constant(fields->bits[new_opcode.last], - rule))); - - /* now see if our current opcode needs expanding */ - if (new_opcode.first <= rule->last - && curr_opcode->first > new_opcode.first) - curr_opcode->first = new_opcode.first; - if (new_opcode.last >= rule->first - && curr_opcode->last < new_opcode.last) - curr_opcode->last = new_opcode.last; - - } - - /* was any thing interesting found? */ - if (curr_opcode->first > rule->last) { - ASSERT(curr_opcode->last < rule->first); - return NULL; - } - ASSERT(curr_opcode->last >= rule->first); - ASSERT(curr_opcode->first <= rule->last); - - /* if something was found, check it includes the forced field range */ - if (!string_only - && curr_opcode->first > rule->force_first) { - curr_opcode->first = rule->force_first; - } - if (!string_only - && curr_opcode->last < rule->force_last) { - curr_opcode->last = rule->force_last; - } - /* handle special case elminating any need to do shift after mask */ - if (string_only - && rule->force_last == insn_size-1) { - curr_opcode->last = insn_size-1; - } - - /* handle any special cases */ - switch (rule->special_rule) { - case 0: /* let the above apply */ - break; - case 1: /* expand a limited nr of bits, ignoring the rest */ - curr_opcode->first = rule->force_first; - curr_opcode->last = rule->force_last; - break; - case 2: /* boolean field */ - curr_opcode->is_boolean = 1; - break; - } - - return curr_opcode; -} - - -static void -insn_table_insert_expanded(insn_table *table, - insn *old_insn, - int new_opcode_nr, - insn_bits *new_bits) -{ - insn_table **ptr_to_cur_entry = &table->entries; - insn_table *cur_entry = *ptr_to_cur_entry; - - /* find the new table for this entry */ - while (cur_entry != NULL - && cur_entry->opcode_nr < new_opcode_nr) { - ptr_to_cur_entry = &cur_entry->sibling; - cur_entry = *ptr_to_cur_entry; - } - - if (cur_entry == NULL || cur_entry->opcode_nr != new_opcode_nr) { - insn_table *new_entry = ZALLOC(insn_table); - new_entry->opcode_nr = new_opcode_nr; - new_entry->expanded_bits = new_bits; - new_entry->opcode_rule = table->opcode_rule->next; - new_entry->sibling = cur_entry; - new_entry->parent = table; - *ptr_to_cur_entry = new_entry; - cur_entry = new_entry; - table->nr_entries++; - } - /* ASSERT new_bits == cur_entry bits */ - ASSERT(cur_entry != NULL && cur_entry->opcode_nr == new_opcode_nr); - insn_table_insert_insn(cur_entry, - old_insn->file_entry, - old_insn->fields); -} - -static void -insn_table_expand_opcode(insn_table *table, - insn *instruction, - int field_nr, - int opcode_nr, - insn_bits *bits) -{ - - if (field_nr > table->opcode->last) { - insn_table_insert_expanded(table, instruction, opcode_nr, bits); - } - else { - insn_field *field = instruction->fields->bits[field_nr]; - if (field->is_int || field->is_slash) { - ASSERT(field->first >= table->opcode->first - && field->last <= table->opcode->last); - insn_table_expand_opcode(table, instruction, field->last+1, - ((opcode_nr << field->width) + field->val_int), - bits); - } - else { - int val; - int last_pos = ((field->last < table->opcode->last) - ? field->last : table->opcode->last); - int first_pos = ((field->first > table->opcode->first) - ? field->first : table->opcode->first); - int width = last_pos - first_pos + 1; - int last_val = (table->opcode->is_boolean - ? 2 : (1 << width)); - for (val = 0; val < last_val; val++) { - insn_bits *new_bits = ZALLOC(insn_bits); - new_bits->field = field; - new_bits->value = val; - new_bits->last = bits; - new_bits->opcode = table->opcode; - insn_table_expand_opcode(table, instruction, last_pos+1, - ((opcode_nr << width) | val), - new_bits); - } - } - } -} - -static void -insn_table_insert_expanding(insn_table *table, - insn *entry) -{ - insn_table_expand_opcode(table, - entry, - table->opcode->first, - 0, - table->expanded_bits); -} - - -static void -insn_table_expand_insns(insn_table *table) -{ - - ASSERT(table->nr_insn >= 1); - - /* determine a valid opcode */ - while (table->opcode_rule) { - /* specials only for single instructions */ - if ((table->nr_insn > 1 - && table->opcode_rule->special_mask == 0 - && table->opcode_rule->special_rule == 0) - || (table->nr_insn == 1 - && table->opcode_rule->special_mask != 0 - && ((table->insns->fields->value - & table->opcode_rule->special_mask) - == table->opcode_rule->special_value)) - || (idecode_expand_semantics - && table->opcode_rule->special_mask == 0 - && table->opcode_rule->special_rule == 0)) - table->opcode = - insn_table_find_opcode_field(table->insns, - table->opcode_rule, - table->nr_insn == 1/*string*/ - ); - if (table->opcode != NULL) - break; - table->opcode_rule = table->opcode_rule->next; - } - - /* did we find anything */ - if (table->opcode == NULL) { - return; - } - ASSERT(table->opcode != NULL); - - /* back link what we found to its parent */ - if (table->parent != NULL) { - ASSERT(table->parent->opcode != NULL); - table->opcode->parent = table->parent->opcode; - } - - /* expand the raw instructions according to the opcode */ - { - insn *entry; - for (entry = table->insns; entry != NULL; entry = entry->next) { - insn_table_insert_expanding(table, entry); - } - } - - /* and do the same for the sub entries */ - { - insn_table *entry; - for (entry = table->entries; entry != NULL; entry = entry->sibling) { - insn_table_expand_insns(entry); - } - } -} - - -static void -model_table_insert(insn_table *table, - table_entry *file_entry) -{ - int len; - - /* create a new model */ - model *new_model = ZALLOC(model); - - new_model->name = file_entry->fields[model_identifer]; - new_model->printable_name = file_entry->fields[model_name]; - new_model->insn_default = file_entry->fields[model_default]; - - while (*new_model->insn_default && isspace(*new_model->insn_default)) - new_model->insn_default++; - - len = strlen(new_model->insn_default); - if (max_model_fields_len < len) - max_model_fields_len = len; - - /* append it to the end of the model list */ - if (last_model) - last_model->next = new_model; - else - models = new_model; - last_model = new_model; -} - -static void -model_table_insert_specific(insn_table *table, - table_entry *file_entry, - insn **start_ptr, - insn **end_ptr) -{ - insn *ptr = ZALLOC(insn); - ptr->file_entry = file_entry; - if (*end_ptr) - (*end_ptr)->next = ptr; - else - (*start_ptr) = ptr; - (*end_ptr) = ptr; -} - - - -static insn_table * -insn_table_load_insns(char *file_name) -{ - table *file = table_open(file_name, nr_insn_table_fields, nr_insn_model_table_fields); - insn_table *table = ZALLOC(insn_table); - table_entry *file_entry; - table->opcode_rule = opcode_table; - - while ((file_entry = table_entry_read(file)) != NULL) { - if (it_is("function", file_entry->fields[insn_flags]) - || it_is("internal", file_entry->fields[insn_flags])) { - insn_table_insert_function(table, file_entry); - } - else if (it_is("model", file_entry->fields[insn_flags])) { - model_table_insert(table, file_entry); - } - else if (it_is("model-macro", file_entry->fields[insn_flags])) { - model_table_insert_specific(table, file_entry, &model_macros, &last_model_macro); - } - else if (it_is("model-function", file_entry->fields[insn_flags])) { - model_table_insert_specific(table, file_entry, &model_functions, &last_model_function); - } - else if (it_is("model-internal", file_entry->fields[insn_flags])) { - model_table_insert_specific(table, file_entry, &model_internal, &last_model_internal); - } - else if (it_is("model-static", file_entry->fields[insn_flags])) { - model_table_insert_specific(table, file_entry, &model_static, &last_model_static); - } - else if (it_is("model-data", file_entry->fields[insn_flags])) { - model_table_insert_specific(table, file_entry, &model_data, &last_model_data); - } - else { - insn_fields *fields; - /* skip instructions that aren't relevant to the mode */ - filter *filt = filters; - while (filt != NULL) { - if (it_is(filt->flag, file_entry->fields[insn_flags])) - break; - filt = filt->next; - } - if (filt == NULL) { - /* create/insert the new instruction */ - fields = parse_insn_format(file_entry, - file_entry->fields[insn_format]); - insn_table_insert_insn(table, file_entry, fields); - } - } - } - return table; -} - - -static void -dump_insn(insn *entry, int indent, int levels) -{ - printf("(insn*)%p\n", entry); - - if (levels && entry != NULL) { - - dumpf(indent, "(file_entry "); - dump_table_entry(entry->file_entry, indent+1); - dumpf(indent, " )\n"); - - dumpf(indent, "(fields "); - dump_insn_fields(entry->fields, indent+1); - dumpf(indent, " )\n"); - - dumpf(indent, "(next "); - dump_insn(entry->next, indent+1, levels-1); - dumpf(indent, " )\n"); - - } - -} - - -static void -dump_insn_table(insn_table *table, - int indent, int levels) -{ - - printf("(insn_table*)%p\n", table); - - if (levels && table != NULL) { - - dumpf(indent, "(opcode_nr %d)\n", table->opcode_nr); - - dumpf(indent, "(expanded_bits "); - dump_insn_bits(table->expanded_bits, indent+1, -1); - dumpf(indent, " )\n"); - - dumpf(indent, "(int nr_insn %d)\n", table->nr_insn); - - dumpf(indent, "(insns "); - dump_insn(table->insns, indent+1, table->nr_insn); - dumpf(indent, " )\n"); - - dumpf(indent, "(opcode_rule "); - dump_opcode_rule(table->opcode_rule, indent+1); - dumpf(indent, " )\n"); - - dumpf(indent, "(opcode "); - dump_opcode_field(table->opcode, indent+1, 1); - dumpf(indent, " )\n"); - - dumpf(indent, "(nr_entries %d)\n", table->entries); - dumpf(indent, "(entries "); - dump_insn_table(table->entries, indent+1, table->nr_entries); - dumpf(indent, " )\n"); - - dumpf(indent, "(sibling ", table->sibling); - dump_insn_table(table->sibling, indent+1, levels-1); - dumpf(indent, " )\n"); - - dumpf(indent, "(parent ", table->parent); - dump_insn_table(table->parent, indent+1, 0); - dumpf(indent, " )\n"); - - } -} - - -/****************************************************************/ - - -static void -lf_print_insn_bits(lf *file, insn_bits *bits) -{ - if (bits == NULL) - return; - lf_print_insn_bits(file, bits->last); - lf_putchr(file, '_'); - lf_putstr(file, bits->field->val_string); - if (!bits->opcode->is_boolean || bits->value == 0) { - if (bits->opcode->last < bits->field->last) - lf_putint(file, bits->value << (bits->field->last - bits->opcode->last)); - else - lf_putint(file, bits->value); - } -} - -static void -lf_print_opcodes(lf *file, - insn_table *table) -{ - if (table != NULL) { - while (1) { - lf_printf(file, "_%d_%d", - table->opcode->first, - table->opcode->last); - if (table->parent == NULL) break; - lf_printf(file, "__%d", table->opcode_nr); - table = table->parent; - } - } -} - -static void -lf_print_table_name(lf *file, - insn_table *table) -{ - lf_printf(file, "idecode_table"); - lf_print_opcodes(file, table); -} - - - -typedef enum { - function_name_prefix_semantics, - function_name_prefix_idecode, - function_name_prefix_itable, - function_name_prefix_none -} lf_function_name_prefixes; - -static void -lf_print_function_name(lf *file, - char *basename, - insn_bits *expanded_bits, - lf_function_name_prefixes prefix) -{ - - /* the prefix */ - switch (prefix) { - case function_name_prefix_semantics: - lf_putstr(file, "semantic_"); - break; - case function_name_prefix_idecode: - lf_printf(file, "idecode_"); - break; - case function_name_prefix_itable: - lf_putstr(file, "itable_"); - break; - default: - break; - } - - /* the function name */ - { - char *pos; - for (pos = basename; - *pos != '\0'; - pos++) { - switch (*pos) { - case '/': - case '-': - break; - case ' ': - lf_putchr(file, '_'); - break; - default: - lf_putchr(file, *pos); - break; - } - } - } - - /* the suffix */ - if (idecode_expand_semantics) - lf_print_insn_bits(file, expanded_bits); -} - - -static void -lf_print_idecode_table(lf *file, - insn_table *entry) -{ - int can_assume_leaf; - opcode_rules *opcode_rule; - - /* have a look at the rule table, if all table rules follow all - switch rules, I can assume that all end points are leaves */ - opcode_rule = opcode_table; - while (opcode_rule != NULL - && opcode_rule->use_switch) - opcode_rule = opcode_rule->next; - while (opcode_rule != NULL - && opcode_rule->use_switch - && opcode_rule->special_rule) - opcode_rule = opcode_rule->next; - can_assume_leaf = opcode_rule == NULL; - - lf_printf(file, "{\n"); - lf_indent(file, +2); - { - lf_printf(file, "idecode_table_entry *table = "); - lf_print_table_name(file, entry); - lf_printf(file, ";\n"); - lf_printf(file, "int opcode = EXTRACTED32(instruction, %d, %d);\n", - i2target(hi_bit_nr, entry->opcode->first), - i2target(hi_bit_nr, entry->opcode->last)); - lf_printf(file, "idecode_table_entry *table_entry = table + opcode;\n"); - lf_printf(file, "while (1) {\n"); - lf_indent(file, +2); - { - lf_printf(file, "/* nonzero mask -> another table */\n"); - lf_printf(file, "while (table_entry->mask != 0) {\n"); - lf_indent(file, +2); - { - lf_printf(file, "table = ((idecode_table_entry*)\n"); - lf_printf(file, " table_entry->function_or_table);\n"); - lf_printf(file, "opcode = ((instruction & table_entry->mask)\n"); - lf_printf(file, " >> table_entry->shift);\n"); - lf_printf(file, "table_entry = table + opcode;\n"); - } - lf_indent(file, -2); - lf_printf(file, "}\n"); - lf_printf(file, "ASSERT(table_entry->mask == 0);\n"); - if (can_assume_leaf) - lf_printf(file, "ASSERT(table_entry->shift == 0);\n"); - else { - lf_printf(file, "if (table_entry->shift == 0)\n"); - lf_indent(file, +2); - } - if (idecode_cache) { - lf_printf(file, "return (((idecode_crack*)\n"); - lf_printf(file, " table_entry->function_or_table)\n"); - lf_printf(file, " (%s));\n", cache_idecode_actual); - } - else { - lf_printf(file, "return (((idecode_semantic*)\n"); - lf_printf(file, " table_entry->function_or_table)\n"); - lf_printf(file, " (%s));\n", semantic_actual); - } - if (!can_assume_leaf) { - lf_indent(file, -2); - lf_printf(file, "/* must be a boolean */\n"); - lf_printf(file, "opcode = (instruction & table_entry->shift) != 0;\n"); - lf_printf(file, "table = ((idecode_table_entry*)\n"); - lf_printf(file, " table_entry->function_or_table);\n"); - lf_printf(file, "table_entry = table + opcode;\n"); - } - } - lf_indent(file, -2); - lf_printf(file, "}\n"); - } - lf_indent(file, -2); - lf_printf(file, "}\n"); -} - - -static void -lf_print_my_prefix(lf *file, - table_entry *file_entry, - int idecode) -{ - lf_printf(file, "const char *const my_prefix __attribute__((__unused__)) = \n"); - lf_printf(file, " \"%s:%s:%s:%d\";\n", - filter_filename (file_entry->file_name), - (idecode ? "idecode" : "semantics"), - file_entry->fields[insn_name], - file_entry->line_nr); - lf_printf(file, "const itable_index my_index __attribute__((__unused__)) = "); - lf_print_function_name(file, - file_entry->fields[insn_name], - NULL, - function_name_prefix_itable); - lf_printf(file, ";\n"); -} - - -static void -lf_print_ptrace(lf *file, - int idecode) -{ - lf_printf(file, "\n"); - lf_printf(file, "ITRACE(trace_%s, (\"\\n\"));\n", - (idecode ? "idecode" : "semantics")); -} - - -/****************************************************************/ - -typedef void leaf_handler -(insn_table *entry, - void *data, - int depth); -typedef void padding_handler -(insn_table *table, - void *data, - int depth, - int opcode_nr); - - -static void -insn_table_traverse_tree(insn_table *table, - void *data, - int depth, - leaf_handler *start, - leaf_handler *leaf, - leaf_handler *end, - padding_handler *padding) -{ - insn_table *entry; - int entry_nr; - - ASSERT(table != NULL - && table->opcode != NULL - && table->nr_entries > 0 - && table->entries != 0); - - if (start != NULL && depth >= 0) - start(table, data, depth); - - for (entry_nr = 0, entry = table->entries; - entry_nr < (table->opcode->is_boolean - ? 2 - : (1 << (table->opcode->last - table->opcode->first + 1))); - entry_nr ++) { - if (entry == NULL - || (!table->opcode->is_boolean - && entry_nr < entry->opcode_nr)) { - if (padding != NULL && depth >= 0) - padding(table, data, depth, entry_nr); - } - else { - ASSERT(entry != NULL && (entry->opcode_nr == entry_nr - || table->opcode->is_boolean)); - if (entry->opcode != NULL && depth != 0) { - insn_table_traverse_tree(entry, data, depth+1, - start, leaf, end, padding); - } - else if (depth >= 0) { - if (leaf != NULL) - leaf(entry, data, depth); - } - entry = entry->sibling; - } - } - if (end != NULL && depth >= 0) - end(table, data, depth); -} - - -typedef void function_handler -(insn_table *table, - void *data, - table_entry *function); - -static void -insn_table_traverse_function(insn_table *table, - void *data, - function_handler *leaf) -{ - insn *function; - for (function = table->functions; - function != NULL; - function = function->next) { - leaf(table, data, function->file_entry); - } -} - - -typedef void insn_handler -(insn_table *table, - void *data, - insn *instruction); - -static void -insn_table_traverse_insn(insn_table *table, - void *data, - insn_handler *leaf) -{ - insn *instruction; - for (instruction = table->insns; - instruction != NULL; - instruction = instruction->next) { - leaf(table, data, instruction); - } -} - - -static void -update_depth(insn_table *entry, - void *data, - int depth) -{ - int *max_depth = (int*)data; - if (*max_depth < depth) - *max_depth = depth; -} - - -static int -insn_table_depth(insn_table *table) -{ - int depth = 0; - insn_table_traverse_tree(table, - &depth, - 1, - NULL, /*start*/ - update_depth, - NULL, /*end*/ - NULL); /*padding*/ - return depth; -} - - -/****************************************************************/ - -static void -dump_traverse_start(insn_table *table, - void *data, - int depth) -{ - dumpf(depth*2, "(%d\n", table->opcode_nr); -} - -static void -dump_traverse_leaf(insn_table *entry, - void *data, - int depth) -{ - ASSERT(entry->nr_entries == 0 - && entry->nr_insn == 1 - && entry->opcode == NULL); - dumpf(depth*2, ".%d %s\n", entry->opcode_nr, - entry->insns->file_entry->fields[insn_format]); -} - -static void -dump_traverse_end(insn_table *table, - void *data, - int depth) -{ - dumpf(depth*2, ")\n"); -} - -static void -dump_traverse_padding(insn_table *table, - void *data, - int depth, - int opcode_nr) -{ - dumpf(depth*2, ".<%d>\n", opcode_nr); -} - - -static void -dump_traverse(insn_table *table) -{ - insn_table_traverse_tree(table, NULL, 1, - dump_traverse_start, - dump_traverse_leaf, - dump_traverse_end, - dump_traverse_padding); -} - - -/****************************************************************/ - - -static void -lf_print_semantic_function_header(lf *file, - char *basename, - insn_bits *expanded_bits, - int is_function_definition, - int is_inline_function) -{ - lf_printf(file, "\n"); - lf_print_function_type(file, "unsigned_word", "EXTERN_SEMANTICS", - " "); - lf_print_function_name(file, - basename, - expanded_bits, - function_name_prefix_semantics); - lf_printf(file, "\n(%s)", - (idecode_cache ? cache_semantic_formal : semantic_formal)); - if (!is_function_definition) - lf_printf(file, ";"); - lf_printf(file, "\n"); -} - - -static void -semantics_h_leaf(insn_table *entry, - void *data, - int depth) -{ - lf *file = (lf*)data; - ASSERT(entry->nr_insn == 1); - lf_print_semantic_function_header(file, - entry->insns->file_entry->fields[insn_name], - entry->expanded_bits, - 0/* isnt function definition*/, - !idecode_cache && entry->parent->opcode_rule->use_switch); -} - -static void -semantics_h_insn(insn_table *entry, - void *data, - insn *instruction) -{ - lf *file = (lf*)data; - lf_print_semantic_function_header(file, - instruction->file_entry->fields[insn_name], - NULL, - 0/*isnt function definition*/, - 0/*isnt inline function*/); -} - -static void -semantics_h_function(insn_table *entry, - void *data, - table_entry *function) -{ - lf *file = (lf*)data; - if (function->fields[function_type] == NULL - || function->fields[function_type][0] == '\0') { - lf_print_semantic_function_header(file, - function->fields[function_name], - NULL, - 0/*isnt function definition*/, - 1/*is inline function*/); - } - else { - lf_printf(file, "\n"); - lf_print_function_type(file, function->fields[function_type], - "INLINE_SEMANTICS", " "); - lf_printf(file, "%s\n(%s);\n", - function->fields[function_name], - function->fields[function_param]); - } -} - - -static void -gen_semantics_h(insn_table *table, lf *file) -{ - - lf_print_copyleft(file); - lf_printf(file, "\n"); - lf_printf(file, "#ifndef _SEMANTICS_H_\n"); - lf_printf(file, "#define _SEMANTICS_H_\n"); - lf_printf(file, "\n"); - - /* output a declaration for all functions */ - insn_table_traverse_function(table, - file, - semantics_h_function); - - /* output a declaration for all instructions */ - if (idecode_expand_semantics) - insn_table_traverse_tree(table, - file, - 1, - NULL, /* start */ - semantics_h_leaf, /* leaf */ - NULL, /* end */ - NULL); /* padding */ - else - insn_table_traverse_insn(table, - file, - semantics_h_insn); - - lf_printf(file, "\n"); - lf_printf(file, "#endif /* _SEMANTICS_H_ */\n"); - -} - -/****************************************************************/ - -typedef struct _icache_tree icache_tree; -struct _icache_tree { - char *name; - icache_tree *next; - icache_tree *children; -}; - -static icache_tree * -icache_tree_insert(icache_tree *tree, - char *name) -{ - icache_tree *new_tree; - /* find it */ - icache_tree **ptr_to_cur_tree = &tree->children; - icache_tree *cur_tree = *ptr_to_cur_tree; - while (cur_tree != NULL - && strcmp(cur_tree->name, name) < 0) { - ptr_to_cur_tree = &cur_tree->next; - cur_tree = *ptr_to_cur_tree; - } - ASSERT(cur_tree == NULL - || strcmp(cur_tree->name, name) >= 0); - /* already in the tree */ - if (cur_tree != NULL - && strcmp(cur_tree->name, name) == 0) - return cur_tree; - /* missing, insert it */ - ASSERT(cur_tree == NULL - || strcmp(cur_tree->name, name) > 0); - new_tree = ZALLOC(icache_tree); - new_tree->name = name; - new_tree->next = cur_tree; - *ptr_to_cur_tree = new_tree; - return new_tree; -} - - -static icache_tree * -insn_table_cache_fields(insn_table *table) -{ - icache_tree *tree = ZALLOC(icache_tree); - insn *instruction; - for (instruction = table->insns; - instruction != NULL; - instruction = instruction->next) { - insn_field *field; - icache_tree *form = - icache_tree_insert(tree, - instruction->file_entry->fields[insn_form]); - for (field = instruction->fields->first; - field != NULL; - field = field->next) { - if (field->is_string) - icache_tree_insert(form, field->val_string); - } - } - return tree; -} - - - -static void -gen_icache_h(icache_tree *tree, - lf *file) -{ - lf_print_copyleft(file); - lf_printf(file, "\n"); - lf_printf(file, "#ifndef _ICACHE_H_\n"); - lf_printf(file, "#define _ICACHE_H_\n"); - lf_printf(file, "\n"); - - lf_printf(file, "#define WITH_IDECODE_CACHE_SIZE %d\n", - idecode_cache); - lf_printf(file, "\n"); - - /* create an instruction cache if being used */ - if (idecode_cache) { - icache_tree *form; - lf_printf(file, "typedef struct _idecode_cache {\n"); - lf_printf(file, " unsigned_word address;\n"); - lf_printf(file, " void *semantic;\n"); - lf_printf(file, " union {\n"); - for (form = tree->children; - form != NULL; - form = form->next) { - icache_tree *field; - lf_printf(file, " struct {\n"); - for (field = form->children; - field != NULL; - field = field->next) { - cache_rules *cache_rule; - int found_rule = 0; - for (cache_rule = cache_table; - cache_rule != NULL; - cache_rule = cache_rule->next) { - if (strcmp(field->name, cache_rule->old_name) == 0) { - found_rule = 1; - if (cache_rule->new_name != NULL) - lf_printf(file, " %s %s; /* %s */\n", - (cache_rule->type == NULL - ? "unsigned" - : cache_rule->type), - cache_rule->new_name, - cache_rule->old_name); - } - } - if (!found_rule) - lf_printf(file, " unsigned %s;\n", field->name); - } - lf_printf(file, " } %s;\n", form->name); - } - lf_printf(file, " } crack;\n"); - lf_printf(file, "} idecode_cache;\n"); - } - else { - /* alernativly, since no cache, #define the fields to be - extractions from the instruction variable. Emit a dummy - definition for idecode_cache to allow model_issue to not - be #ifdefed at the call level */ - cache_rules *cache_rule; - lf_printf(file, "\n"); - lf_printf(file, "typedef void idecode_cache;\n"); - lf_printf(file, "\n"); - for (cache_rule = cache_table; - cache_rule != NULL; - cache_rule = cache_rule->next) { - if (cache_rule->expression != NULL - && strlen(cache_rule->expression) > 0) - lf_printf(file, "#define %s %s\n", - cache_rule->new_name, cache_rule->expression); - } - } - - lf_printf(file, "\n"); - lf_printf(file, "#endif /* _ICACHE_H_ */\n"); -} - - - - -/****************************************************************/ - - -static void -lf_print_c_extraction(lf *file, - insn *instruction, - char *field_name, - char *field_type, - char *field_expression, - insn_field *cur_field, - insn_bits *bits, - int get_value_from_cache, - int put_value_in_cache) -{ - ASSERT(field_name != NULL); - if (bits != NULL - && (!bits->opcode->is_boolean || bits->value == 0) - && strcmp(field_name, cur_field->val_string) == 0) { - ASSERT(bits->field == cur_field); - ASSERT(field_type == NULL); - table_entry_lf_c_line_nr(file, instruction->file_entry); - lf_printf(file, "const unsigned %s __attribute__((__unused__)) = ", - field_name); - if (bits->opcode->last < bits->field->last) - lf_printf(file, "%d;\n", - bits->value << (bits->field->last - bits->opcode->last)); - else - lf_printf(file, "%d;\n", bits->value); - } - else if (get_value_from_cache && !put_value_in_cache - && semantics_use_cache_struct) { - insn_undef *undef = ZALLOC(insn_undef); - /* Use #define to reference the cache struct directly, rather than putting - them into local variables */ - lf_indent_suppress(file); - lf_printf(file, "#define %s (cache_entry->crack.%s.%s)\n", - field_name, - instruction->file_entry->fields[insn_form], - field_name); - - if (first_undef) - last_undef->next = undef; - else - first_undef = undef; - last_undef = undef;; - undef->name = field_name; - } - else { - /* put the field in the local variable */ - table_entry_lf_c_line_nr(file, instruction->file_entry); - lf_printf(file, "%s const %s __attribute__((__unused__)) = ", - field_type == NULL ? "unsigned" : field_type, - field_name); - /* getting it from the cache */ - if (get_value_from_cache || put_value_in_cache) { - lf_printf(file, "cache_entry->crack.%s.%s", - instruction->file_entry->fields[insn_form], - field_name); - if (put_value_in_cache) /* also put it in the cache? */ - lf_printf(file, " = "); - } - if (!get_value_from_cache) { - if (strcmp(field_name, cur_field->val_string) == 0) - lf_printf(file, "EXTRACTED32(instruction, %d, %d)", - i2target(hi_bit_nr, cur_field->first), - i2target(hi_bit_nr, cur_field->last)); - else if (field_expression != NULL) - lf_printf(file, "%s", field_expression); - else - lf_printf(file, "eval_%s", field_name); - } - lf_printf(file, ";\n"); - } -} - - -static void -lf_print_c_extractions(lf *file, - insn *instruction, - insn_bits *expanded_bits, - int get_value_from_cache, - int put_value_in_cache) -{ - insn_field *cur_field; - - /* extract instruction fields */ - lf_printf(file, "/* extraction: %s */\n", - instruction->file_entry->fields[insn_format]); - - for (cur_field = instruction->fields->first; - cur_field->first < insn_size; - cur_field = cur_field->next) { - if (cur_field->is_string) { - insn_bits *bits; - int found_rule = 0; - /* find any corresponding value */ - for (bits = expanded_bits; - bits != NULL; - bits = bits->last) { - if (bits->field == cur_field) - break; - } - /* try the cache rule table for what to do */ - if (get_value_from_cache || put_value_in_cache) { - cache_rules *cache_rule; - for (cache_rule = cache_table; - cache_rule != NULL; - cache_rule = cache_rule->next) { - if (strcmp(cur_field->val_string, cache_rule->old_name) == 0) { - found_rule = 1; - if (cache_rule->valid > 1 && put_value_in_cache) - lf_print_c_extraction(file, - instruction, - cache_rule->new_name, - cache_rule->type, - cache_rule->expression, - cur_field, - bits, - 0, - 0); - else if (cache_rule->valid == 1) - lf_print_c_extraction(file, - instruction, - cache_rule->new_name, - cache_rule->type, - cache_rule->expression, - cur_field, - bits, - get_value_from_cache, - put_value_in_cache); - } - } - } - if (found_rule == 0) - lf_print_c_extraction(file, - instruction, - cur_field->val_string, - 0, - 0, - cur_field, - bits, - get_value_from_cache, - put_value_in_cache); - /* if any (XXX == 0), output a corresponding test */ - if (instruction->file_entry->annex != NULL) { - char *field_name = cur_field->val_string; - char *is_0_ptr = instruction->file_entry->annex; - int field_len = strlen(field_name); - if (strlen(is_0_ptr) >= (strlen("_is_0") + field_len)) { - is_0_ptr += field_len; - while ((is_0_ptr = strstr(is_0_ptr, "_is_0")) != NULL) { - if (strncmp(is_0_ptr - field_len, field_name, field_len) == 0 - && !isalpha(is_0_ptr[ - field_len - 1])) { - table_entry_lf_c_line_nr(file, instruction->file_entry); - lf_printf(file, "const unsigned %s_is_0 __attribute__((__unused__)) = (", field_name); - if (bits != NULL) - lf_printf(file, "%d", bits->value); - else - lf_printf(file, "%s", field_name); - lf_printf(file, " == 0);\n"); - break; - } - is_0_ptr += strlen("_is_0"); - } - } - } - /* any thing else ... */ - } - } - lf_print_lf_c_line_nr(file); -} - - -static void -lf_print_idecode_illegal(lf *file) -{ - if (idecode_cache) - lf_printf(file, "return idecode_illegal(%s);\n", cache_idecode_actual); - else - lf_printf(file, "return semantic_illegal(%s);\n", semantic_actual); -} - - -static void -lf_print_idecode_floating_point_unavailable(lf *file) -{ - if (idecode_cache) - lf_printf(file, "return idecode_floating_point_unavailable(%s);\n", - cache_idecode_actual); - else - lf_printf(file, "return semantic_floating_point_unavailable(%s);\n", - semantic_actual); -} - - -/* Output code to do any final checks on the decoded instruction. - This includes things like verifying any on decoded fields have the - correct value and checking that (for floating point) floating point - hardware isn't disabled */ - -static void -lf_print_c_validate(lf *file, - insn *instruction, - opcode_field *opcodes) -{ - /* Validate: unchecked instruction fields - - If any constant fields in the instruction were not checked by the - idecode tables, output code to check that they have the correct - value here */ - { - unsigned check_mask = 0; - unsigned check_val = 0; - insn_field *field; - opcode_field *opcode; - - /* form check_mask/check_val containing what needs to be checked - in the instruction */ - for (field = instruction->fields->first; - field->first < insn_size; - field = field->next) { - - check_mask <<= field->width; - check_val <<= field->width; - - /* is it a constant that could need validating? */ - if (!field->is_int && !field->is_slash) - continue; - - /* has it been checked by a table? */ - for (opcode = opcodes; opcode != NULL; opcode = opcode->parent) { - if (field->first >= opcode->first - && field->last <= opcode->last) - break; - } - if (opcode != NULL) - continue; - - check_mask |= (1 << field->width)-1; - check_val |= field->val_int; - } - - /* if any bits not checked by opcode tables, output code to check them */ - if (check_mask) { - lf_printf(file, "\n"); - lf_printf(file, "/* validate: %s */\n", - instruction->file_entry->fields[insn_format]); - lf_printf(file, "if (WITH_RESERVED_BITS && (instruction & 0x%x) != 0x%x)\n", - check_mask, check_val); - lf_indent(file, +2); - lf_print_idecode_illegal(file); - lf_indent(file, -2); - } - } - - /* Validate floating point hardware - - If the simulator is being built with out floating point hardware - (different to it being disabled in the MSR) then floating point - instructions are invalid */ - { - if (it_is("f", instruction->file_entry->fields[insn_flags])) { - lf_printf(file, "\n"); - lf_printf(file, "/* Validate: FP hardware exists */\n"); - lf_printf(file, "if (CURRENT_FLOATING_POINT != HARD_FLOATING_POINT)\n"); - lf_indent(file, +2); - lf_print_idecode_illegal(file); - lf_indent(file, -2); - } - } - - /* Validate: Floating Point available - - If floating point is not available, we enter a floating point - unavailable interrupt into the cache instead of the instruction - proper. - - The PowerPC spec requires a CSI after MSR[FP] is changed and when - ever a CSI occures we flush the instruction cache. */ - - { - if (it_is("f", instruction->file_entry->fields[insn_flags])) { - lf_printf(file, "\n"); - lf_printf(file, "/* Validate: FP available according to MSR[FP] */\n"); - lf_printf(file, "if (!IS_FP_AVAILABLE(processor))\n"); - lf_indent(file, +2); - lf_print_idecode_floating_point_unavailable(file); - lf_indent(file, -2); - } - } -} - - -static void -lf_print_c_cracker(lf *file, - insn *instruction, - insn_bits *expanded_bits, - opcode_field *opcodes) -{ - - /* function header */ - lf_printf(file, "{\n"); - lf_indent(file, +2); - - lf_print_my_prefix(file, - instruction->file_entry, - 1/*putting-value-in-cache*/); - - lf_print_ptrace(file, - 1/*putting-value-in-cache*/); - - lf_print_c_validate(file, instruction, opcodes); - - lf_printf(file, "\n"); - lf_printf(file, "{\n"); - lf_indent(file, +2); - lf_print_c_extractions(file, - instruction, - expanded_bits, - 0/*get_value_from_cache*/, - 1/*put_value_in_cache*/); - lf_indent(file, -2); - lf_printf(file, "}\n"); - - /* return the function propper (main sorts this one out) */ - lf_printf(file, "\n"); - lf_printf(file, "/* semantic routine */\n"); - table_entry_lf_c_line_nr(file, instruction->file_entry); - lf_printf(file, "return "); - lf_print_function_name(file, - instruction->file_entry->fields[insn_name], - expanded_bits, - function_name_prefix_semantics); - lf_printf(file, ";\n"); - - lf_print_lf_c_line_nr(file); - lf_indent(file, -2); - lf_printf(file, "}\n"); -} - - -static void -lf_print_c_semantic(lf *file, - insn *instruction, - insn_bits *expanded_bits, - opcode_field *opcodes) -{ - - lf_printf(file, "{\n"); - lf_indent(file, +2); - - lf_print_my_prefix(file, - instruction->file_entry, - 0/*not putting value in cache*/); - lf_printf(file, "unsigned_word nia = cia + %d;\n", insn_size / 8); - - lf_printf(file, "\n"); - lf_print_c_extractions(file, - instruction, - expanded_bits, - idecode_cache/*get_value_from_cache*/, - 0/*put_value_in_cache*/); - - lf_print_ptrace(file, - 0/*put_value_in_cache*/); - - /* validate the instruction, if a cache this has already been done */ - if (!idecode_cache) - lf_print_c_validate(file, instruction, opcodes); - - /* generate the profiling call - this is delayed until after the - instruction has been verified */ - lf_printf(file, "\n"); - lf_printf(file, "if (WITH_MON & MONITOR_INSTRUCTION_ISSUE) {\n"); - lf_printf(file, " mon_issue("); - lf_print_function_name(file, - instruction->file_entry->fields[insn_name], - NULL, - function_name_prefix_itable); - lf_printf(file, ", processor, cia);\n"); - lf_printf(file, "}\n"); - lf_printf(file, "\n"); - - /* generate the code (or at least something */ - if (instruction->file_entry->annex != NULL) { - /* true code */ - lf_printf(file, "\n"); - table_entry_lf_c_line_nr(file, instruction->file_entry); - lf_printf(file, "{\n"); - lf_indent(file, +2); - lf_print_c_code(file, instruction->file_entry->annex); - lf_indent(file, -2); - lf_printf(file, "}\n"); - lf_print_lf_c_line_nr(file); - } - else if (it_is("nop", instruction->file_entry->fields[insn_flags])) { - lf_print_lf_c_line_nr(file); - } - else if (it_is("f", instruction->file_entry->fields[insn_flags])) { - /* unimplemented floating point instruction - call for assistance */ - lf_printf(file, "\n"); - lf_printf(file, "/* unimplemented floating point instruction - call for assistance */\n"); - table_entry_lf_c_line_nr(file, instruction->file_entry); - lf_putstr(file, "floating_point_assist_interrupt(processor, cia);\n"); - lf_print_lf_c_line_nr(file); - } - else { - /* abort so it is implemented now */ - table_entry_lf_c_line_nr(file, instruction->file_entry); - lf_putstr(file, "error(\"%s: unimplemented, cia=0x%x\\n\", my_prefix, cia);\n"); - lf_print_lf_c_line_nr(file); - lf_printf(file, "\n"); - } - - lf_printf(file, "return nia;\n"); - lf_indent(file, -2); - lf_printf(file, "}\n"); -} - -static void -lf_print_c_semantic_function(lf *file, - insn *instruction, - insn_bits *expanded_bits, - opcode_field *opcodes, - int is_inline_function) -{ - insn_undef *undef, *next; - - /* build the semantic routine to execute the instruction */ - lf_print_semantic_function_header(file, - instruction->file_entry->fields[insn_name], - expanded_bits, - 1/*is-function-definition*/, - is_inline_function); - lf_print_c_semantic(file, - instruction, - expanded_bits, - opcodes); - - /* If we are referencing the cache structure directly instead of putting the values - in local variables, undef any defines we created */ - for(undef = first_undef; undef; undef = next) { - next = undef->next; - lf_indent_suppress(file); - lf_printf(file, "#undef %s\n", undef->name); - free((void *)undef); - } - first_undef = (insn_undef *)0; - last_undef = (insn_undef *)0; -} - - -static void -semantics_c_leaf(insn_table *entry, - void *data, - int depth) -{ - lf *file = (lf*)data; - ASSERT(entry->nr_insn == 1 - && entry->opcode == NULL - && entry->parent != NULL - && entry->parent->opcode != NULL); - lf_print_c_semantic_function(file, - entry->insns, - entry->expanded_bits, - entry->parent->opcode, - !idecode_cache && entry->parent->opcode_rule->use_switch); -} - -static void -semantics_c_insn(insn_table *table, - void *data, - insn *instruction) -{ - lf *file = (lf*)data; - lf_print_c_semantic_function(file, instruction, - NULL, NULL, - 0/*isnt_inline_function*/); -} - -static void -semantics_c_function(insn_table *table, - void *data, - table_entry *function) -{ - lf *file = (lf*)data; - if (function->fields[function_type] == NULL - || function->fields[function_type][0] == '\0') { - lf_print_semantic_function_header(file, - function->fields[function_name], - NULL, - 1/*is function definition*/, - 1/*is inline function*/); - } - else { - lf_printf(file, "\n"); - lf_print_function_type(file, function->fields[function_type], - "INLINE_SEMANTICS", "\n"); - lf_printf(file, "%s(%s)\n", - function->fields[function_name], - function->fields[function_param]); - } - table_entry_lf_c_line_nr(file, function); - lf_printf(file, "{\n"); - lf_indent(file, +2); - lf_print_c_code(file, function->annex); - lf_indent(file, -2); - lf_printf(file, "}\n"); - lf_print_lf_c_line_nr(file); -} - - - -static void -gen_semantics_c(insn_table *table, lf *file) -{ - lf_print_copyleft(file); - lf_printf(file, "\n"); - lf_printf(file, "#ifndef _SEMANTICS_C_\n"); - lf_printf(file, "#define _SEMANTICS_C_\n"); - lf_printf(file, "\n"); - lf_printf(file, "#include \"cpu.h\"\n"); - lf_printf(file, "#include \"idecode.h\"\n"); - lf_printf(file, "#include \"semantics.h\"\n"); - lf_printf(file, "\n"); - - /* output a definition (c-code) for all functions */ - insn_table_traverse_function(table, - file, - semantics_c_function); - - /* output a definition (c-code) for all instructions */ - if (idecode_expand_semantics) - insn_table_traverse_tree(table, - file, - 1, - NULL, /* start */ - semantics_c_leaf, - NULL, /* end */ - NULL); /* padding */ - else - insn_table_traverse_insn(table, - file, - semantics_c_insn); - - lf_printf(file, "\n"); - lf_printf(file, "#endif /* _SEMANTICS_C_ */\n"); -} - - -/****************************************************************/ - -static void -gen_idecode_h(insn_table *table, lf *file) -{ - lf_print_copyleft(file); - lf_printf(file, "\n"); - lf_printf(file, "#ifndef _IDECODE_H_\n"); - lf_printf(file, "#define _IDECODE_H_\n"); - lf_printf(file, "\n"); - lf_printf(file, "#include \"idecode_expression.h\"\n"); - lf_printf(file, "#include \"idecode_fields.h\"\n"); - lf_printf(file, "#include \"idecode_branch.h\"\n"); - lf_printf(file, "\n"); - lf_printf(file, "#include \"icache.h\"\n"); - lf_printf(file, "\n"); - lf_printf(file, "typedef unsigned_word idecode_semantic\n(%s);\n", - (idecode_cache ? cache_semantic_formal : semantic_formal)); - lf_printf(file, "\n"); - if (idecode_cache) { - lf_print_function_type(file, "idecode_semantic *", "INLINE_IDECODE", " "); - lf_printf(file, "idecode\n(%s);\n", cache_idecode_formal); - } - else { - lf_print_function_type(file, "unsigned_word", "INLINE_IDECODE", " "); - lf_printf(file, "idecode_issue\n(%s);\n", semantic_formal); - } - lf_printf(file, "\n"); - lf_printf(file, "#endif /* _IDECODE_H_ */\n"); -} - - -/****************************************************************/ - - -static void -idecode_table_start(insn_table *table, - void *data, - int depth) -{ - lf *file = (lf*)data; - ASSERT(depth == 0); - /* start of the table */ - if (!table->opcode_rule->use_switch) { - lf_printf(file, "\n"); - lf_printf(file, "static idecode_table_entry "); - lf_print_table_name(file, table); - lf_printf(file, "[] = {\n"); - } -} - -static void -idecode_table_leaf(insn_table *entry, - void *data, - int depth) -{ - lf *file = (lf*)data; - ASSERT(entry->parent != NULL); - ASSERT(depth == 0); - - /* add an entry to the table */ - if (!entry->parent->opcode_rule->use_switch) { - if (entry->opcode == NULL) { - /* table leaf entry */ - lf_printf(file, " /*%d*/ { 0, 0, ", entry->opcode_nr); - lf_print_function_name(file, - entry->insns->file_entry->fields[insn_name], - entry->expanded_bits, - (idecode_cache - ? function_name_prefix_idecode - : function_name_prefix_semantics)); - lf_printf(file, " },\n"); - } - else if (entry->opcode_rule->use_switch) { - /* table calling switch statement */ - lf_printf(file, " /*%d*/ { 0, 0, ", - entry->opcode_nr); - lf_print_table_name(file, entry); - lf_printf(file, " },\n"); - } - else { - /* table `calling' another table */ - lf_printf(file, " /*%d*/ { ", entry->opcode_nr); - if (entry->opcode->is_boolean) - lf_printf(file, "MASK32(%d,%d), 0, ", - i2target(hi_bit_nr, entry->opcode->first), - i2target(hi_bit_nr, entry->opcode->last)); - else - lf_printf(file, "%d, MASK32(%d,%d), ", - insn_size - entry->opcode->last - 1, - i2target(hi_bit_nr, entry->opcode->first), - i2target(hi_bit_nr, entry->opcode->last)); - lf_print_table_name(file, entry); - lf_printf(file, " },\n"); - } - } -} - -static void -idecode_table_end(insn_table *table, - void *data, - int depth) -{ - lf *file = (lf*)data; - ASSERT(depth == 0); - - if (!table->opcode_rule->use_switch) { - lf_printf(file, "};\n"); - } -} - -static void -idecode_table_padding(insn_table *table, - void *data, - int depth, - int opcode_nr) -{ - lf *file = (lf*)data; - ASSERT(depth == 0); - - if (!table->opcode_rule->use_switch) { - lf_printf(file, " /*%d*/ { 0, 0, %s_illegal },\n", - opcode_nr, (idecode_cache ? "idecode" : "semantic")); - } -} - - -/****************************************************************/ - - -void lf_print_idecode_switch -(lf *file, - insn_table *table); - - -static void -idecode_switch_start(insn_table *table, - void *data, - int depth) -{ - lf *file = (lf*)data; - ASSERT(depth == 0); - ASSERT(table->opcode_rule->use_switch); - - lf_printf(file, "switch (EXTRACTED32(instruction, %d, %d)) {\n", - i2target(hi_bit_nr, table->opcode->first), - i2target(hi_bit_nr, table->opcode->last)); -} - - -static void -idecode_switch_leaf(insn_table *entry, - void *data, - int depth) -{ - lf *file = (lf*)data; - ASSERT(entry->parent != NULL); - ASSERT(depth == 0); - ASSERT(entry->parent->opcode_rule->use_switch); - ASSERT(entry->parent->opcode); - - if (!entry->parent->opcode->is_boolean - || entry->opcode_nr == 0) - lf_printf(file, "case %d:\n", entry->opcode_nr); - else - lf_printf(file, "default:\n"); - lf_indent(file, +2); - { - if (entry->opcode == NULL) { - /* switch calling leaf */ - lf_printf(file, "return "); - lf_print_function_name(file, - entry->insns->file_entry->fields[insn_name], - entry->expanded_bits, - (idecode_cache - ? function_name_prefix_idecode - : function_name_prefix_semantics)); - if (idecode_cache) - lf_printf(file, "(%s);\n", cache_idecode_actual); - else - lf_printf(file, "(%s);\n", semantic_actual); - } - else if (entry->opcode_rule->use_switch) { - /* switch calling switch */ - lf_print_idecode_switch(file, entry); - } - else { - /* switch looking up a table */ - lf_print_idecode_table(file, entry); - } - lf_printf(file, "break;\n"); - } - lf_indent(file, -2); -} - - -static void -lf_print_idecode_switch_illegal(lf *file) -{ - lf_indent(file, +2); - lf_print_idecode_illegal(file); - lf_printf(file, "break;\n"); - lf_indent(file, -2); -} - -static void -idecode_switch_end(insn_table *table, - void *data, - int depth) -{ - lf *file = (lf*)data; - ASSERT(depth == 0); - ASSERT(table->opcode_rule->use_switch); - ASSERT(table->opcode); - - lf_printf(file, "default:\n"); - if (table->opcode_rule->use_switch == 1 - && !table->opcode->is_boolean) { - lf_print_idecode_switch_illegal(file); - } - else { - lf_printf(file, " error(\"igen internal error - bad switch generated\n\");\n"); - } - lf_printf(file, "}\n"); -} - -static void -idecode_switch_padding(insn_table *table, - void *data, - int depth, - int opcode_nr) -{ - lf *file = (lf*)data; - - ASSERT(depth == 0); - ASSERT(table->opcode_rule->use_switch); - - if (table->opcode_rule->use_switch > 1) { - lf_printf(file, "case %d:\n", opcode_nr); - lf_print_idecode_switch_illegal(file); - } -} - - -void -lf_print_idecode_switch(lf *file, - insn_table *table) -{ - insn_table_traverse_tree(table, - file, - 0, - idecode_switch_start, - idecode_switch_leaf, - idecode_switch_end, - idecode_switch_padding); -} - - -static void -lf_print_idecode_switch_function_header(lf *file, - insn_table *table, - int is_function_definition) -{ - lf_printf(file, "\n"); - lf_printf(file, "static "); - if (idecode_cache) - lf_printf(file, "idecode_semantic *"); - else - lf_printf(file, "unsigned_word"); - if (is_function_definition) - lf_printf(file, "\n"); - else - lf_printf(file, " "); - lf_print_table_name(file, table); - lf_printf(file, "\n(%s)", - (idecode_cache ? cache_idecode_formal : semantic_formal)); - if (!is_function_definition) - lf_printf(file, ";"); - lf_printf(file, "\n"); -} - - -static void -idecode_declare_if_switch(insn_table *table, - void *data, - int depth) -{ - lf *file = (lf*)data; - - if (table->opcode_rule->use_switch - && table->parent != NULL /* don't declare the top one yet */ - && !table->parent->opcode_rule->use_switch) { - lf_print_idecode_switch_function_header(file, - table, - 0/*isnt function definition*/); - } -} - - -static void -idecode_expand_if_switch(insn_table *table, - void *data, - int depth) -{ - lf *file = (lf*)data; - - if (table->opcode_rule->use_switch - && table->parent != NULL /* don't expand the top one yet */ - && !table->parent->opcode_rule->use_switch) { - lf_print_idecode_switch_function_header(file, - table, - 1/*is function definition*/); - lf_printf(file, "{\n"); - { - lf_indent(file, +2); - lf_print_idecode_switch(file, table); - lf_indent(file, -2); - } - lf_printf(file, "}\n"); - } -} - +#include "table.h" +#include "config.h" -static void -lf_print_c_cracker_function(lf *file, - insn *instruction, - insn_bits *expanded_bits, - opcode_field *opcodes, - int is_inline_function) -{ - /* if needed, generate code to enter this routine into a cache */ - lf_printf(file, "\n"); - lf_printf(file, "static idecode_semantic *\n"); - lf_print_function_name(file, - instruction->file_entry->fields[insn_name], - expanded_bits, - function_name_prefix_idecode); - lf_printf(file, "\n(%s)\n", cache_idecode_formal); +#include "filter.h" - lf_print_c_cracker(file, - instruction, - expanded_bits, - opcodes); -} +#include "ld-decode.h" +#include "ld-cache.h" +#include "ld-insn.h" -static void -idecode_crack_leaf(insn_table *entry, - void *data, - int depth) -{ - lf *file = (lf*)data; - ASSERT(entry->nr_insn == 1 - && entry->opcode == NULL - && entry->parent != NULL - && entry->parent->opcode != NULL - && entry->parent->opcode_rule != NULL); - lf_print_c_cracker_function(file, - entry->insns, - entry->expanded_bits, - entry->opcode, - entry->parent->opcode_rule->use_switch); -} +#include "igen.h" -static void -idecode_crack_insn(insn_table *entry, - void *data, - insn *instruction) -{ - lf *file = (lf*)data; - lf_print_c_cracker_function(file, - instruction, - NULL, - NULL, - 0/*isnt inline function*/); -} +#include "gen-model.h" +#include "gen-icache.h" +#include "gen-itable.h" +#include "gen-idecode.h" +#include "gen-semantics.h" +#include "gen-support.h" -static void -idecode_c_internal_function(insn_table *table, - void *data, - table_entry *function) -{ - lf *file = (lf*)data; - ASSERT(idecode_cache != 0); - if (it_is("internal", function->fields[insn_flags])) { - lf_printf(file, "\n"); - lf_print_function_type(file, "idecode_semantic *", "STATIC_INLINE_IDECODE", - "\n"); - lf_print_function_name(file, - function->fields[insn_name], - NULL, - function_name_prefix_idecode); - lf_printf(file, "\n(%s)\n", cache_idecode_formal); - lf_printf(file, "{\n"); - lf_indent(file, +2); - lf_printf(file, "/* semantic routine */\n"); - table_entry_lf_c_line_nr(file, function); - lf_printf(file, "return "); - lf_print_function_name(file, - function->fields[insn_name], - NULL, - function_name_prefix_semantics); - lf_printf(file, ";\n"); +int hi_bit_nr; +int insn_bit_size = max_insn_bit_size; - lf_print_lf_c_line_nr(file); - lf_indent(file, -2); - lf_printf(file, "}\n"); - } -} +igen_code code = generate_calls; +int generate_expanded_instructions; +int icache_size; +int generate_smp; /****************************************************************/ -static void -gen_idecode_c(insn_table *table, lf *file) +static int +print_insn_bits(lf *file, insn_bits *bits) { - int depth; - - /* the intro */ - lf_print_copyleft(file); - lf_printf(file, "\n"); - lf_printf(file, "\n"); - lf_printf(file, "#ifndef _IDECODE_C_\n"); - lf_printf(file, "#define _IDECODE_C_\n"); - lf_printf(file, "\n"); - lf_printf(file, "#include \"cpu.h\"\n"); - lf_printf(file, "#include \"idecode.h\"\n"); - lf_printf(file, "#include \"semantics.h\"\n"); - lf_printf(file, "\n"); - lf_printf(file, "\n"); - lf_printf(file, "typedef idecode_semantic *idecode_crack\n(%s);\n", - (idecode_cache ? cache_idecode_formal : semantic_formal)); - lf_printf(file, "\n"); - lf_printf(file, "typedef struct _idecode_table_entry {\n"); - lf_printf(file, " unsigned shift;\n"); - lf_printf(file, " unsigned mask;\n"); - lf_printf(file, " void *function_or_table;\n"); - lf_printf(file, "} idecode_table_entry;\n"); - lf_printf(file, "\n"); - lf_printf(file, "\n"); - - /* output `internal' invalid/floating-point unavailable functions - where needed */ - if (idecode_cache) { - insn_table_traverse_function(table, - file, - idecode_c_internal_function); - } - - /* output cracking functions where needed */ - if (idecode_cache) { - if (idecode_expand_semantics) - insn_table_traverse_tree(table, - file, - 1, - NULL, - idecode_crack_leaf, - NULL, - NULL); + int nr = 0; + if (bits == NULL) + return nr; + nr += print_insn_bits(file, bits->last); + nr += lf_putchr(file, '_'); + nr += lf_putstr(file, bits->field->val_string); + if (bits->opcode->is_boolean && bits->value == 0) + nr += lf_putint(file, bits->opcode->boolean_constant); + else if (!bits->opcode->is_boolean) { + if (bits->opcode->last < bits->field->last) + nr += lf_putint(file, bits->value << (bits->field->last - bits->opcode->last)); else - insn_table_traverse_insn(table, - file, - idecode_crack_insn); + nr += lf_putint(file, bits->value); } + return nr; +} - /* output switch function declarations where needed by tables */ - insn_table_traverse_tree(table, - file, - 1, - idecode_declare_if_switch, /* START */ - NULL, NULL, NULL); - - /* output tables where needed */ - for (depth = insn_table_depth(table); - depth > 0; - depth--) { - insn_table_traverse_tree(table, - file, - 1-depth, - idecode_table_start, - idecode_table_leaf, - idecode_table_end, - idecode_table_padding); +extern int +print_function_name(lf *file, + const char *basename, + insn_bits *expanded_bits, + lf_function_name_prefixes prefix) +{ + int nr = 0; + /* the prefix */ + switch (prefix) { + case function_name_prefix_semantics: + nr += lf_putstr(file, "semantic_"); + break; + case function_name_prefix_idecode: + nr += lf_printf(file, "idecode_"); + break; + case function_name_prefix_itable: + nr += lf_putstr(file, "itable_"); + break; + case function_name_prefix_icache: + nr += lf_putstr(file, "icache_"); + break; + default: + break; } - /* output switch functions where needed */ - insn_table_traverse_tree(table, - file, - 1, - idecode_expand_if_switch, /* START */ - NULL, NULL, NULL); - - /* output the main idecode routine */ - lf_printf(file, "\n"); - if (idecode_cache) { - lf_print_function_type(file, "idecode_semantic *", "INLINE_IDECODE", "\n"); - lf_printf(file, "idecode\n(%s)\n", cache_idecode_formal); - } - else { - lf_print_function_type(file, "unsigned_word", "INLINE_IDECODE", "\n"); - lf_printf(file, "idecode_issue\n(%s)\n", semantic_formal); + /* the function name */ + { + const char *pos; + for (pos = basename; + *pos != '\0'; + pos++) { + switch (*pos) { + case '/': + case '-': + break; + case ' ': + nr += lf_putchr(file, '_'); + break; + default: + nr += lf_putchr(file, *pos); + break; + } + } } - lf_printf(file, "{\n"); - lf_indent(file, +2); - if (table->opcode_rule->use_switch) - lf_print_idecode_switch(file, table); - else - lf_print_idecode_table(file, table); - lf_indent(file, -2); - lf_printf(file, "}\n"); - lf_printf(file, "\n"); - lf_printf(file, "#endif /* _IDECODE_C_ */\n"); -} - -/****************************************************************/ + /* the suffix */ + if (generate_expanded_instructions) + nr += print_insn_bits(file, expanded_bits); -static void -itable_h_insn(insn_table *entry, - void *data, - insn *instruction) -{ - lf *file = (lf*)data; - lf_printf(file, " "); - lf_print_function_name(file, - instruction->file_entry->fields[insn_name], - NULL, - function_name_prefix_itable); - lf_printf(file, ",\n"); + return nr; } -static void -gen_itable_h(insn_table *table, lf *file) +void +print_define_my_index(lf *file, + table_entry *file_entry) { - - lf_print_copyleft(file); - lf_printf(file, "\n"); - lf_printf(file, "#ifndef _ITABLE_H_\n"); - lf_printf(file, "#define _ITABLE_H_\n"); - lf_printf(file, "\n"); - - /* output an enumerated type for each instruction */ - lf_printf(file, "typedef enum {\n"); - insn_table_traverse_insn(table, - file, - itable_h_insn); - lf_printf(file, " nr_itable_entries,\n"); - lf_printf(file, "} itable_index;\n"); - lf_printf(file, "\n"); - - /* output the table that contains the actual instruction info */ - lf_printf(file, "typedef struct _itable_instruction_info {\n"); - lf_printf(file, " itable_index nr;\n"); - lf_printf(file, " char *format;\n"); - lf_printf(file, " char *form;\n"); - lf_printf(file, " char *flags;\n"); - lf_printf(file, " char *mnemonic;\n"); - lf_printf(file, " char *name;\n"); - lf_printf(file, "} itable_info;\n"); - lf_printf(file, "\n"); - lf_printf(file, "extern itable_info itable[nr_itable_entries];\n"); - + lf_indent_suppress(file); + lf_printf(file, "#undef MY_INDEX\n"); + lf_indent_suppress(file); + lf_printf(file, "#define MY_INDEX "); + print_function_name(file, + file_entry->fields[insn_name], + NULL, + function_name_prefix_itable); lf_printf(file, "\n"); - lf_printf(file, "#endif /* _ITABLE_C_ */\n"); - } -/****************************************************************/ -static void -itable_c_insn(insn_table *entry, - void *data, - insn *instruction) +void +print_itrace(lf *file, + table_entry *file_entry, + int idecode) { - lf *file = (lf*)data; - char **fields = instruction->file_entry->fields; - lf_printf(file, " { "); - lf_print_function_name(file, - instruction->file_entry->fields[insn_name], - NULL, - function_name_prefix_itable); - lf_printf(file, ",\n"); - lf_printf(file, " \"%s\",\n", fields[insn_format]); - lf_printf(file, " \"%s\",\n", fields[insn_form]); - lf_printf(file, " \"%s\",\n", fields[insn_flags]); - lf_printf(file, " \"%s\",\n", fields[insn_mnemonic]); - lf_printf(file, " \"%s\",\n", fields[insn_name]); - lf_printf(file, " },\n"); + lf_print__external_reference(file, file_entry->line_nr, file_entry->file_name); + lf_printf(file, "ITRACE(trace_%s, (\"%s %s\\n\"));\n", + (idecode ? "idecode" : "semantics"), + (idecode ? "idecode" : "semantics"), + file_entry->fields[insn_name]); + lf_print__internal_reference(file); } -static void -gen_itable_c(insn_table *table, lf *file) -{ - - lf_print_copyleft(file); - lf_printf(file, "\n"); - lf_printf(file, "#ifndef _ITABLE_C_\n"); - lf_printf(file, "#define _ITABLE_C_\n"); - lf_printf(file, "\n"); - lf_printf(file, "#include \"itable.h\"\n"); - lf_printf(file, "\n"); - - /* output the table that contains the actual instruction info */ - lf_printf(file, "itable_info itable[nr_itable_entries] = {\n"); - insn_table_traverse_insn(table, - file, - itable_c_insn); - lf_printf(file, "};\n"); - lf_printf(file, "\n"); - - lf_printf(file, "\n"); - lf_printf(file, "#endif /* _ITABLE_C_ */\n"); -} - /****************************************************************/ -static void -model_c_or_h_data(insn_table *table, - lf *file, - table_entry *data) -{ - if (data->annex) { - table_entry_lf_c_line_nr(file, data); - lf_print_c_code(file, data->annex); - lf_print_lf_c_line_nr(file); - lf_printf(file, "\n"); - } -} static void -model_c_or_h_function(insn_table *entry, - lf *file, - table_entry *function, - char *prefix) -{ - if (function->fields[function_type] == NULL - || function->fields[function_type][0] == '\0') { - error("Model function type not specified for %s", function->fields[function_name]); - } - lf_printf(file, "\n"); - lf_print_function_type(file, function->fields[function_type], prefix, " "); - lf_printf(file, "%s\n(%s);\n", - function->fields[function_name], - function->fields[function_param]); - lf_printf(file, "\n"); -} - -static void -gen_model_h(insn_table *table, lf *file) +gen_semantics_h(insn_table *table, + lf *file, + igen_code generate) { - insn *insn_ptr; - model *model_ptr; - insn *macro; - char *name; - int model_create_p = 0; - int model_init_p = 0; - int model_halt_p = 0; - int model_mon_info_p = 0; - int model_mon_info_free_p = 0; - - lf_print_copyleft(file); - lf_printf(file, "\n"); - lf_printf(file, "#ifndef _MODEL_H_\n"); - lf_printf(file, "#define _MODEL_H_\n"); - lf_printf(file, "\n"); - - for(macro = model_macros; macro; macro = macro->next) { - model_c_or_h_data(table, file, macro->file_entry); - } - - lf_printf(file, "typedef enum _model_enum {\n"); - lf_printf(file, " MODEL_NONE,\n"); - for (model_ptr = models; model_ptr; model_ptr = model_ptr->next) { - lf_printf(file, " MODEL_%s,\n", model_ptr->name); - } - lf_printf(file, " nr_models\n"); - lf_printf(file, "} model_enum;\n"); - lf_printf(file, "\n"); - - lf_printf(file, "#define DEFAULT_MODEL MODEL_%s\n", (models) ? models->name : "NONE"); - lf_printf(file, "\n"); - - lf_printf(file, "typedef struct _model_data model_data;\n"); - lf_printf(file, "typedef struct _model_time model_time;\n"); + lf_printf(file, "typedef %s idecode_semantic\n(%s);\n", + SEMANTIC_FUNCTION_TYPE, + SEMANTIC_FUNCTION_FORMAL); lf_printf(file, "\n"); - - lf_printf(file, "extern model_enum current_model;\n"); - lf_printf(file, "extern const char *model_name[ (int)nr_models ];\n"); - lf_printf(file, "extern const char *const *const model_func_unit_name[ (int)nr_models ];\n"); - lf_printf(file, "extern const model_time *const model_time_mapping[ (int)nr_models ];\n"); - lf_printf(file, "\n"); - - for(insn_ptr = model_functions; insn_ptr; insn_ptr = insn_ptr->next) { - model_c_or_h_function(table, file, insn_ptr->file_entry, "INLINE_MODEL"); - name = insn_ptr->file_entry->fields[function_name]; - if (strcmp (name, "model_create") == 0) - model_create_p = 1; - else if (strcmp (name, "model_init") == 0) - model_init_p = 1; - else if (strcmp (name, "model_halt") == 0) - model_halt_p = 1; - else if (strcmp (name, "model_mon_info") == 0) - model_mon_info_p = 1; - else if (strcmp (name, "model_mon_info_free") == 0) - model_mon_info_free_p = 1; + if ((code & generate_calls)) { + if (generate_expanded_instructions) + insn_table_traverse_tree(table, + file, NULL, + 1, + NULL, /* start */ + print_semantic_declaration, /* leaf */ + NULL, /* end */ + NULL); /* padding */ + else + insn_table_traverse_insn(table, + file, NULL, + print_semantic_declaration); + } - - if (!model_create_p) { - lf_print_function_type(file, "model_data *", "INLINE_MODEL", " "); - lf_printf(file, "model_create\n"); - lf_printf(file, "(cpu *processor);\n"); - lf_printf(file, "\n"); + else { + lf_print__this_file_is_empty(file); } +} - if (!model_init_p) { - lf_print_function_type(file, "void", "INLINE_MODEL", " "); - lf_printf(file, "model_init\n"); - lf_printf(file, "(model_data *model_ptr);\n"); - lf_printf(file, "\n"); - } - if (!model_halt_p) { - lf_print_function_type(file, "void", "INLINE_MODEL", " "); - lf_printf(file, "model_halt\n"); - lf_printf(file, "(model_data *model_ptr);\n"); +static void +gen_semantics_c(insn_table *table, + cache_table *cache_rules, + lf *file, + igen_code generate) +{ + if ((code & generate_calls)) { lf_printf(file, "\n"); - } - - if (!model_mon_info_p) { - lf_print_function_type(file, "model_print *", "INLINE_MODEL", " "); - lf_printf(file, "model_mon_info\n"); - lf_printf(file, "(model_data *model_ptr);\n"); + lf_printf(file, "#include \"cpu.h\"\n"); + lf_printf(file, "#include \"idecode.h\"\n"); + lf_printf(file, "#include \"semantics.h\"\n"); + lf_printf(file, "#include \"support.h\"\n"); lf_printf(file, "\n"); + if (generate_expanded_instructions) + insn_table_traverse_tree(table, + file, cache_rules, + 1, + NULL, /* start */ + print_semantic_definition, /* leaf */ + NULL, /* end */ + NULL); /* padding */ + else + insn_table_traverse_insn(table, + file, cache_rules, + print_semantic_definition); + } - - if (!model_mon_info_free_p) { - lf_print_function_type(file, "void", "INLINE_MODEL", " "); - lf_printf(file, "model_mon_info_free\n"); - lf_printf(file, "(model_data *model_ptr,\n"); - lf_printf(file, " model_print *info_ptr);\n"); - lf_printf(file, "\n"); + else { + lf_print__this_file_is_empty(file); } - - lf_print_function_type(file, "void", "INLINE_MODEL", " "); - lf_printf(file, "model_set\n"); - lf_printf(file, "(const char *name);\n"); - lf_printf(file, "\n"); - lf_printf(file, "#endif /* _MODEL_H_ */\n"); } -/****************************************************************/ - -typedef struct _model_c_passed_data model_c_passed_data; -struct _model_c_passed_data { - lf *file; - model *model_ptr; -}; - -static void -model_c_insn(insn_table *entry, - void *data, - insn *instruction) -{ - model_c_passed_data *data_ptr = (model_c_passed_data *)data; - lf *file = data_ptr->file; - char *current_name = data_ptr->model_ptr->printable_name; - table_model_entry *model_ptr = instruction->file_entry->model_first; - - while (model_ptr) { - if (model_ptr->fields[insn_model_name] == current_name) { - lf_printf(file, " { %-*s }, /* %s */\n", - max_model_fields_len, - model_ptr->fields[insn_model_fields], - instruction->file_entry->fields[insn_name]); - return; - } - model_ptr = model_ptr->next; - } +/****************************************************************/ - lf_printf(file, " { %-*s }, /* %s */\n", - max_model_fields_len, - data_ptr->model_ptr->insn_default, - instruction->file_entry->fields[insn_name]); -} static void -model_c_function(insn_table *table, - lf *file, - table_entry *function, - const char *prefix) +gen_icache_h(insn_table *table, + lf *file, + igen_code generate) { - if (function->fields[function_type] == NULL - || function->fields[function_type][0] == '\0') { - error("Model function return type not specified for %s", function->fields[function_name]); + lf_printf(file, "typedef %s idecode_icache\n(%s);\n", + ICACHE_FUNCTION_TYPE, + ICACHE_FUNCTION_FORMAL); + lf_printf(file, "\n"); + if ((code & generate_calls) + && (code & generate_with_icache)) { + insn_table_traverse_function(table, + file, NULL, + print_icache_internal_function_declaration); + if (generate_expanded_instructions) + insn_table_traverse_tree(table, + file, NULL, + 1, + NULL, /* start */ + print_icache_declaration, /* leaf */ + NULL, /* end */ + NULL); /* padding */ + else + insn_table_traverse_insn(table, + file, NULL, + print_icache_declaration); + } else { - lf_printf(file, "\n"); - lf_print_function_type(file, function->fields[function_type], prefix, "\n"); - lf_printf(file, "%s(%s)\n", - function->fields[function_name], - function->fields[function_param]); + lf_print__this_file_is_empty(file); } - table_entry_lf_c_line_nr(file, function); - lf_printf(file, "{\n"); - if (function->annex) { - lf_indent(file, +2); - lf_print_c_code(file, function->annex); - lf_indent(file, -2); - } - lf_printf(file, "}\n"); - lf_print_lf_c_line_nr(file); - lf_printf(file, "\n"); } -static void -gen_model_c(insn_table *table, lf *file) +static void +gen_icache_c(insn_table *table, + cache_table *cache_rules, + lf *file, + igen_code generate) { - insn *insn_ptr; - model *model_ptr; - char *name; - int model_create_p = 0; - int model_init_p = 0; - int model_halt_p = 0; - int model_mon_info_p = 0; - int model_mon_info_free_p = 0; - - lf_print_copyleft(file); - lf_printf(file, "\n"); - lf_printf(file, "#ifndef _MODEL_C_\n"); - lf_printf(file, "#define _MODEL_C_\n"); - lf_printf(file, "\n"); - lf_printf(file, "#include \"cpu.h\"\n"); - lf_printf(file, "#include \"mon.h\"\n"); - lf_printf(file, "\n"); - lf_printf(file, "#ifdef HAVE_STDLIB_H\n"); - lf_printf(file, "#include \n"); - lf_printf(file, "#endif\n"); - lf_printf(file, "\n"); - - for(insn_ptr = model_data; insn_ptr; insn_ptr = insn_ptr->next) { - model_c_or_h_data(table, file, insn_ptr->file_entry); - } - - for(insn_ptr = model_static; insn_ptr; insn_ptr = insn_ptr->next) { - model_c_or_h_function(table, file, insn_ptr->file_entry, "/*h*/STATIC"); - } - - for(insn_ptr = model_internal; insn_ptr; insn_ptr = insn_ptr->next) { - model_c_or_h_function(table, file, insn_ptr->file_entry, "STATIC_INLINE_MODEL"); - } - - for(insn_ptr = model_static; insn_ptr; insn_ptr = insn_ptr->next) { - model_c_function(table, file, insn_ptr->file_entry, "/*c*/STATIC"); - } - - for(insn_ptr = model_internal; insn_ptr; insn_ptr = insn_ptr->next) { - model_c_function(table, file, insn_ptr->file_entry, "STATIC_INLINE_MODEL"); - } - - for(insn_ptr = model_functions; insn_ptr; insn_ptr = insn_ptr->next) { - model_c_function(table, file, insn_ptr->file_entry, "INLINE_MODEL"); - name = insn_ptr->file_entry->fields[function_name]; - if (strcmp (name, "model_create") == 0) - model_create_p = 1; - else if (strcmp (name, "model_init") == 0) - model_init_p = 1; - else if (strcmp (name, "model_halt") == 0) - model_halt_p = 1; - else if (strcmp (name, "model_mon_info") == 0) - model_mon_info_p = 1; - else if (strcmp (name, "model_mon_info_free") == 0) - model_mon_info_free_p = 1; - } - - if (!model_create_p) { - lf_print_function_type(file, "model_data *", "INLINE_MODEL", "\n"); - lf_printf(file, "model_create(cpu *processor)\n"); - lf_printf(file, "{\n"); - lf_printf(file, " return (model_data *)0;\n"); - lf_printf(file, "}\n"); - lf_printf(file, "\n"); - } - - if (!model_init_p) { - lf_print_function_type(file, "void", "INLINE_MODEL", "\n"); - lf_printf(file, "model_init(model_data *model_ptr)\n"); - lf_printf(file, "{\n"); - lf_printf(file, "}\n"); - lf_printf(file, "\n"); - } - - if (!model_halt_p) { - lf_print_function_type(file, "void", "INLINE_MODEL", "\n"); - lf_printf(file, "model_halt(model_data *model_ptr)\n"); - lf_printf(file, "{\n"); - lf_printf(file, "}\n"); - lf_printf(file, "\n"); - } - - if (!model_mon_info_p) { - lf_print_function_type(file, "model_print *", "INLINE_MODEL", "\n"); - lf_printf(file, "model_mon_info(model_data *model_ptr)\n"); - lf_printf(file, "{\n"); - lf_printf(file, " return (model_print *)0;\n"); - lf_printf(file, "}\n"); + /* output `internal' invalid/floating-point unavailable functions + where needed */ + if ((code & generate_calls) + && (code & generate_with_icache)) { lf_printf(file, "\n"); - } - - if (!model_mon_info_free_p) { - lf_print_function_type(file, "void", "INLINE_MODEL", "\n"); - lf_printf(file, "model_mon_info_free(model_data *model_ptr,\n"); - lf_printf(file, " model_print *info_ptr)\n"); - lf_printf(file, "{\n"); - lf_printf(file, "}\n"); + lf_printf(file, "#include \"cpu.h\"\n"); + lf_printf(file, "#include \"idecode.h\"\n"); + lf_printf(file, "#include \"semantics.h\"\n"); + lf_printf(file, "#include \"icache.h\"\n"); + lf_printf(file, "#include \"support.h\"\n"); lf_printf(file, "\n"); - } - - lf_printf(file, "/* Insn functional unit info */\n"); - for(model_ptr = models; model_ptr; model_ptr = model_ptr->next) { - model_c_passed_data data; - - lf_printf(file, "static const model_time model_time_%s[] = {\n", model_ptr->name); - data.file = file; - data.model_ptr = model_ptr; - insn_table_traverse_insn(table, - (void *)&data, - model_c_insn); - - lf_printf(file, "};\n"); + insn_table_traverse_function(table, + file, NULL, + print_icache_internal_function_definition); lf_printf(file, "\n"); - lf_printf(file, "\f\n"); - } - - lf_printf(file, "#ifndef _INLINE_C_\n"); - lf_printf(file, "const model_time *const model_time_mapping[ (int)nr_models ] = {\n"); - lf_printf(file, " (const model_time *const)0,\n"); - for(model_ptr = models; model_ptr; model_ptr = model_ptr->next) { - lf_printf(file, " model_time_%s,\n", model_ptr->name); - } - lf_printf(file, "};\n"); - lf_printf(file, "#endif\n"); - lf_printf(file, "\n"); - - lf_printf(file, "\f\n"); - lf_printf(file, "/* map model enumeration into printable string */\n"); - lf_printf(file, "#ifndef _INLINE_C_\n"); - lf_printf(file, "const char *model_name[ (int)nr_models ] = {\n"); - lf_printf(file, " \"NONE\",\n"); - for (model_ptr = models; model_ptr; model_ptr = model_ptr->next) { - lf_printf(file, " \"%s\",\n", model_ptr->printable_name); + if (generate_expanded_instructions) + insn_table_traverse_tree(table, + file, cache_rules, + 1, + NULL, /* start */ + print_icache_definition, /* leaf */ + NULL, /* end */ + NULL); /* padding */ + else + insn_table_traverse_insn(table, + file, cache_rules, + print_icache_definition); + } - lf_printf(file, "};\n"); - lf_printf(file, "#endif\n"); - lf_printf(file, "\n"); - - lf_print_function_type(file, "void", "INLINE_MODEL", "\n"); - lf_printf(file, "model_set(const char *name)\n"); - lf_printf(file, "{\n"); - if (models) { - lf_printf(file, " model_enum model;\n"); - lf_printf(file, " for(model = MODEL_%s; model < nr_models; model++) {\n", models->name); - lf_printf(file, " if(strcmp(name, model_name[model]) == 0) {\n"); - lf_printf(file, " current_model = model;\n"); - lf_printf(file, " return;\n"); - lf_printf(file, " }\n"); - lf_printf(file, " }\n"); - lf_printf(file, "\n"); - lf_printf(file, " error(\"Unknown model '%%s', Models which are known are:%%s\n\",\n"); - lf_printf(file, " name,\n"); - lf_printf(file, " \""); - for(model_ptr = models; model_ptr; model_ptr = model_ptr->next) { - lf_printf(file, "\\n\\t%s", model_ptr->printable_name); - } - lf_printf(file, "\");\n"); - } else { - lf_printf(file, " error(\"No models are currently known about\");\n"); + else { + lf_print__this_file_is_empty(file); } - - lf_printf(file, "}\n"); - lf_printf(file, "\n"); - - lf_printf(file, "#endif /* _MODEL_C_ */\n"); - } + /****************************************************************/ @@ -3330,140 +307,166 @@ main(int argc, char **argv, char **envp) { + cache_table *cache_rules = NULL; + lf_file_references file_references = lf_include_references; + decode_table *decode_rules = NULL; + filter *filters = NULL; insn_table *instructions = NULL; - icache_tree *cache_fields = NULL; char *real_file_name = NULL; + int is_header = 0; int ch; if (argc == 1) { printf("Usage:\n"); printf(" igen ... ... ...\n"); printf("Config options:\n"); - printf(" -f eg -f 64 to skip 64bit instructions\n"); - printf(" -e Expand (duplicate) semantic functions\n"); - printf(" -r Generate cracking cache version\n"); + printf(" -F eg -F 64 to skip 64bit instructions\n"); + printf(" -C Include semantics in cache functions\n"); + printf(" -E Expand (duplicate) semantic functions\n"); + printf(" -I Generate cracking cache version\n"); printf(" -R Use defines to reference cache vars\n"); - printf(" -l Supress line numbering in output files\n"); - printf(" -b Set the number of bits in an instruction\n"); - printf(" -h Set the nr of the high (msb bit)\n"); + printf(" -L Supress line numbering in output files\n"); + printf(" -B Set the number of bits in an instruction\n"); + printf(" -H Set the nr of the high (msb bit)\n"); + printf(" -N Specify the max number of cpus the simulation will support\n"); + printf(" -J Use jumps instead of function calls\n"); printf("\n"); printf("Input options (ucase version also dumps loaded table):\n"); - printf(" -[Oo] \n"); - printf(" -[Kk] \n"); - printf(" -[Ii] \n"); + printf(" -o \n"); + printf(" -k \n"); + printf(" -i \n"); printf("\n"); printf("Output options:\n"); - printf(" -[Cc] output icache.h(C) invalid(c)\n"); - printf(" -[Dd] output idecode.h(D) idecode.c(d)\n"); - printf(" -[Mm] output model.h(M) model.c(M)\n"); - printf(" -[Ss] output schematic.h(S) schematic.c(s)\n"); - printf(" -[Tt] output itable.h(T) itable.c(t)\n"); + printf(" -n Specify the real name of for the next output file\n"); + printf(" -h Generate header file\n"); + printf(" -c output icache\n"); + printf(" -d output idecode\n"); + printf(" -m output model\n"); + printf(" -s output schematic\n"); + printf(" -t output itable\n"); + printf(" -f output support functions\n"); } while ((ch = getopt(argc, argv, - "leb:h:r:Rf:I:i:O:o:K:k:M:m:n:S:s:D:d:T:t:C:")) != -1) { + "F:EI:RLJCB:H:N:o:k:i:n:hc:d:m:s:t:f:")) + != -1) { fprintf(stderr, "\t-%c %s\n", ch, (optarg ? optarg : "")); switch(ch) { - case 'l': - number_lines = 0; + case 'C': + code |= generate_with_icache; + code |= generate_with_semantic_icache; + if (icache_size == 0) + icache_size = 1024; + break; + case 'L': + file_references = lf_omit_references; + break; + case 'E': + generate_expanded_instructions = 1; break; - case 'e': - idecode_expand_semantics = 1; + case 'I': + icache_size = a2i(optarg); + code |= generate_with_icache; break; - case 'r': - idecode_cache = a2i(optarg); + case 'N': + generate_smp = a2i(optarg); break; case 'R': - semantics_use_cache_struct = 1; + code |= generate_with_icache; + code |= generate_with_direct_access_icache; + if (icache_size == 0) + icache_size = 1024; break; - case 'b': - insn_size = a2i(optarg); - ASSERT(insn_size > 0 && insn_size <= max_insn_size - && (hi_bit_nr == insn_size-1 || hi_bit_nr == 0)); + case 'B': + insn_bit_size = a2i(optarg); + ASSERT(insn_bit_size > 0 && insn_bit_size <= max_insn_bit_size + && (hi_bit_nr == insn_bit_size-1 || hi_bit_nr == 0)); break; - case 'h': + case 'H': hi_bit_nr = a2i(optarg); - ASSERT(hi_bit_nr == insn_size-1 || hi_bit_nr == 0); + ASSERT(hi_bit_nr == insn_bit_size-1 || hi_bit_nr == 0); + break; + case 'F': + filters = new_filter(optarg, filters); + break; + case 'J': + code &= ~generate_calls; + code |= generate_jumps; break; - case 'f': - { - filter *new_filter = ZALLOC(filter); - new_filter->flag = strdup(optarg); - new_filter->next = filters; - filters = new_filter; - break; - } - case 'I': case 'i': - ASSERT(opcode_table != NULL); - ASSERT(cache_table != NULL); - instructions = insn_table_load_insns(optarg); + if (decode_rules == NULL || cache_rules == NULL) { + fprintf(stderr, "Must specify decode and cache tables\n"); + exit (1); + } + instructions = load_insn_table(optarg, decode_rules, filters); fprintf(stderr, "\texpanding ...\n"); insn_table_expand_insns(instructions); - fprintf(stderr, "\tcache fields ...\n"); - cache_fields = insn_table_cache_fields(instructions); - if (ch == 'I') { - dump_traverse(instructions); - dump_insn_table(instructions, 0, 1); - } break; - case 'O': case 'o': - opcode_table = load_opcode_rules(optarg); - if (ch == 'O') - dump_opcode_rules(opcode_table, 0); + decode_rules = load_decode_table(optarg, hi_bit_nr); break; - case 'K': case 'k': - cache_table = load_cache_rules(optarg); - if (ch == 'K') - dump_cache_rules(cache_table, 0); + cache_rules = load_cache_table(optarg, hi_bit_nr); break; case 'n': real_file_name = strdup(optarg); break; - case 'S': + case 'h': + is_header = 1; + break; case 's': - case 'D': case 'd': - case 'M': case 'm': - case 'T': case 't': - case 'C': + case 'f': + case 'c': { - lf *file = lf_open(optarg, real_file_name, number_lines); + lf *file = lf_open(optarg, real_file_name, file_references, + (is_header ? lf_is_h : lf_is_c), + argv[0]); + lf_print__file_start(file); ASSERT(instructions != NULL); switch (ch) { - case 'S': - gen_semantics_h(instructions, file); - break; case 's': - gen_semantics_c(instructions, file); - break; - case 'D': - gen_idecode_h(instructions, file); + if(is_header) + gen_semantics_h(instructions, file, code); + else + gen_semantics_c(instructions, cache_rules, file, code); break; case 'd': - gen_idecode_c(instructions, file); - break; - case 'M': - gen_model_h(instructions, file); + if (is_header) + gen_idecode_h(file, instructions, cache_rules); + else + gen_idecode_c(file, instructions, cache_rules); break; case 'm': - gen_model_c(instructions, file); - break; - case 'T': - gen_itable_h(instructions, file); + if (is_header) + gen_model_h(instructions, file); + else + gen_model_c(instructions, file); break; case 't': - gen_itable_c(instructions, file); + if (is_header) + gen_itable_h(instructions, file); + else + gen_itable_c(instructions, file); + break; + case 'f': + if (is_header) + gen_support_h(instructions, file); + else + gen_support_c(instructions, file); break; - case 'C': - gen_icache_h(cache_fields, file); + case 'c': + if (is_header) + gen_icache_h(instructions, file, code); + else + gen_icache_c(instructions, cache_rules, file, code); break; } + lf_print__file_finish(file); lf_close(file); + is_header = 0; } real_file_name = NULL; break; diff --git a/sim/ppc/igen.h b/sim/ppc/igen.h new file mode 100644 index 00000000000..2e3a8e038d2 --- /dev/null +++ b/sim/ppc/igen.h @@ -0,0 +1,186 @@ +/* This file is part of the program psim. + + Copyright (C) 1994,1995,1996, Andrew Cagney + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +/* What does the instruction look like - bit ordering and size */ +extern int hi_bit_nr; +extern int insn_bit_size; + + +/* generation options: */ + + +enum { + generate_with_icache = 0x1, + generate_with_semantic_icache = 0x2, + generate_with_direct_access_icache = 0x4, +}; + + +typedef enum { + + /* Transfer control to an instructions semantic code using the the + standard call/return mechanism */ + + generate_calls = 0x10, + + /* In addition, pre-decode an instructions opcode fields (entering + them into an icache) so that semantic code can avoid the need to + re-decode fields each time it is executed */ + + generate_calls_with_icache + = generate_calls | generate_with_icache, + + /* In addition, the instruction decode code includes a duplicated + copy of the instructions semantic code. This avoids the need to + perform two calls (one to decode an instructions opcode fields + and one to execute the instruction) when there is a miss of the + icache */ + + generate_calls_with_semantic_icache + = generate_calls_with_icache | generate_with_semantic_icache, + + /* In addition, the semantic function refers to icache entries + directly instead of first moving them into local variables */ + + generate_calls_with_direct_access_icache + = generate_calls_with_icache | generate_with_direct_access_icache, + + generate_calls_with_direct_access_semantic_icache + = generate_calls_with_direct_access_icache | generate_with_semantic_icache, + + + /* Transfer control to an instructions semantic code using + (computed) goto's instead of the more conventional call/return + mechanism */ + + generate_jumps = 0x20, + + /* As for generate_calls_with_icache but applies to jumping code */ + + generate_jumps_with_icache + = generate_jumps | generate_with_icache, + + /* As for generate_calls_with_semantic_icache but applies to jumping + code */ + + generate_jumps_with_semantic_icache + = generate_jumps_with_icache | generate_with_semantic_icache, + + /* As for generate_calls_with_direct_access_icache */ + + generate_jumps_with_direct_access_icache + = generate_jumps_with_icache | generate_with_direct_access_icache, + + generate_jumps_with_direct_access_semantic_icache + = generate_jumps_with_direct_access_icache | generate_with_semantic_icache, + +} igen_code; + +extern igen_code code; + + + + +extern int icache_size; + + +/* Instruction expansion? + + Should the semantic code for each instruction, when the oportunity + arrises, be expanded according to the variable opcode files that + the instruction decode process renders constant */ + +extern int generate_expanded_instructions; + + +/* SMP? + + Should the generated code include SMP support (>0) and if so, for + how many processors? */ + +extern int generate_smp; + + + + +/* Misc junk */ + + + +/* Function header definitions */ + + +/* Cache functions: */ + +#define ICACHE_FUNCTION_FORMAL \ +"cpu *processor,\n\ + instruction_word instruction,\n\ + unsigned_word cia,\n\ + idecode_cache *cache_entry" + +#define ICACHE_FUNCTION_ACTUAL "processor, instruction, cia, cache_entry" + +#define ICACHE_FUNCTION_TYPE \ +((code & generate_with_semantic_icache) \ + ? SEMANTIC_FUNCTION_TYPE \ + : "idecode_semantic *") + + +/* Semantic functions: */ + +#define SEMANTIC_FUNCTION_FORMAL \ +((code & generate_with_icache) \ + ? "cpu *processor,\n idecode_cache *cache_entry,\n unsigned_word cia" \ + : "cpu *processor,\n instruction_word instruction,\n unsigned_word cia") + +#define SEMANTIC_FUNCTION_ACTUAL \ +((code & generate_with_icache) \ + ? "processor, instruction, cia, cache_entry" \ + : "processor, instruction, cia") + +#define SEMANTIC_FUNCTION_TYPE "unsigned_word" + + + +extern void print_define_my_index +(lf *file, + table_entry *file_entry); + +extern void print_itrace +(lf *file, + table_entry *file_entry, + int idecode); + + +typedef enum { + function_name_prefix_semantics, + function_name_prefix_idecode, + function_name_prefix_itable, + function_name_prefix_goto, + function_name_prefix_icache, + function_name_prefix_none +} lf_function_name_prefixes; + +extern int print_function_name +(lf *file, + const char *basename, + insn_bits *expanded_bits, + lf_function_name_prefixes prefix); diff --git a/sim/ppc/inline.c b/sim/ppc/inline.c index b025745fcd7..aafa7b92bba 100644 --- a/sim/ppc/inline.c +++ b/sim/ppc/inline.c @@ -22,76 +22,77 @@ #ifndef _INLINE_C_ #define _INLINE_C_ -#if BITS_INLINE +#include "config.h" +#include "ppc-config.h" + +#include "inline.h" + +#if (BITS_INLINE & INCLUDE_MODULE) #include "bits.c" #endif -#if SIM_ENDIAN_INLINE +#if (SIM_ENDIAN_INLINE & INCLUDE_MODULE) #include "sim-endian.c" #endif -#if ICACHE_INLINE +#if (ICACHE_INLINE & INCLUDE_MODULE) #include "icache.c" #endif -#if CORE_INLINE +#if (CORE_INLINE & INCLUDE_MODULE) #include "corefile.c" #endif -#if VM_INLINE +#if (VM_INLINE & INCLUDE_MODULE) #include "vm.c" #endif -#if CPU_INLINE -#include "cpu.c" -#endif - -#if EVENTS_INLINE +#if (EVENTS_INLINE & INCLUDE_MODULE) #include "events.c" #endif -#if MODEL_INLINE +#if (MODEL_INLINE & INCLUDE_MODULE) #include "model.c" #endif -#if OPTIONS_INLINE +#if (OPTIONS_INLINE & INCLUDE_MODULE) #include "options.c" #endif -#if FUNCTION_UNIT_INLINE -#include "function_unit.c" -#endif - -#if MON_INLINE +#if (MON_INLINE & INCLUDE_MODULE) #include "mon.c" #endif -#if REGISTERS_INLINE +#if (REGISTERS_INLINE & INCLUDE_MODULE) #include "registers.c" #endif -#if INTERRUPTS_INLINE +#if (INTERRUPTS_INLINE & INCLUDE_MODULE) #include "interrupts.c" #endif -#if DEVICE_TREE_INLINE -#include "device_tree.c" +#if (DEVICE_INLINE & INCLUDE_MODULE) +#include "device.c" #endif -#if DEVICES_INLINE -#include "devices.c" -#endif - -#if SPREG_INLINE +#if (SPREG_INLINE & INCLUDE_MODULE) #include "spreg.c" #endif -#if SEMANTICS_INLINE +#if (SEMANTICS_INLINE & INCLUDE_MODULE) #include "semantics.c" #endif -#if IDECODE_INLINE +#if (IDECODE_INLINE & INCLUDE_MODULE) #include "idecode.c" #endif +#if (SUPPORT_INLINE & INCLUDE_MODULE) +#include "support.c" +#endif + +#if (OS_EMUL_INLINE & INCLUDE_MODULE) +#include "os_emul.c" +#endif + #endif diff --git a/sim/ppc/inline.h b/sim/ppc/inline.h index c6112f3a78c..bd1e95f66c9 100644 --- a/sim/ppc/inline.h +++ b/sim/ppc/inline.h @@ -22,154 +22,447 @@ #ifndef _INLINE_H_ #define _INLINE_H_ -#if SIM_ENDIAN_INLINE -#if SIM_ENDIAN_INLINE == 2 -#define INLINE_SIM_ENDIAN static INLINE + +#define STATIC(TYPE) static TYPE + + +/* sim_endian is always inlined */ + +#if !defined(_SIM_ENDIAN_C_) && (SIM_ENDIAN_INLINE & INCLUDE_MODULE) +# if (SIM_ENDIAN_INLINE & INLINE_MODULE) +# define INLINE_SIM_ENDIAN(TYPE) static INLINE TYPE UNUSED +# define EXTERN_SIM_ENDIAN(TYPE) static TYPE UNUSED +# else +# define INLINE_SIM_ENDIAN(TYPE) static TYPE UNUSED +# define EXTERN_SIM_ENDIAN(TYPE) static TYPE UNUSED +# endif #else -#define INLINE_SIM_ENDIAN static +# define INLINE_SIM_ENDIAN(TYPE) TYPE +# define EXTERN_SIM_ENDIAN(TYPE) TYPE #endif + +#if (SIM_ENDIAN_INLINE & INLINE_LOCALS) +# define STATIC_INLINE_SIM_ENDIAN(TYPE) static INLINE TYPE +#else +# define STATIC_INLINE_SIM_ENDIAN(TYPE) static TYPE #endif -#if ICACHE_INLINE -#if ICACHE_INLINE == 2 -#define INLINE_ICACHE static INLINE + +/* bits is always inlined */ + +#if !defined(_BITS_C_) && (BITS_INLINE & INCLUDE_MODULE) +# if (BITS_INLINE & INLINE_MODULE) +# define INLINE_BITS(TYPE) static INLINE TYPE UNUSED +# define EXTERN_BITS(TYPE) static TYPE UNUSED +# else +# define INLINE_BITS(TYPE) static TYPE UNUSED +# define EXTERN_BITS(TYPE) static TYPE UNUSED +# endif #else -#define INLINE_ICACHE static +# define INLINE_BITS(TYPE) TYPE +# define EXTERN_BITS(TYPE) TYPE #endif + +#if (BITS_INLINE & INLINE_LOCALS) +# define STATIC_INLINE_BITS(TYPE) static INLINE TYPE +#else +# define STATIC_INLINE_BITS(TYPE) static TYPE #endif -#if CORE_INLINE -#if CORE_INLINE == 2 -#define INLINE_CORE static INLINE + +/* core is inlined with inline.c */ + +#if defined(_INLINE_C_) && !defined(_CORE_C_) && (CORE_INLINE & INCLUDE_MODULE) +# if (CORE_INLINE & INLINE_MODULE) +# define INLINE_CORE(TYPE) static INLINE TYPE UNUSED +# define EXTERN_CORE(TYPE) static TYPE UNUSED #else -#define INLINE_CORE static +# define INLINE_CORE(TYPE) static TYPE UNUSED +# define EXTERN_CORE(TYPE) static TYPE UNUSED #endif +#else +# define INLINE_CORE(TYPE) TYPE +# define EXTERN_CORE(TYPE) TYPE +#endif + +#if (CORE_INLINE & INLINE_LOCALS) +# define STATIC_INLINE_CORE(TYPE) static INLINE TYPE +#else +# define STATIC_INLINE_CORE(TYPE) static TYPE #endif -#if VM_INLINE -#if VM_INLINE == 2 -#define INLINE_VM static INLINE + +/* vm is inlined with inline.c */ + +#if defined(_INLINE_C_) && !defined(_VM_C_) && (VM_INLINE & INCLUDE_MODULE) +# if (VM_INLINE & INLINE_MODULE) +# define INLINE_VM(TYPE) static INLINE TYPE UNUSED +# define EXTERN_VM(TYPE) static TYPE UNUSED +#else +# define INLINE_VM(TYPE) static TYPE UNUSED +# define EXTERN_VM(TYPE) static TYPE UNUSED +#endif #else -#define INLINE_VM static +# define INLINE_VM(TYPE) TYPE +# define EXTERN_VM(TYPE) TYPE #endif + +#if (VM_INLINE & INLINE_LOCALS) +# define STATIC_INLINE_VM(TYPE) static INLINE TYPE +#else +# define STATIC_INLINE_VM(TYPE) static TYPE #endif -#if CPU_INLINE -#if CPU_INLINE == 2 -#define INLINE_CPU static INLINE + +/* cpu is always inlined */ + +#if !defined(_CPU_C_) && (CPU_INLINE & INCLUDE_MODULE) +# if (CPU_INLINE & INLINE_MODULE) +# define INLINE_CPU(TYPE) static INLINE TYPE UNUSED +# define EXTERN_CPU(TYPE) static TYPE UNUSED #else -#define INLINE_CPU static +# define INLINE_CPU(TYPE) static TYPE UNUSED +# define EXTERN_CPU(TYPE) static TYPE UNUSED #endif +#else +# define INLINE_CPU(TYPE) TYPE +# define EXTERN_CPU(TYPE) TYPE +#endif + +#if (CPU_INLINE & INLINE_LOCALS) +# define STATIC_INLINE_CPU(TYPE) static INLINE TYPE +#else +# define STATIC_INLINE_CPU(TYPE) static TYPE #endif -#if MODEL_INLINE -#if MODEL_INLINE == 2 -#define INLINE_MODEL static INLINE + +/* model is inlined with inline.c */ + +#if defined(_INLINE_C_) && !defined(_MODEL_C_) && (MODEL_INLINE & INCLUDE_MODULE) +# if (MODEL_INLINE & INLINE_MODULE) +# define INLINE_MODEL(TYPE) static INLINE TYPE UNUSED +# define EXTERN_MODEL(TYPE) static TYPE UNUSED #else -#define INLINE_MODEL static +# define INLINE_MODEL(TYPE) static TYPE UNUSED +# define EXTERN_MODEL(TYPE) static TYPE UNUSED #endif -#define STATIC_MODEL static -#define EXTERN_MODEL static +#else +# define INLINE_MODEL(TYPE) TYPE +# define EXTERN_MODEL(TYPE) TYPE #endif -#if BITS_INLINE -#if BITS_INLINE == 2 -#define INLINE_BITS static INLINE +#if (MODEL_INLINE & INLINE_LOCALS) +# define STATIC_INLINE_MODEL(TYPE) static INLINE TYPE #else -#define INLINE_BITS static +# define STATIC_INLINE_MODEL(TYPE) static TYPE #endif + + +/* events is inlined with inline.c */ + +#if defined(_INLINE_C_) && !defined(_EVENTS_C_) && (EVENTS_INLINE & INCLUDE_MODULE) +# if (EVENTS_INLINE & INLINE_MODULE) +# define INLINE_EVENTS(TYPE) static INLINE TYPE UNUSED +# define EXTERN_EVENTS(TYPE) static TYPE UNUSED +#else +# define INLINE_EVENTS(TYPE) static TYPE UNUSED +# define EXTERN_EVENTS(TYPE) static TYPE UNUSED +#endif +#else +# define INLINE_EVENTS(TYPE) TYPE +# define EXTERN_EVENTS(TYPE) TYPE +#endif + +#if (EVENTS_INLINE & INLINE_LOCALS) +# define STATIC_INLINE_EVENTS(TYPE) static INLINE TYPE +#else +# define STATIC_INLINE_EVENTS(TYPE) static TYPE #endif -#if EVENTS_INLINE -#if EVENTS_INLINE == 2 -#define INLINE_EVENTS static INLINE + +/* mon is inlined with inline.c */ + +#if defined(_INLINE_C_) && !defined(_MON_C_) && (MON_INLINE & INCLUDE_MODULE) +# if (MON_INLINE & INLINE_MODULE) +# define INLINE_MON(TYPE) static INLINE TYPE UNUSED +# define EXTERN_MON(TYPE) static TYPE UNUSED #else -#define INLINE_EVENTS static +# define INLINE_MON(TYPE) static TYPE UNUSED +# define EXTERN_MON(TYPE) static TYPE UNUSED #endif +#else +# define INLINE_MON(TYPE) TYPE +# define EXTERN_MON(TYPE) TYPE #endif -#if MON_INLINE -#if MON_INLINE == 2 -#define INLINE_MON static INLINE +#if (MON_INLINE & INLINE_LOCALS) +# define STATIC_INLINE_MON(TYPE) static INLINE TYPE #else -#define INLINE_MON static +# define STATIC_INLINE_MON(TYPE) static TYPE #endif + + +/* registers is inlined with inline.c */ + +#if defined(_INLINE_C_) && !defined(_REGISTERS_C_) && (REGISTERS_INLINE & INCLUDE_MODULE) +# if (REGISTERS_INLINE & INLINE_MODULE) +# define INLINE_REGISTERS(TYPE) static INLINE TYPE UNUSED +# define EXTERN_REGISTERS(TYPE) static TYPE UNUSED +#else +# define INLINE_REGISTERS(TYPE) static TYPE UNUSED +# define EXTERN_REGISTERS(TYPE) static TYPE UNUSED +#endif +#else +# define INLINE_REGISTERS(TYPE) TYPE +# define EXTERN_REGISTERS(TYPE) TYPE +#endif + +#if (REGISTERS_INLINE & INLINE_LOCALS) +# define STATIC_INLINE_REGISTERS(TYPE) static INLINE TYPE +#else +# define STATIC_INLINE_REGISTERS(TYPE) static TYPE #endif -#if REGISTERS_INLINE -#if REGISTERS_INLINE == 2 -#define INLINE_REGISTERS static INLINE + +/* interrupts is inlined with inline.c */ + +#if defined(_INLINE_C_) && !defined(_INTERRUPTS_C_) && (INTERRUPTS_INLINE & INCLUDE_MODULE) +# if (INTERRUPTS_INLINE & INLINE_MODULE) +# define INLINE_INTERRUPTS(TYPE) static INLINE TYPE UNUSED +# define EXTERN_INTERRUPTS(TYPE) static TYPE UNUSED #else -#define INLINE_REGISTERS static +# define INLINE_INTERRUPTS(TYPE) static TYPE UNUSED +# define EXTERN_INTERRUPTS(TYPE) static TYPE UNUSED #endif +#else +# define INLINE_INTERRUPTS(TYPE) TYPE +# define EXTERN_INTERRUPTS(TYPE) TYPE #endif -#if INTERRUPTS_INLINE -#if INTERRUPTS_INLINE == 2 -#define INLINE_INTERRUPTS static INLINE +#if (INTERRUPTS_INLINE & INLINE_LOCALS) +# define STATIC_INLINE_INTERRUPTS(TYPE) static INLINE TYPE #else -#define INLINE_INTERRUPTS static +# define STATIC_INLINE_INTERRUPTS(TYPE) static TYPE #endif + + +/* device is inlined with inline.c */ + +#if defined(_INLINE_C_) && !defined(_DEVICE_C_) && (DEVICE_INLINE & INCLUDE_MODULE) +# if (DEVICE_INLINE & INLINE_MODULE) +# define INLINE_DEVICE(TYPE) static INLINE TYPE UNUSED +# define EXTERN_DEVICE(TYPE) static TYPE UNUSED +#else +# define INLINE_DEVICE(TYPE) static TYPE UNUSED +# define EXTERN_DEVICE(TYPE) static TYPE UNUSED +#endif +#else +# define INLINE_DEVICE(TYPE) TYPE +# define EXTERN_DEVICE(TYPE) TYPE #endif -#if DEVICE_TREE_INLINE -#if DEVICE_TREE_INLINE == 2 -#define INLINE_DEVICE_TREE static INLINE +#if (DEVICE_INLINE & INLINE_LOCALS) +# define STATIC_INLINE_DEVICE(TYPE) static INLINE TYPE #else -#define INLINE_DEVICE_TREE static +# define STATIC_INLINE_DEVICE(TYPE) static TYPE #endif + + +/* spreg is inlined with inline.c */ + +#if defined(_INLINE_C_) && !defined(_SPREG_C_) && (SPREG_INLINE & INCLUDE_MODULE) +# if (SPREG_INLINE & INLINE_MODULE) +# define INLINE_SPREG(TYPE) static INLINE TYPE UNUSED +# define EXTERN_SPREG(TYPE) static TYPE UNUSED +#else +# define INLINE_SPREG(TYPE) static TYPE UNUSED +# define EXTERN_SPREG(TYPE) static TYPE UNUSED +#endif +#else +# define INLINE_SPREG(TYPE) TYPE +# define EXTERN_SPREG(TYPE) TYPE +#endif + +#if (SPREG_INLINE & INLINE_LOCALS) +# define STATIC_INLINE_SPREG(TYPE) static INLINE TYPE +#else +# define STATIC_INLINE_SPREG(TYPE) static TYPE +#endif + + +/* semantics is inlined with inline.c */ + +#if defined(_INLINE_C_) && !defined(_SEMANTICS_C_) && (SEMANTICS_INLINE & INCLUDE_MODULE) +# if (SEMANTICS_INLINE & INLINE_MODULE) +# define INLINE_SEMANTICS(TYPE) static INLINE TYPE UNUSED +# define EXTERN_SEMANTICS(TYPE) static TYPE UNUSED REGPARM +#else +# define INLINE_SEMANTICS(TYPE) static TYPE UNUSED REGPARM +# define EXTERN_SEMANTICS(TYPE) static TYPE UNUSED REGPARM +#endif +#else +# define INLINE_SEMANTICS(TYPE) TYPE REGPARM +# define EXTERN_SEMANTICS(TYPE) TYPE REGPARM #endif -#if DEVICES_INLINE -#if DEVICES_INLINE == 2 -#define INLINE_DEVICES static INLINE +#if (SEMANTICS_INLINE & INLINE_LOCALS) +# define STATIC_INLINE_SEMANTICS(TYPE) static INLINE TYPE +#else +# define STATIC_INLINE_SEMANTICS(TYPE) static TYPE REGPARM +#endif + + +/* idecode is actually not inlined */ + +#if defined(_INLINE_C_) && !defined(_IDECODE_C_) && (IDECODE_INLINE & INCLUDE_MODULE) +# if (IDECODE_INLINE & INLINE_MODULE) +# define INLINE_IDECODE(TYPE) static INLINE TYPE UNUSED +# define EXTERN_IDECODE(TYPE) static TYPE UNUSED REGPARM +#else +# define INLINE_IDECODE(TYPE) static TYPE UNUSED REGPARM +# define EXTERN_IDECODE(TYPE) static TYPE UNUSED REGPARM +#endif +#else +# define INLINE_IDECODE(TYPE) TYPE REGPARM +# define EXTERN_IDECODE(TYPE) TYPE REGPARM +#endif + +#if (IDECODE_INLINE & INLINE_LOCALS) +# define STATIC_INLINE_IDECODE(TYPE) static INLINE TYPE +#else +# define STATIC_INLINE_IDECODE(TYPE) static TYPE REGPARM +#endif + + +/* icache is inlined with inline.c */ + +#if defined(_INLINE_C_) && !defined(_ICACHE_C_) && (ICACHE_INLINE & INCLUDE_MODULE) +# if (ICACHE_INLINE & INLINE_MODULE) +# define INLINE_ICACHE(TYPE) static INLINE TYPE UNUSED +# define EXTERN_ICACHE(TYPE) static TYPE UNUSED REGPARM +#else +# define INLINE_ICACHE(TYPE) static TYPE UNUSED REGPARM +# define EXTERN_ICACHE(TYPE) static TYPE UNUSED REGPARM +#endif #else -#define INLINE_DEVICES static +# define INLINE_ICACHE(TYPE) TYPE REGPARM +# define EXTERN_ICACHE(TYPE) TYPE REGPARM #endif -#define STATIC_DEVICES static + +#if (ICACHE_INLINE & INLINE_LOCALS) +# define STATIC_INLINE_ICACHE(TYPE) static INLINE TYPE +#else +# define STATIC_INLINE_ICACHE(TYPE) static TYPE REGPARM #endif -#if SPREG_INLINE -#if SPREG_INLINE == 2 -#define INLINE_SPREG static INLINE + +/* support is inlined with inline.c */ + +#if defined(_INLINE_C_) && !defined(_SUPPORT_C_) && (SUPPORT_INLINE & INCLUDE_MODULE) +# if (SUPPORT_INLINE & INLINE_MODULE) +# define INLINE_SUPPORT(TYPE) static INLINE TYPE UNUSED +# define EXTERN_SUPPORT(TYPE) static TYPE UNUSED REGPARM #else -#define INLINE_SPREG static +# define INLINE_SUPPORT(TYPE) static TYPE UNUSED REGPARM +# define EXTERN_SUPPORT(TYPE) static TYPE UNUSED REGPARM #endif +#else +# define INLINE_SUPPORT(TYPE) TYPE REGPARM +# define EXTERN_SUPPORT(TYPE) TYPE REGPARM +#endif + +#if (SUPPORT_INLINE & INLINE_LOCALS) +# define STATIC_INLINE_SUPPORT(TYPE) static INLINE TYPE +#else +# define STATIC_INLINE_SUPPORT(TYPE) static TYPE REGPARM #endif -#if SEMANTICS_INLINE && !defined(_SEMANTICS_C_) -#if SEMANTICS_INLINE == 2 -#define INLINE_SEMANTICS static INLINE + +/* options is inlined with inline.c */ + +#if defined(_INLINE_C_) && !defined(_OPTIONS_C_) && (OPTIONS_INLINE & INCLUDE_MODULE) +# if (OPTIONS_INLINE & INLINE_MODULE) +# define INLINE_OPTIONS(TYPE) static INLINE TYPE UNUSED +# define EXTERN_OPTIONS(TYPE) static TYPE UNUSED #else -#define INLINE_SEMANTICS static +# define INLINE_OPTIONS(TYPE) static TYPE UNUSED +# define EXTERN_OPTIONS(TYPE) static TYPE UNUSED #endif -#define STATIC_SEMANTICS static +#else +# define INLINE_OPTIONS(TYPE) TYPE +# define EXTERN_OPTIONS(TYPE) TYPE #endif -#if IDECODE_INLINE -#if IDECODE_INLINE == 2 -#define INLINE_IDECODE static INLINE +#if (OPTIONS_INLINE & INLINE_LOCALS) +# define STATIC_INLINE_OPTIONS(TYPE) static INLINE TYPE #else -#define INLINE_IDECODE static +# define STATIC_INLINE_OPTIONS(TYPE) static TYPE #endif -#define STATIC_IDECODE static + + +/* os_emul is inlined with inline.c */ + +#if defined(_INLINE_C_) && !defined(_OS_EMUL_C_) && (OS_EMUL_INLINE & INCLUDE_MODULE) +# if (OS_EMUL_INLINE & INLINE_MODULE) +# define INLINE_OS_EMUL(TYPE) static INLINE TYPE UNUSED +# define EXTERN_OS_EMUL(TYPE) static TYPE UNUSED +#else +# define INLINE_OS_EMUL(TYPE) static TYPE UNUSED +# define EXTERN_OS_EMUL(TYPE) static TYPE UNUSED +#endif +#else +# define INLINE_OS_EMUL(TYPE) TYPE +# define EXTERN_OS_EMUL(TYPE) TYPE +#endif + +#if (OS_EMUL_INLINE & INLINE_LOCALS) +# define STATIC_INLINE_OS_EMUL(TYPE) static INLINE TYPE +#else +# define STATIC_INLINE_OS_EMUL(TYPE) static TYPE #endif -#if FUNCTION_UNIT_INLINE -#if FUNCTION_UNIT_INLINE == 2 -#define INLINE_FUNCTION_UNIT static INLINE + +/* psim is actually not inlined */ + +#if defined(_INLINE_C_) && !defined(_PSIM_C_) && (PSIM_INLINE & INCLUDE_MODULE) +# if (PSIM_INLINE & INLINE_MODULE) +# define INLINE_PSIM(TYPE) static INLINE TYPE UNUSED +# define EXTERN_PSIM(TYPE) static TYPE UNUSED #else -#define INLINE_FUNCTION_UNIT static +# define INLINE_PSIM(TYPE) static TYPE UNUSED +# define EXTERN_PSIM(TYPE) static TYPE UNUSED #endif +#else +# define INLINE_PSIM(TYPE) TYPE +# define EXTERN_PSIM(TYPE) TYPE #endif -#if OPTIONS_INLINE -#if OPTIONS_INLINE == 2 -#define INLINE_OPTIONS static INLINE +#if (PSIM_INLINE & INLINE_LOCALS) +# define STATIC_INLINE_PSIM(TYPE) static INLINE TYPE #else -#define INLINE_OPTIONS static +# define STATIC_INLINE_PSIM(TYPE) static TYPE #endif + + +/* cap is inlined with inline.c */ + +#if defined(_INLINE_C_) && !defined(_CAP_C_) && (CAP_INLINE & INCLUDE_MODULE) +# if (CAP_INLINE & INLINE_MODULE) +# define INLINE_CAP(TYPE) static INLINE TYPE UNUSED +# define EXTERN_CAP(TYPE) static TYPE UNUSED +#else +# define INLINE_CAP(TYPE) static TYPE UNUSED +# define EXTERN_CAP(TYPE) static TYPE UNUSED +#endif +#else +# define INLINE_CAP(TYPE) TYPE +# define EXTERN_CAP(TYPE) TYPE #endif +#if (CAP_INLINE & INLINE_LOCALS) +# define STATIC_INLINE_CAP(TYPE) static INLINE TYPE +#else +# define STATIC_INLINE_CAP(TYPE) static TYPE +#endif #endif diff --git a/sim/ppc/ld-cache.c b/sim/ppc/ld-cache.c new file mode 100644 index 00000000000..134339a083d --- /dev/null +++ b/sim/ppc/ld-cache.c @@ -0,0 +1,114 @@ +/* This file is part of the program psim. + + Copyright (C) 1994,1995,1996, Andrew Cagney + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#include "misc.h" +#include "lf.h" +#include "table.h" +#include "ld-cache.h" + +#ifndef NULL +#define NULL 0 +#endif + + +enum { + ca_type, + ca_old_name, + ca_new_name, + ca_type_def, + ca_expression, + nr_cache_rule_fields, +}; + +static const name_map cache_type_map[] = { + { "cache", cache_value }, + { "compute", compute_value }, + { NULL, 0 }, +}; + + +cache_table * +load_cache_table(char *file_name, + int hi_bit_nr) +{ + table *file = table_open(file_name, nr_cache_rule_fields, 0); + table_entry *entry; + cache_table *table = NULL; + cache_table **curr_rule = &table; + while ((entry = table_entry_read(file)) != NULL) { + cache_table *new_rule = ZALLOC(cache_table); + new_rule->type = name2i(entry->fields[ca_type], cache_type_map); + new_rule->old_name = entry->fields[ca_old_name]; + new_rule->new_name = entry->fields[ca_new_name]; + new_rule->type_def = (strlen(entry->fields[ca_type_def]) + ? entry->fields[ca_type_def] + : NULL); + new_rule->expression = (strlen(entry->fields[ca_expression]) > 0 + ? entry->fields[ca_expression] + : NULL); + new_rule->file_entry = entry; + *curr_rule = new_rule; + curr_rule = &new_rule->next; + } + return table; +} + + + +#ifdef MAIN + +static void +dump_cache_rule(cache_table* rule, + int indent) +{ + dumpf(indent, "((cache_table*)0x%x\n", rule); + dumpf(indent, " (type %s)\n", i2name(rule->type, cache_type_map)); + dumpf(indent, " (old_name \"%s\")\n", rule->old_name); + dumpf(indent, " (new_name \"%s\")\n", rule->new_name); + dumpf(indent, " (type-def \"%s\")\n", rule->type_def); + dumpf(indent, " (expression \"%s\")\n", rule->expression); + dumpf(indent, " (next 0x%x)\n", rule->next); + dumpf(indent, " )\n"); +} + + +static void +dump_cache_rules(cache_table* rule, + int indent) +{ + while (rule) { + dump_cache_rule(rule, indent); + rule = rule->next; + } +} + + +int +main(int argc, char **argv) +{ + cache_table *rules; + if (argc != 3) + error("Usage: cache \n"); + rules = load_cache_table(argv[1], a2i(argv[2])); + dump_cache_rules(rules, 0); + return 0; +} +#endif diff --git a/sim/ppc/ld-cache.h b/sim/ppc/ld-cache.h new file mode 100644 index 00000000000..06d05ffac6f --- /dev/null +++ b/sim/ppc/ld-cache.h @@ -0,0 +1,75 @@ +/* This file is part of the program psim. + + Copyright (C) 1994,1995,1996, Andrew Cagney + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + +/* Instruction unpacking: + + Once the instruction has been decoded, the register (and other) + fields within the instruction need to be extracted. + + The table that follows determines how each field should be treated. + Importantly it considers the case where the extracted field is to + be used immediatly or stored in an instruction cache. + + + + Zero marks the end of the table. More importantly 1. indicates + that the entry is valid and can be cached. 2. indicates that that + the entry is valid but can not be cached. + + + + The field name as given in the instruction spec. + + + + A name for once it has been extracted from the + instructioin (and possibly stored in the instruction cache). + + + + String specifying the storage type for (the extracted + field>. + + + + Specifies how to get from . If null, old and + new name had better be the same. */ + + +typedef enum { + cache_value, + compute_value, +} cache_rule_type; + +typedef struct _cache_table cache_table; +struct _cache_table { + cache_rule_type type; + char *old_name; + char *new_name; + char *type_def; + char *expression; + table_entry *file_entry; + cache_table *next; +}; + + +extern cache_table *load_cache_table +(char *file_name, + int hi_bit_nr); diff --git a/sim/ppc/ld-decode.h b/sim/ppc/ld-decode.h new file mode 100644 index 00000000000..30992ee3c54 --- /dev/null +++ b/sim/ppc/ld-decode.h @@ -0,0 +1,139 @@ +/* This file is part of the program psim. + + Copyright (C) 1994,1995,1996, Andrew Cagney + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + +/* Instruction decode table: + + ::::::... + + + + Ignore the below: + + + The instruction decode table contains rules that dictate how igen + is going to firstly break down the opcode table and secondly + + The table that follows is used by gen to construct a decision tree + that can identify each possible instruction. Gen then outputs this + decision tree as (according to config) a table or switch statement + as the function idecode. + + In parallel to this, as mentioned above, WITH_EXPANDED_SEMANTICS + determines of the semantic functions themselves should be expanded + in a similar way. + + + + + Range of bits (within the instruction) that should be searched for + an instruction field. Within such ranges, gen looks for opcodes + (constants), registers (strings) and reserved bits (slash) and + according to the rules that follows includes or excludes them from + a possible instruction field. + + + + + If an instruction field was found, enlarge the field size so that + it is forced to at least include bits starting from + (). To stop this occuring, use = + + 1 and = - 1. + + + + Treat `/' fields as a constant instead of variable when looking for + an instruction field. + + + + Treat any contained register (string) fields as constant when + determining the instruction field. For the instruction decode (and + controled by IDECODE_EXPAND_SEMANTICS) this forces the expansion of + what would otherwize be non constant bits of an instruction. + + + + Should this table be expanded using a switch statement (val 1) and + if so, should it be padded with entries so as to force the compiler + to generate a jump table (val 2). Or a branch table (val 3). + + + + + + + Special rule to fine tune how specific (or groups) of instructions + are expanded. The applicability of the rule is determined by + + != 0 && (instruction> & ) == + + Where is obtained by looking only at constant fields + with in an instructions spec. When determining an expansion, the + rule is only considered when a node contains a single instruction. + can be any of: + + 0: for this instruction, expand by earlier rules + 1: expand bits .. only + 2: boolean expansion of only zero/non-zero cases + 3: boolean expansion of equality of special constant + + */ + + +typedef enum { + normal_decode_rule, + expand_forced_rule, + boolean_rule, + nr_decode_rules +} decode_special_type; + +typedef enum { + array_gen, + switch_gen, + padded_switch_gen, + goto_gen, + nr_decode_gen_types, +} decode_gen_type; + + +typedef struct _decode_table decode_table; +struct _decode_table { + decode_special_type type; + decode_gen_type gen; + int first; + int last; + int force_first; + int force_last; + int force_slash; + char *force_expansion; + unsigned special_mask; + unsigned special_value; + unsigned special_constant; + decode_table *next; +}; + + +extern decode_table *load_decode_table +(char *file_name, + int hi_bit_nr); + +extern void dump_decode_rule +(decode_table *rule, + int indent); diff --git a/sim/ppc/ld-insn.c b/sim/ppc/ld-insn.c new file mode 100644 index 00000000000..a190d85a83f --- /dev/null +++ b/sim/ppc/ld-insn.c @@ -0,0 +1,925 @@ +/* This file is part of the program psim. + + Copyright (C) 1994,1995,1996, Andrew Cagney + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#include "misc.h" +#include "lf.h" +#include "table.h" +#include "filter.h" +#include "ld-decode.h" +#include "ld-cache.h" +#include "ld-insn.h" + +#include "igen.h" + +static void +update_depth(insn_table *entry, + lf *file, + void *data, + insn *instruction, + int depth) +{ + int *max_depth = (int*)data; + if (*max_depth < depth) + *max_depth = depth; +} + + +int +insn_table_depth(insn_table *table) +{ + int depth = 0; + insn_table_traverse_tree(table, + NULL, + &depth, + 1, + NULL, /*start*/ + update_depth, + NULL, /*end*/ + NULL); /*padding*/ + return depth; +} + + +static insn_fields * +parse_insn_format(table_entry *entry, + char *format) +{ + char *chp; + insn_fields *fields = ZALLOC(insn_fields); + + /* create a leading sentinal */ + fields->first = ZALLOC(insn_field); + fields->first->first = -1; + fields->first->last = -1; + fields->first->width = 0; + + /* and a trailing sentinal */ + fields->last = ZALLOC(insn_field); + fields->last->first = insn_bit_size; + fields->last->last = insn_bit_size; + fields->last->width = 0; + + /* link them together */ + fields->first->next = fields->last; + fields->last->prev = fields->first; + + /* now work through the formats */ + chp = format; + + while (*chp != '\0') { + char *start_pos; + char *start_val; + int strlen_val; + int strlen_pos; + insn_field *new_field; + + /* sanity check */ + if (!isdigit(*chp)) { + error("%s:%d: missing position field at `%s'\n", + entry->file_name, entry->line_nr, chp); + } + + /* break out the bit position */ + start_pos = chp; + while (isdigit(*chp)) + chp++; + strlen_pos = chp - start_pos; + if (*chp == '.' && strlen_pos > 0) + chp++; + else { + error("%s:%d: missing field value at %s\n", + entry->file_name, entry->line_nr, chp); + break; + } + + /* break out the value */ + start_val = chp; + while ((*start_val == '/' && *chp == '/') + || (isdigit(*start_val) && isdigit(*chp)) + || (isalpha(*start_val) && (isalnum(*chp) || *chp == '_'))) + chp++; + strlen_val = chp - start_val; + if (*chp == ',') + chp++; + else if (*chp != '\0' || strlen_val == 0) { + error("%s:%d: missing field terminator at %s\n", + entry->file_name, entry->line_nr, chp); + break; + } + + /* create a new field and insert it */ + new_field = ZALLOC(insn_field); + new_field->next = fields->last; + new_field->prev = fields->last->prev; + new_field->next->prev = new_field; + new_field->prev->next = new_field; + + /* the value */ + new_field->val_string = (char*)zalloc(strlen_val+1); + strncpy(new_field->val_string, start_val, strlen_val); + if (isdigit(*new_field->val_string)) { + new_field->val_int = a2i(new_field->val_string); + new_field->is_int = 1; + } + else if (new_field->val_string[0] == '/') { + new_field->is_slash = 1; + } + else { + new_field->is_string = 1; + } + + /* the pos */ + new_field->pos_string = (char*)zalloc(strlen_pos+1); + strncpy(new_field->pos_string, start_pos, strlen_pos); + new_field->first = target_a2i(hi_bit_nr, new_field->pos_string); + new_field->last = new_field->next->first - 1; /* guess */ + new_field->width = new_field->last - new_field->first + 1; /* guess */ + new_field->prev->last = new_field->first-1; /*fix*/ + new_field->prev->width = new_field->first - new_field->prev->first; /*fix*/ + } + + /* fiddle first/last so that the sentinals `disapear' */ + ASSERT(fields->first->last < 0); + ASSERT(fields->last->first >= insn_bit_size); + fields->first = fields->first->next; + fields->last = fields->last->prev; + + /* now go over this again, pointing each bit position at a field + record */ + { + int i; + insn_field *field; + field = fields->first; + for (i = 0; i < insn_bit_size; i++) { + while (field->last < i) + field = field->next; + fields->bits[i] = field; + } + } + + /* go over each of the fields, and compute a `value' for the insn */ + { + insn_field *field; + fields->value = 0; + for (field = fields->first; + field->last < insn_bit_size; + field = field->next) { + fields->value <<= field->width; + if (field->is_int) + fields->value |= field->val_int; + } + } + return fields; +} + + +static void +model_table_insert(insn_table *table, + table_entry *file_entry) +{ + int len; + + /* create a new model */ + model *new_model = ZALLOC(model); + + new_model->name = file_entry->fields[model_identifer]; + new_model->printable_name = file_entry->fields[model_name]; + new_model->insn_default = file_entry->fields[model_default]; + + while (*new_model->insn_default && isspace(*new_model->insn_default)) + new_model->insn_default++; + + len = strlen(new_model->insn_default); + if (max_model_fields_len < len) + max_model_fields_len = len; + + /* append it to the end of the model list */ + if (last_model) + last_model->next = new_model; + else + models = new_model; + last_model = new_model; +} + +static void +model_table_insert_specific(insn_table *table, + table_entry *file_entry, + insn **start_ptr, + insn **end_ptr) +{ + insn *ptr = ZALLOC(insn); + ptr->file_entry = file_entry; + if (*end_ptr) + (*end_ptr)->next = ptr; + else + (*start_ptr) = ptr; + (*end_ptr) = ptr; +} + + +static void +insn_table_insert_function(insn_table *table, + table_entry *file_entry) +{ + /* create a new function */ + insn *new_function = ZALLOC(insn); + new_function->file_entry = file_entry; + + /* append it to the end of the function list */ + if (table->last_function) + table->last_function->next = new_function; + else + table->functions = new_function; + table->last_function = new_function; +} + +extern void +insn_table_insert_insn(insn_table *table, + table_entry *file_entry, + insn_fields *fields) +{ + insn **ptr_to_cur_insn = &table->insns; + insn *cur_insn = *ptr_to_cur_insn; + table_model_entry *insn_model_ptr; + model *model_ptr; + + /* create a new instruction */ + insn *new_insn = ZALLOC(insn); + new_insn->file_entry = file_entry; + new_insn->fields = fields; + + /* Check out any model information returned to make sure the model + is correct. */ + for(insn_model_ptr = file_entry->model_first; insn_model_ptr; insn_model_ptr = insn_model_ptr->next) { + char *name = insn_model_ptr->fields[insn_model_name]; + int len = strlen (insn_model_ptr->fields[insn_model_fields]); + + while (len > 0 && isspace(*insn_model_ptr->fields[insn_model_fields])) { + len--; + insn_model_ptr->fields[insn_model_fields]++; + } + + if (max_model_fields_len < len) + max_model_fields_len = len; + + for(model_ptr = models; model_ptr; model_ptr = model_ptr->next) { + if (strcmp(name, model_ptr->printable_name) == 0) { + + /* Replace the name field with that of the global model, so that when we + want to print it out, we can just compare pointers. */ + insn_model_ptr->fields[insn_model_name] = model_ptr->printable_name; + break; + } + } + + if (!model_ptr) + error("%s:%d: machine model `%s' was not known about\n", + file_entry->file_name, file_entry->line_nr, name); + } + + /* insert it according to the order of the fields */ + while (cur_insn != NULL + && new_insn->fields->value >= cur_insn->fields->value) { + ptr_to_cur_insn = &cur_insn->next; + cur_insn = *ptr_to_cur_insn; + } + + new_insn->next = cur_insn; + *ptr_to_cur_insn = new_insn; + + table->nr_insn++; +} + + + +insn_table * +load_insn_table(const char *file_name, + decode_table *decode_rules, + filter *filters) +{ + table *file = table_open(file_name, nr_insn_table_fields, nr_insn_model_table_fields); + insn_table *table = ZALLOC(insn_table); + table_entry *file_entry; + table->opcode_rule = decode_rules; + + while ((file_entry = table_entry_read(file)) != NULL) { + if (it_is("function", file_entry->fields[insn_flags]) + || it_is("internal", file_entry->fields[insn_flags])) { + insn_table_insert_function(table, file_entry); + } + else if (it_is("model", file_entry->fields[insn_flags])) { + model_table_insert(table, file_entry); + } + else if (it_is("model-macro", file_entry->fields[insn_flags])) { + model_table_insert_specific(table, file_entry, &model_macros, &last_model_macro); + } + else if (it_is("model-function", file_entry->fields[insn_flags])) { + model_table_insert_specific(table, file_entry, &model_functions, &last_model_function); + } + else if (it_is("model-internal", file_entry->fields[insn_flags])) { + model_table_insert_specific(table, file_entry, &model_internal, &last_model_internal); + } + else if (it_is("model-static", file_entry->fields[insn_flags])) { + model_table_insert_specific(table, file_entry, &model_static, &last_model_static); + } + else if (it_is("model-data", file_entry->fields[insn_flags])) { + model_table_insert_specific(table, file_entry, &model_data, &last_model_data); + } + else { + insn_fields *fields; + /* skip instructions that aren't relevant to the mode */ + if (is_filtered_out(file_entry->fields[insn_flags], filters)) { + fprintf(stderr, "Dropping %s - %s\n", + file_entry->fields[insn_name], + file_entry->fields[insn_flags]); + } + else { + /* create/insert the new instruction */ + fields = parse_insn_format(file_entry, + file_entry->fields[insn_format]); + insn_table_insert_insn(table, file_entry, fields); + } + } + } + return table; +} + + +extern void +insn_table_traverse_tree(insn_table *table, + lf *file, + void *data, + int depth, + leaf_handler *start, + insn_handler *leaf, + leaf_handler *end, + padding_handler *padding) +{ + insn_table *entry; + int entry_nr; + + ASSERT(table != NULL + && table->opcode != NULL + && table->nr_entries > 0 + && table->entries != 0); + + if (start != NULL && depth >= 0) + start(table, file, data, depth); + + for (entry_nr = 0, entry = table->entries; + entry_nr < (table->opcode->is_boolean + ? 2 + : (1 << (table->opcode->last - table->opcode->first + 1))); + entry_nr ++) { + if (entry == NULL + || (!table->opcode->is_boolean + && entry_nr < entry->opcode_nr)) { + if (padding != NULL && depth >= 0) + padding(table, file, data, depth, entry_nr); + } + else { + ASSERT(entry != NULL && (entry->opcode_nr == entry_nr + || table->opcode->is_boolean)); + if (entry->opcode != NULL && depth != 0) { + insn_table_traverse_tree(entry, file, data, depth+1, + start, leaf, end, padding); + } + else if (depth >= 0) { + if (leaf != NULL) + leaf(entry, file, data, entry->insns, depth); + } + entry = entry->sibling; + } + } + if (end != NULL && depth >= 0) + end(table, file, data, depth); +} + + +extern void +insn_table_traverse_function(insn_table *table, + lf *file, + void *data, + function_handler *leaf) +{ + insn *function; + for (function = table->functions; + function != NULL; + function = function->next) { + leaf(table, file, data, function->file_entry); + } +} + +extern void +insn_table_traverse_insn(insn_table *table, + lf *file, + void *data, + insn_handler *handler) +{ + insn *instruction; + for (instruction = table->insns; + instruction != NULL; + instruction = instruction->next) { + handler(table, file, data, instruction, 0); + } +} + + +/****************************************************************/ + +typedef enum { + field_constant_int = 1, + field_constant_slash = 2, + field_constant_string = 3 +} constant_field_types; + + +static int +insn_field_is_constant(insn_field *field, + decode_table *rule) +{ + /* field is an integer */ + if (field->is_int) + return field_constant_int; + /* field is `/' and treating that as a constant */ + if (field->is_slash && rule->force_slash) + return field_constant_slash; + /* field, though variable is on the list */ + if (field->is_string && rule->force_expansion != NULL) { + char *forced_fields = rule->force_expansion; + while (*forced_fields != '\0') { + int field_len; + char *end = strchr(forced_fields, ','); + if (end == NULL) + field_len = strlen(forced_fields); + else + field_len = end-forced_fields; + if (strncmp(forced_fields, field->val_string, field_len) == 0 + && field->val_string[field_len] == '\0') + return field_constant_string; + forced_fields += field_len; + if (*forced_fields == ',') + forced_fields++; + } + } + return 0; +} + + +static opcode_field * +insn_table_find_opcode_field(insn *insns, + decode_table *rule, + int string_only) +{ + opcode_field *curr_opcode = ZALLOC(opcode_field); + insn *entry; + ASSERT(rule); + + curr_opcode->first = insn_bit_size; + curr_opcode->last = -1; + for (entry = insns; entry != NULL; entry = entry->next) { + insn_fields *fields = entry->fields; + opcode_field new_opcode; + + /* find a start point for the opcode field */ + new_opcode.first = rule->first; + while (new_opcode.first <= rule->last + && (!string_only + || insn_field_is_constant(fields->bits[new_opcode.first], + rule) != field_constant_string) + && (string_only + || !insn_field_is_constant(fields->bits[new_opcode.first], + rule))) + new_opcode.first = fields->bits[new_opcode.first]->last + 1; + ASSERT(new_opcode.first > rule->last + || (string_only + && insn_field_is_constant(fields->bits[new_opcode.first], + rule) == field_constant_string) + || (!string_only + && insn_field_is_constant(fields->bits[new_opcode.first], + rule))); + + /* find the end point for the opcode field */ + new_opcode.last = rule->last; + while (new_opcode.last >= rule->first + && (!string_only + || insn_field_is_constant(fields->bits[new_opcode.last], + rule) != field_constant_string) + && (string_only + || !insn_field_is_constant(fields->bits[new_opcode.last], + rule))) + new_opcode.last = fields->bits[new_opcode.last]->first - 1; + ASSERT(new_opcode.last < rule->first + || (string_only + && insn_field_is_constant(fields->bits[new_opcode.last], + rule) == field_constant_string) + || (!string_only + && insn_field_is_constant(fields->bits[new_opcode.last], + rule))); + + /* now see if our current opcode needs expanding */ + if (new_opcode.first <= rule->last + && curr_opcode->first > new_opcode.first) + curr_opcode->first = new_opcode.first; + if (new_opcode.last >= rule->first + && curr_opcode->last < new_opcode.last) + curr_opcode->last = new_opcode.last; + + } + + /* was any thing interesting found? */ + if (curr_opcode->first > rule->last) { + ASSERT(curr_opcode->last < rule->first); + return NULL; + } + ASSERT(curr_opcode->last >= rule->first); + ASSERT(curr_opcode->first <= rule->last); + + /* if something was found, check it includes the forced field range */ + if (!string_only + && curr_opcode->first > rule->force_first) { + curr_opcode->first = rule->force_first; + } + if (!string_only + && curr_opcode->last < rule->force_last) { + curr_opcode->last = rule->force_last; + } + /* handle special case elminating any need to do shift after mask */ + if (string_only + && rule->force_last == insn_bit_size-1) { + curr_opcode->last = insn_bit_size-1; + } + + /* handle any special cases */ + switch (rule->type) { + case normal_decode_rule: + /* let the above apply */ + break; + case expand_forced_rule: + /* expand a limited nr of bits, ignoring the rest */ + curr_opcode->first = rule->force_first; + curr_opcode->last = rule->force_last; + break; + case boolean_rule: + curr_opcode->is_boolean = 1; + curr_opcode->boolean_constant = rule->special_constant; + break; + default: + error("Something is going wrong\n"); + } + + return curr_opcode; +} + + +static void +insn_table_insert_expanded(insn_table *table, + insn *old_insn, + int new_opcode_nr, + insn_bits *new_bits) +{ + insn_table **ptr_to_cur_entry = &table->entries; + insn_table *cur_entry = *ptr_to_cur_entry; + + /* find the new table for this entry */ + while (cur_entry != NULL + && cur_entry->opcode_nr < new_opcode_nr) { + ptr_to_cur_entry = &cur_entry->sibling; + cur_entry = *ptr_to_cur_entry; + } + + if (cur_entry == NULL || cur_entry->opcode_nr != new_opcode_nr) { + insn_table *new_entry = ZALLOC(insn_table); + new_entry->opcode_nr = new_opcode_nr; + new_entry->expanded_bits = new_bits; + new_entry->opcode_rule = table->opcode_rule->next; + new_entry->sibling = cur_entry; + new_entry->parent = table; + *ptr_to_cur_entry = new_entry; + cur_entry = new_entry; + table->nr_entries++; + } + /* ASSERT new_bits == cur_entry bits */ + ASSERT(cur_entry != NULL && cur_entry->opcode_nr == new_opcode_nr); + insn_table_insert_insn(cur_entry, + old_insn->file_entry, + old_insn->fields); +} + +static void +insn_table_expand_opcode(insn_table *table, + insn *instruction, + int field_nr, + int opcode_nr, + insn_bits *bits) +{ + + if (field_nr > table->opcode->last) { + insn_table_insert_expanded(table, instruction, opcode_nr, bits); + } + else { + insn_field *field = instruction->fields->bits[field_nr]; + if (field->is_int || field->is_slash) { + ASSERT(field->first >= table->opcode->first + && field->last <= table->opcode->last); + insn_table_expand_opcode(table, instruction, field->last+1, + ((opcode_nr << field->width) + field->val_int), + bits); + } + else { + int val; + int last_pos = ((field->last < table->opcode->last) + ? field->last : table->opcode->last); + int first_pos = ((field->first > table->opcode->first) + ? field->first : table->opcode->first); + int width = last_pos - first_pos + 1; + int last_val = (table->opcode->is_boolean + ? 2 : (1 << width)); + for (val = 0; val < last_val; val++) { + insn_bits *new_bits = ZALLOC(insn_bits); + new_bits->field = field; + new_bits->value = val; + new_bits->last = bits; + new_bits->opcode = table->opcode; + insn_table_expand_opcode(table, instruction, last_pos+1, + ((opcode_nr << width) | val), + new_bits); + } + } + } +} + +static void +insn_table_insert_expanding(insn_table *table, + insn *entry) +{ + insn_table_expand_opcode(table, + entry, + table->opcode->first, + 0, + table->expanded_bits); +} + + +extern void +insn_table_expand_insns(insn_table *table) +{ + + ASSERT(table->nr_insn >= 1); + + /* determine a valid opcode */ + while (table->opcode_rule) { + /* specials only for single instructions */ + if ((table->nr_insn > 1 + && table->opcode_rule->special_mask == 0 + && table->opcode_rule->type == normal_decode_rule) + || (table->nr_insn == 1 + && table->opcode_rule->special_mask != 0 + && ((table->insns->fields->value + & table->opcode_rule->special_mask) + == table->opcode_rule->special_value)) + || (generate_expanded_instructions + && table->opcode_rule->special_mask == 0 + && table->opcode_rule->type == normal_decode_rule)) + table->opcode = + insn_table_find_opcode_field(table->insns, + table->opcode_rule, + table->nr_insn == 1/*string*/ + ); + if (table->opcode != NULL) + break; + table->opcode_rule = table->opcode_rule->next; + } + + /* did we find anything */ + if (table->opcode == NULL) { + return; + } + ASSERT(table->opcode != NULL); + + /* back link what we found to its parent */ + if (table->parent != NULL) { + ASSERT(table->parent->opcode != NULL); + table->opcode->parent = table->parent->opcode; + } + + /* expand the raw instructions according to the opcode */ + { + insn *entry; + for (entry = table->insns; entry != NULL; entry = entry->next) { + insn_table_insert_expanding(table, entry); + } + } + + /* and do the same for the sub entries */ + { + insn_table *entry; + for (entry = table->entries; entry != NULL; entry = entry->sibling) { + insn_table_expand_insns(entry); + } + } +} + + + + +#ifdef MAIN + +static void +dump_insn_field(insn_field *field, + int indent) +{ + + printf("(insn_field*)0x%x\n", (unsigned)field); + + dumpf(indent, "(first %d)\n", field->first); + + dumpf(indent, "(last %d)\n", field->last); + + dumpf(indent, "(width %d)\n", field->width); + + if (field->is_int) + dumpf(indent, "(is_int %d)\n", field->val_int); + + if (field->is_slash) + dumpf(indent, "(is_slash)\n"); + + if (field->is_string) + dumpf(indent, "(is_string `%s')\n", field->val_string); + + dumpf(indent, "(next 0x%x)\n", field->next); + + dumpf(indent, "(prev 0x%x)\n", field->prev); + + +} + +static void +dump_insn_fields(insn_fields *fields, + int indent) +{ + int i; + + printf("(insn_fields*)%p\n", fields); + + dumpf(indent, "(first 0x%x)\n", fields->first); + dumpf(indent, "(last 0x%x)\n", fields->last); + + dumpf(indent, "(value 0x%x)\n", fields->value); + + for (i = 0; i < insn_bit_size; i++) { + dumpf(indent, "(bits[%d] ", i, fields->bits[i]); + dump_insn_field(fields->bits[i], indent+1); + dumpf(indent, " )\n"); + } + +} + + +static void +dump_opcode_field(opcode_field *field, int indent, int levels) +{ + printf("(opcode_field*)%p\n", field); + if (levels && field != NULL) { + dumpf(indent, "(first %d)\n", field->first); + dumpf(indent, "(last %d)\n", field->last); + dumpf(indent, "(is_boolean %d)\n", field->is_boolean); + dumpf(indent, "(parent "); + dump_opcode_field(field->parent, indent, levels-1); + } +} + + +static void +dump_insn_bits(insn_bits *bits, int indent, int levels) +{ + printf("(insn_bits*)%p\n", bits); + + if (levels && bits != NULL) { + dumpf(indent, "(value %d)\n", bits->value); + dumpf(indent, "(opcode "); + dump_opcode_field(bits->opcode, indent+1, 0); + dumpf(indent, " )\n"); + dumpf(indent, "(field "); + dump_insn_field(bits->field, indent+1); + dumpf(indent, " )\n"); + dumpf(indent, "(last "); + dump_insn_bits(bits->last, indent+1, levels-1); + } +} + + + +static void +dump_insn(insn *entry, int indent, int levels) +{ + printf("(insn*)%p\n", entry); + + if (levels && entry != NULL) { + + dumpf(indent, "(file_entry "); + dump_table_entry(entry->file_entry, indent+1); + dumpf(indent, " )\n"); + + dumpf(indent, "(fields "); + dump_insn_fields(entry->fields, indent+1); + dumpf(indent, " )\n"); + + dumpf(indent, "(next "); + dump_insn(entry->next, indent+1, levels-1); + dumpf(indent, " )\n"); + + } + +} + + +static void +dump_insn_table(insn_table *table, + int indent, int levels) +{ + + printf("(insn_table*)%p\n", table); + + if (levels && table != NULL) { + + dumpf(indent, "(opcode_nr %d)\n", table->opcode_nr); + + dumpf(indent, "(expanded_bits "); + dump_insn_bits(table->expanded_bits, indent+1, -1); + dumpf(indent, " )\n"); + + dumpf(indent, "(int nr_insn %d)\n", table->nr_insn); + + dumpf(indent, "(insns "); + dump_insn(table->insns, indent+1, table->nr_insn); + dumpf(indent, " )\n"); + + dumpf(indent, "(opcode_rule "); + dump_decode_rule(table->opcode_rule, indent+1); + dumpf(indent, " )\n"); + + dumpf(indent, "(opcode "); + dump_opcode_field(table->opcode, indent+1, 1); + dumpf(indent, " )\n"); + + dumpf(indent, "(nr_entries %d)\n", table->entries); + dumpf(indent, "(entries "); + dump_insn_table(table->entries, indent+1, table->nr_entries); + dumpf(indent, " )\n"); + + dumpf(indent, "(sibling ", table->sibling); + dump_insn_table(table->sibling, indent+1, levels-1); + dumpf(indent, " )\n"); + + dumpf(indent, "(parent ", table->parent); + dump_insn_table(table->parent, indent+1, 0); + dumpf(indent, " )\n"); + + } +} + +int insn_bit_size = max_insn_bit_size; +int hi_bit_nr; +int generate_expanded_instructions; + +int +main(int argc, char **argv) +{ + filter *filters = NULL; + decode_table *decode_rules = NULL; + insn_table *instructions = NULL; + + if (argc != 5) + error("Usage: insn \n"); + + filters = new_filter(argv[1], filters); + hi_bit_nr = a2i(argv[2]); + ASSERT(hi_bit_nr < insn_bit_size); + decode_rules = load_decode_table(argv[3], hi_bit_nr); + instructions = load_insn_table(argv[4], decode_rules, filters); + insn_table_expand_insns(instructions); + + dump_insn_table(instructions, 0, -1); + return 0; +} + +#endif diff --git a/sim/ppc/ld-insn.h b/sim/ppc/ld-insn.h new file mode 100644 index 00000000000..e800f0dac23 --- /dev/null +++ b/sim/ppc/ld-insn.h @@ -0,0 +1,281 @@ +/* This file is part of the program psim. + + Copyright (C) 1994,1995,1996, Andrew Cagney + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + +/* +# -- +# +# +# Fields: +# +# 1 Instruction format as a `start-bit,content' pairs. +# the content is one of a digit, field name or `/' (aka.0) +# +# 2 Format specifier +# +# 3 Flags: 64 - 64bit only +# f - floating point enabled required +# +# 4 short name +# +# 5 Description +# +# +# For flags marked 'model', the fields are interpreted as follows: +# +# 1 Not used +# +# 2 Not used +# +# 3 "macro" +# +# 4 String name for model +# +# 5 Specific CPU model, must be an identifier +# +# 6 Comma separated list of functional units + +*/ + + +/* Global constants */ + +enum { + max_insn_bit_size = 32, +}; + + +typedef struct _insn_field insn_field; +struct _insn_field { + int first; + int last; + int width; + int is_int; + int is_slash; + int is_string; + int val_int; + char *pos_string; + char *val_string; + insn_field *next; + insn_field *prev; +}; + +typedef struct _insn_fields insn_fields; +struct _insn_fields { + insn_field *bits[max_insn_bit_size]; + insn_field *first; + insn_field *last; + unsigned value; +}; + + +/****************************************************************/ + +typedef struct _opcode_field opcode_field; +struct _opcode_field { + int first; + int last; + int is_boolean; + unsigned boolean_constant; + opcode_field *parent; +}; + + +/****************************************************************/ + +typedef struct _insn_bits insn_bits; +struct _insn_bits { + int is_expanded; + int value; + insn_field *field; + opcode_field *opcode; + insn_bits *last; +}; + + +/****************************************************************/ + + +typedef enum { + insn_format, + insn_form, + insn_flags, + insn_mnemonic, + insn_name, + insn_comment, + nr_insn_table_fields +} insn_table_fields; + +typedef enum { + function_type = insn_format, + function_name = insn_name, + function_param = insn_comment +} function_table_fields; + +typedef enum { + model_name = insn_mnemonic, + model_identifer = insn_name, + model_default = insn_comment, +} model_table_fields; + +typedef struct _insn insn; +struct _insn { + table_entry *file_entry; + insn_fields *fields; + insn *next; +}; + +typedef struct _insn_undef insn_undef; +struct _insn_undef { + insn_undef *next; + char *name; +}; + +typedef struct _model model; +struct _model { + model *next; + char *name; + char *printable_name; + char *insn_default; + table_model_entry *func_unit_start; + table_model_entry *func_unit_end; +}; + +typedef struct _insn_table insn_table; +struct _insn_table { + int opcode_nr; + insn_bits *expanded_bits; + int nr_insn; + insn *insns; + insn *functions; + insn *last_function; + decode_table *opcode_rule; + opcode_field *opcode; + int nr_entries; + insn_table *entries; + insn_table *sibling; + insn_table *parent; +}; + +typedef enum { + insn_model_name, + insn_model_fields, + nr_insn_model_table_fields +} insn_model_table_fields; + + +extern insn_table *load_insn_table +(const char *file_name, + decode_table *decode_rules, + filter *filters); + +model *models; +model *last_model; + +insn *model_macros; +insn *last_model_macro; + +insn *model_functions; +insn *last_model_function; + +insn *model_internal; +insn *last_model_internal; + +insn *model_static; +insn *last_model_static; + +insn *model_data; +insn *last_model_data; + +int max_model_fields_len; + +extern void insn_table_insert_insn +(insn_table *table, + table_entry *file_entry, + insn_fields *fields); + + +/****************************************************************/ + +/****************************************************************/ + +typedef void leaf_handler +(insn_table *entry, + lf *file, + void *data, + int depth); + +typedef void insn_handler +(insn_table *table, + lf *file, + void *data, + insn *instruction, + int depth); + +typedef void padding_handler +(insn_table *table, + lf *file, + void *data, + int depth, + int opcode_nr); + + +extern void insn_table_traverse_tree +(insn_table *table, + lf *file, + void *data, + int depth, + leaf_handler *start, + insn_handler *handler, + leaf_handler *end, + padding_handler *padding); + + +extern void insn_table_traverse_insn +(insn_table *table, + lf *file, + void *data, + insn_handler *handler); + + + +/****************************************************************/ + +typedef void function_handler +(insn_table *table, + lf *file, + void *data, + table_entry *function); + +extern void +insn_table_traverse_function +(insn_table *table, + lf *file, + void *data, + function_handler *leaf); + +/****************************************************************/ + + + +extern void insn_table_expand_insns +(insn_table *table); + +extern int insn_table_depth +(insn_table *table); diff --git a/sim/ppc/ppc-cache-rules b/sim/ppc/ppc-cache-rules index 939b943dd15..88c55e8f8ce 100644 --- a/sim/ppc/ppc-cache-rules +++ b/sim/ppc/ppc-cache-rules @@ -17,84 +17,47 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # -# -# Instruction unpacking: -# -# Once the instruction has been decoded, the register (and other) -# fields within the instruction need to be extracted. -# -# The table that follows determines how each field should be treated. -# Importantly it considers the case where the extracted field is to -# be used immediatly or stored in an instruction cache. -# -# -# -# Zero marks the end of the table. More importantly 1. indicates -# that the entry is valid and can be cached. 2. indicates that that -# the entry is valid but can not be cached. -# -# -# -# The field name as given in the instruction spec. -# -# -# -# A name for once it has been extracted from the -# instructioin (and possibly stored in the instruction cache). -# -# -# -# String specifying the storage type for (the extracted -# field>. -# -# -# -# Specifies how to get from . If null, old and -# new name had better be the same. */ -# -# -1:RA:RA:: -1:RA:rA:signed_word *:(cpu_registers(processor)->gpr + RA) -1:RA:RA_BITMASK:unsigned32:(1 << RA) -1:RT:RT:: -1:RT:rT:signed_word *:(cpu_registers(processor)->gpr + RT) -1:RT:RT_BITMASK:unsigned32:(1 << RT) -2:RS:RS:: -1:RS:rS:signed_word *:(cpu_registers(processor)->gpr + RS) -1:RS:RS_BITMASK:unsigned32:(1 << RS) -2:RB:RB:: -1:RB:rB:signed_word *:(cpu_registers(processor)->gpr + RB) -1:RB:RB_BITMASK:unsigned32:(1 << RB) -2:FRA:FRA:: -1:FRA:frA:unsigned64 *:(cpu_registers(processor)->fpr + FRA) -1:FRA:FRA_BITMASK:unsigned32:(1 << FRA) -2:FRB:FRB:: -1:FRB:frB:unsigned64 *:(cpu_registers(processor)->fpr + FRB) -1:FRB:FRB_BITMASK:unsigned32:(1 << FRB) -2:FRC:FRC:: -1:FRC:frC:unsigned64 *:(cpu_registers(processor)->fpr + FRC) -1:FRC:FRC_BITMASK:unsigned32:(1 << FRC) -2:FRS:FRS:: -1:FRS:frS:unsigned64 *:(cpu_registers(processor)->fpr + FRS) -1:FRS:FRS_BITMASK:unsigned32:(1 << FRS) -2:FRT:FRT:: -1:FRT:frT:unsigned64 *:(cpu_registers(processor)->fpr + FRT) -1:FRT:FRT_BITMASK:unsigned32:(1 << FRT) -1:SI:EXTS_SI:unsigned_word:((signed_word)(signed16)instruction) -2:BI:BI:: -1:BI:BIT32_BI::BIT32(BI) -1:BF:BF:: -1:BF:BF_BITMASK:unsigned32:(1 << BF) -2:BA:BA:: -1:BA:BIT32_BA::BIT32(BA) -1:BA:BA_BITMASK:unsigned32:(1 << BA) -2:BB:BB:: -1:BB:BIT32_BB::BIT32(BB) -1:BB:BB_BITMASK:unsigned32:(1 << BB) -1:BT:BT:: -1:BT:BT_BITMASK:unsigned32:(1 << BT) -1:BD:EXTS_BD_0b00:unsigned_word:(((signed_word)(signed16)instruction) & ~3) -#1:BD:CIA_plus_EXTS_BD_0b00:unsigned_word:CIA + EXTS(BD_0b00) -1:LI:EXTS_LI_0b00:unsigned_word:((((signed_word)(signed32)(instruction << 6)) >> 6) & ~0x3) -1:D:EXTS_D:unsigned_word:((signed_word)(signed16)(instruction)) -1:DS:EXTS_DS_0b00:unsigned_word:(((signed_word)(signed16)instruction) & ~0x3) +cache:RA:RA:: +cache:RA:rA:signed_word *:(cpu_registers(processor)->gpr + RA) +cache:RA:RA_BITMASK:unsigned32:(1 << RA) +cache:RT:RT:: +cache:RT:rT:signed_word *:(cpu_registers(processor)->gpr + RT) +cache:RT:RT_BITMASK:unsigned32:(1 << RT) +compute:RS:RS:: +cache:RS:rS:signed_word *:(cpu_registers(processor)->gpr + RS) +cache:RS:RS_BITMASK:unsigned32:(1 << RS) +compute:RB:RB:: +cache:RB:rB:signed_word *:(cpu_registers(processor)->gpr + RB) +cache:RB:RB_BITMASK:unsigned32:(1 << RB) +compute:FRA:FRA:: +cache:FRA:frA:unsigned64 *:(cpu_registers(processor)->fpr + FRA) +cache:FRA:FRA_BITMASK:unsigned32:(1 << FRA) +compute:FRB:FRB:: +cache:FRB:frB:unsigned64 *:(cpu_registers(processor)->fpr + FRB) +cache:FRB:FRB_BITMASK:unsigned32:(1 << FRB) +compute:FRC:FRC:: +cache:FRC:frC:unsigned64 *:(cpu_registers(processor)->fpr + FRC) +cache:FRC:FRC_BITMASK:unsigned32:(1 << FRC) +compute:FRS:FRS:: +cache:FRS:frS:unsigned64 *:(cpu_registers(processor)->fpr + FRS) +cache:FRS:FRS_BITMASK:unsigned32:(1 << FRS) +compute:FRT:FRT:: +cache:FRT:frT:unsigned64 *:(cpu_registers(processor)->fpr + FRT) +cache:FRT:FRT_BITMASK:unsigned32:(1 << FRT) +cache:SI:EXTS_SI:unsigned_word:((signed_word)(signed16)instruction) +compute:BI:BI:: +cache:BI:BIT32_BI::BIT32(BI) +cache:BF:BF:: +cache:BF:BF_BITMASK:unsigned32:(1 << BF) +compute:BA:BA:: +cache:BA:BIT32_BA::BIT32(BA) +cache:BA:BA_BITMASK:unsigned32:(1 << BA) +compute:BB:BB:: +cache:BB:BIT32_BB::BIT32(BB) +cache:BB:BB_BITMASK:unsigned32:(1 << BB) +cache:BT:BT:: +cache:BT:BT_BITMASK:unsigned32:(1 << BT) +cache:BD:EXTS_BD_0b00:unsigned_word:(((signed_word)(signed16)instruction) & ~3) +cache:LI:EXTS_LI_0b00:unsigned_word:((((signed_word)(signed32)(instruction << 6)) >> 6) & ~0x3) +cache:D:EXTS_D:unsigned_word:((signed_word)(signed16)(instruction)) +cache:DS:EXTS_DS_0b00:unsigned_word:(((signed_word)(signed16)instruction) & ~0x3) diff --git a/sim/ppc/ppc-instructions b/sim/ppc/ppc-instructions index 2ac13ab68ca..be626555670 100644 --- a/sim/ppc/ppc-instructions +++ b/sim/ppc/ppc-instructions @@ -1,7 +1,7 @@ # # This file is part of the program psim. # -# Copyright (C) 1994-1995, Andrew Cagney +# Copyright (C) 1994-1996, Andrew Cagney # # -- # @@ -33,38 +33,6 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # -# -- -# -# -# Fields: -# -# 1 Instruction format as a `start-bit,content' pairs. -# the content is one of a digit, field name or `/' (aka.0) -# -# 2 Format specifier -# -# 3 Flags: 64 - 64bit only -# f - floating point enabled required -# -# 4 short name -# -# 5 Description -# -# -# For flags marked 'model', the fields are interpreted as follows: -# -# 1 Not used -# -# 2 Not used -# -# 3 "macro" -# -# 4 String name for model -# -# 5 Specific CPU model, must be an identifier -# -# 6 Comma separated list of functional units - # PowerPC models ::model:604:ppc604: PPC_UNIT_BAD, PPC_UNIT_BAD, 1, 1, 0 @@ -78,68 +46,68 @@ do { \ if (CURRENT_MODEL_ISSUE > 0) { \ if (RC) \ - ppc_insn_int(my_index, cpu_model(processor), OUT_MASK, IN_MASK); \ + ppc_insn_int(MY_INDEX, cpu_model(processor), OUT_MASK, IN_MASK); \ else \ - ppc_insn_int_cr(my_index, cpu_model(processor), OUT_MASK, IN_MASK, 1 << 0); \ + ppc_insn_int_cr(MY_INDEX, cpu_model(processor), OUT_MASK, IN_MASK, 1 << 0); \ } \ } while (0) #define PPC_INSN_INT_CR(OUT_MASK, IN_MASK, CR_MASK) \ do { \ if (CURRENT_MODEL_ISSUE > 0) \ - ppc_insn_int_cr(my_index, cpu_model(processor), OUT_MASK, IN_MASK, CR_MASK); \ + ppc_insn_int_cr(MY_INDEX, cpu_model(processor), OUT_MASK, IN_MASK, CR_MASK); \ } while (0) #define PPC_INSN_CR(OUT_MASK, IN_MASK) \ do { \ if (CURRENT_MODEL_ISSUE > 0) \ - ppc_insn_cr(my_index, cpu_model(processor), OUT_MASK, IN_MASK); \ + ppc_insn_cr(MY_INDEX, cpu_model(processor), OUT_MASK, IN_MASK); \ } while (0) #define PPC_INSN_FLOAT(OUT_MASK, IN_MASK, RC) \ do { \ if (CURRENT_MODEL_ISSUE > 0) { \ if (RC) \ - ppc_insn_float(my_index, cpu_model(processor), OUT_MASK, IN_MASK); \ + ppc_insn_float(MY_INDEX, cpu_model(processor), OUT_MASK, IN_MASK); \ else \ - ppc_insn_float_cr(my_index, cpu_model(processor), OUT_MASK, IN_MASK, 1 << 0); \ + ppc_insn_float_cr(MY_INDEX, cpu_model(processor), OUT_MASK, IN_MASK, 1 << 0); \ } \ } while (0) #define PPC_INSN_FLOAT_CR(OUT_MASK, IN_MASK, CR_MASK) \ do { \ if (CURRENT_MODEL_ISSUE > 0) \ - ppc_insn_float_cr(my_index, cpu_model(processor), OUT_MASK, IN_MASK, CR_MASK); \ + ppc_insn_float_cr(MY_INDEX, cpu_model(processor), OUT_MASK, IN_MASK, CR_MASK); \ } while (0) #define PPC_INSN_INT_FLOAT(OUT_INT_MASK, OUT_FP_MASK, IN_INT_MASK, IN_FP_MASK) \ do { \ if (CURRENT_MODEL_ISSUE > 0) \ - ppc_insn_int_float(my_index, cpu_model(processor), OUT_INT_MASK, OUT_FP_MASK, IN_INT_MASK, IN_FP_MASK); \ + ppc_insn_int_float(MY_INDEX, cpu_model(processor), OUT_INT_MASK, OUT_FP_MASK, IN_INT_MASK, IN_FP_MASK); \ } while (0) #define PPC_INSN_FROM_SPR(INT_MASK, SPR) \ do { \ if (CURRENT_MODEL_ISSUE > 0) \ - ppc_insn_from_spr(my_index, cpu_model(processor), INT_MASK, SPR); \ + ppc_insn_from_spr(MY_INDEX, cpu_model(processor), INT_MASK, SPR); \ } while (0) #define PPC_INSN_TO_SPR(INT_MASK, SPR) \ do { \ if (CURRENT_MODEL_ISSUE > 0) \ - ppc_insn_to_spr(my_index, cpu_model(processor), INT_MASK, SPR); \ + ppc_insn_to_spr(MY_INDEX, cpu_model(processor), INT_MASK, SPR); \ } while (0) #define PPC_INSN_MFCR(INT_MASK) \ do { \ if (CURRENT_MODEL_ISSUE > 0) \ - ppc_insn_mfcr(my_index, cpu_model(processor), INT_MASK); \ + ppc_insn_mfcr(MY_INDEX, cpu_model(processor), INT_MASK); \ } while (0) #define PPC_INSN_MTCR(INT_MASK, FXM) \ do { \ if (CURRENT_MODEL_ISSUE > 0) \ - ppc_insn_mtcr(my_index, cpu_model(processor), INT_MASK, FXM); \ + ppc_insn_mtcr(MY_INDEX, cpu_model(processor), INT_MASK, FXM); \ } while (0) ::model-data::: @@ -187,7 +155,7 @@ signed16 done; /* # of cycles until insn is done */ signed16 nr_writebacks; /* # of registers this unit writes back */ }; - + /* Structure to hold the current state information for the simulated CPU model */ struct _model_data { cpu *processor; /* point back to processor */ @@ -783,6 +751,15 @@ void::model-function::model_halt:model_data *model_ptr while (model_ptr->busy_head.next) model_new_cycle(model_ptr); +unsigned_word::model-function::model_get_number_of_stalls:model_data *model_ptr + return (model_ptr->nr_stalls_data + + model_ptr->nr_stalls_unit + + model_ptr->nr_stalls_serialize + + model_ptr->nr_stalls_writeback); + +unsigned_word::model-function::model_get_number_of_cycles:model_data *model_ptr + return (model_ptr->nr_cycles); + model_print *::model-function::model_mon_info:model_data *model_ptr model_print *head; model_print *tail; @@ -828,7 +805,7 @@ model_print *::model-function::model_mon_info:model_data *model_ptr tail = tail->next; tail->count = model_ptr->nr_stalls_writeback; tail->name = ""; - tail->suffix_plural = "times a writeback slot was unavilable"; + tail->suffix_plural = "times a write-back slot was unavailable"; tail->suffix_singular = "time a writeback was unavilable"; } @@ -942,7 +919,6 @@ void::model-function::model_branch_predict:model_data *model_ptr, int success ::internal::illegal program_interrupt(processor, cia, illegal_instruction_program_interrupt); - return 0; # The following (floating point unavailable) instruction is `known' by gen @@ -950,7 +926,6 @@ void::model-function::model_branch_predict:model_data *model_ptr, int success # executed but floating point is make unavailable by the MSR ::internal::floating_point_unavailable floating_point_unavailable_interrupt(processor, cia); - return 0; # @@ -1134,59 +1109,64 @@ void::function::convert_to_integer:cpu *processor, unsigned_word cia, unsigned64 int rbit = 0; int xbit = 0; int sign = EXTRACTED64(frb, 0, 0); - if (EXTRACTED64(frb, 1, 11) == 2047 && EXTRACTED64(frb, 12, 63) == 0) - goto Infinity_Operand; - if (EXTRACTED64(frb, 1, 11) == 2047 && EXTRACTED64(frb, 12, 12) == 0) - goto SNaN_Operand; - if (EXTRACTED64(frb, 1, 11) == 2047 && EXTRACTED64(frb, 12, 12) == 1) - goto QNaN_Operand; - if (EXTRACTED64(frb, 1, 11) > 1086) goto Large_Operand; - if (EXTRACTED64(frb, 1, 11) > 0) exp = EXTRACTED64(frb, 1, 11) - 1023; - if (EXTRACTED64(frb, 1, 11) == 0) exp = -1022; - if (EXTRACTED64(frb, 1, 11) > 0) { /* normal */ - frac = BIT64(1) | INSERTED64(EXTRACTED64(frb, 12, 63), 2, 53); - frac64 = 0; - } - if (EXTRACTED64(frb, 1, 11) == 0) { /* denorm */ - frac = INSERTED64(EXTRACTED64(frb, 12, 63), 2, 53); - frac64 = 0; - } - gbit = 0, rbit = 0, xbit = 0; - for (i = 1; i <= 63 - exp; i++) { - xbit = rbit | xbit; - rbit = gbit; - gbit = frac64; - frac64 = EXTRACTED64(frac, 63, 63); - frac = INSERTED64(EXTRACTED64(frac, 0, 62), 1, 63); - } - Round_Integer(processor, sign, &frac, &frac64, gbit, rbit, xbit, round_mode); - if (sign == 1) { /* frac[0:64] = ~frac[0:64] + 1 */ - frac = ~frac; - frac64 ^= 1; - frac += (frac64 ? 1 : 0); - frac64 = (frac64 + 1) & 0x1; - } - if (tgt_precision == 32 /* can ignore frac64 in compare */ - && (signed64)frac > (signed64)MASK64(33+1, 63)/*2^31-1 >>1*/) - goto Large_Operand; - if (tgt_precision == 64 /* can ignore frac64 in compare */ - && (signed64)frac > (signed64)MASK64(1+1, 63)/*2^63-1 >>1*/) - goto Large_Operand; - if (tgt_precision == 32 /* can ignore frac64 in compare */ - && (signed64)frac < (signed64)MASK64(0, 32+1)/*-2^31 >>1*/) - goto Large_Operand; - if (tgt_precision == 64 /* can ignore frac64 in compare */ - && (signed64)frac < (signed64)MASK64(0, 0+1)/*-2^63 >>1*/) - goto Large_Operand; - FPSCR_SET_XX(FPSCR & fpscr_fi); - if (tgt_precision == 32) - *frt = MASKED64(*frt, 0, 31) | (EXTRACTED64(frac, 33, 63) << 1) | frac64; - if (tgt_precision == 64) - *frt = (EXTRACTED64(frac, 1, 63) << 1) | frac64; - /*FPSCR[fprf] = undefined */ - goto Done; - /**/ - Infinity_Operand: + enum { start, finish, Infinity_Operand, SNaN_Operand, QNaN_Operand, Large_Operand, Done } label = start; + while (label != finish) switch (label) { + case finish: + error("Unhandled switch\n"); + case start: + if (EXTRACTED64(frb, 1, 11) == 2047 && EXTRACTED64(frb, 12, 63) == 0) + { label = Infinity_Operand; break; } + if (EXTRACTED64(frb, 1, 11) == 2047 && EXTRACTED64(frb, 12, 12) == 0) + { label = SNaN_Operand; break; } + if (EXTRACTED64(frb, 1, 11) == 2047 && EXTRACTED64(frb, 12, 12) == 1) + { label = QNaN_Operand; break; } + if (EXTRACTED64(frb, 1, 11) > 1086) { label = Large_Operand; break; } + if (EXTRACTED64(frb, 1, 11) > 0) exp = EXTRACTED64(frb, 1, 11) - 1023; + if (EXTRACTED64(frb, 1, 11) == 0) exp = -1022; + if (EXTRACTED64(frb, 1, 11) > 0) { /* normal */ + frac = BIT64(1) | INSERTED64(EXTRACTED64(frb, 12, 63), 2, 53); + frac64 = 0; + } + if (EXTRACTED64(frb, 1, 11) == 0) { /* denorm */ + frac = INSERTED64(EXTRACTED64(frb, 12, 63), 2, 53); + frac64 = 0; + } + gbit = 0, rbit = 0, xbit = 0; + for (i = 1; i <= 63 - exp; i++) { + xbit = rbit | xbit; + rbit = gbit; + gbit = frac64; + frac64 = EXTRACTED64(frac, 63, 63); + frac = INSERTED64(EXTRACTED64(frac, 0, 62), 1, 63); + } + Round_Integer(processor, sign, &frac, &frac64, gbit, rbit, xbit, round_mode); + if (sign == 1) { /* frac[0:64] = ~frac[0:64] + 1 */ + frac = ~frac; + frac64 ^= 1; + frac += (frac64 ? 1 : 0); + frac64 = (frac64 + 1) & 0x1; + } + if (tgt_precision == 32 /* can ignore frac64 in compare */ + && (signed64)frac > (signed64)MASK64(33+1, 63)/*2^31-1 >>1*/) + { label = Large_Operand; break; } + if (tgt_precision == 64 /* can ignore frac64 in compare */ + && (signed64)frac > (signed64)MASK64(1+1, 63)/*2^63-1 >>1*/) + { label = Large_Operand; break; } + if (tgt_precision == 32 /* can ignore frac64 in compare */ + && (signed64)frac < (signed64)MASK64(0, 32+1)/*-2^31 >>1*/) + { label = Large_Operand; break; } + if (tgt_precision == 64 /* can ignore frac64 in compare */ + && (signed64)frac < (signed64)MASK64(0, 0+1)/*-2^63 >>1*/) + { label = Large_Operand; break; } + FPSCR_SET_XX(FPSCR & fpscr_fi); + if (tgt_precision == 32) + *frt = MASKED64(*frt, 0, 31) | (EXTRACTED64(frac, 33, 63) << 1) | frac64; + if (tgt_precision == 64) + *frt = (EXTRACTED64(frac, 1, 63) << 1) | frac64; + /*FPSCR[fprf] = undefined */ + { label = Done; break; } + /**/ + case Infinity_Operand: FPSCR_SET_FR(0); FPSCR_SET_FI(0); FPSCR_OR_VX(fpscr_vxcvi); @@ -1201,9 +1181,9 @@ void::function::convert_to_integer:cpu *processor, unsigned_word cia, unsigned64 } /* FPSCR[FPRF] = undefined */ } - goto Done; + { label = Done; break; } /**/ - SNaN_Operand: + case SNaN_Operand: FPSCR_SET_FR(0); FPSCR_SET_FI(0); FPSCR_OR_VX(fpscr_vxsnan | fpscr_vxcvi); @@ -1212,9 +1192,9 @@ void::function::convert_to_integer:cpu *processor, unsigned_word cia, unsigned64 if (tgt_precision == 64) *frt = BIT64(0); /*0x8000_0000_0000_0000*/ /* FPSCR[fprf] = undefined */ } - goto Done; + { label = Done; break; } /**/ - QNaN_Operand: + case QNaN_Operand: FPSCR_SET_FR(0); FPSCR_SET_FI(0); FPSCR_OR_VX(fpscr_vxcvi); @@ -1223,9 +1203,9 @@ void::function::convert_to_integer:cpu *processor, unsigned_word cia, unsigned64 if (tgt_precision == 64) *frt = BIT64(0);/*0x8000_0000_0000_0000*/ /* FPSCR[fprf] = undefined */ } - goto Done; + { label = Done; break; } /**/ - Large_Operand: + case Large_Operand: FPSCR_SET_FR(0); FPSCR_SET_FI(0); FPSCR_OR_VX(fpscr_vxcvi); @@ -1241,7 +1221,9 @@ void::function::convert_to_integer:cpu *processor, unsigned_word cia, unsigned64 /* FPSCR[fprf] = undefined */ } /**/ - Done: + case Done: + { label = finish; break; } + } # extract out raw fields of a FP number @@ -1419,7 +1401,7 @@ void::function::invalid_arithemetic_operation:cpu *processor, unsigned_word cia, # # I.2.4.1 Branch Instructions # -0.18,6.LI,30.AA,31.LK:I:t::Branch +0.18,6.LI,30.AA,31.LK:I:::Branch *601: PPC_UNIT_BPU, PPC_UNIT_BPU, 1, 1, 0 *603: PPC_UNIT_BPU, PPC_UNIT_BPU, 1, 1, 0 *603e:PPC_UNIT_BPU, PPC_UNIT_BPU, 1, 1, 0 @@ -1430,7 +1412,7 @@ void::function::invalid_arithemetic_operation:cpu *processor, unsigned_word cia, if (CURRENT_MODEL_ISSUE > 0) model_branches(cpu_model(processor), 1, -1); -0.16,6.BO,11.BI,16.BD,30.AA,31.LK:B:t::Branch Conditional +0.16,6.BO,11.BI,16.BD,30.AA,31.LK:B:::Branch Conditional *601: PPC_UNIT_BPU, PPC_UNIT_BPU, 1, 1, 0 *603: PPC_UNIT_BPU, PPC_UNIT_BPU, 1, 1, 0 *603e:PPC_UNIT_BPU, PPC_UNIT_BPU, 1, 1, 0 @@ -1464,7 +1446,7 @@ void::function::invalid_arithemetic_operation:cpu *processor, unsigned_word cia, model_branch_predict(cpu_model(processor), reverse ? !succeed : succeed); } -0.19,6.BO,11.BI,16./,21.16,31.LK:XL:t::Branch Conditional to Link Register +0.19,6.BO,11.BI,16./,21.16,31.LK:XL:::Branch Conditional to Link Register *601: PPC_UNIT_BPU, PPC_UNIT_BPU, 1, 1, 0 *603: PPC_UNIT_BPU, PPC_UNIT_BPU, 1, 1, 0 *603e:PPC_UNIT_BPU, PPC_UNIT_BPU, 1, 1, 0 @@ -1490,7 +1472,7 @@ void::function::invalid_arithemetic_operation:cpu *processor, unsigned_word cia, model_branch_predict(cpu_model(processor), BO{4} ? !succeed : succeed); } -0.19,6.BO,11.BI,16./,21.528,31.LK:XL:t::Branch Conditional to Count Register +0.19,6.BO,11.BI,16./,21.528,31.LK:XL:::Branch Conditional to Count Register *601: PPC_UNIT_BPU, PPC_UNIT_BPU, 1, 1, 0 *603: PPC_UNIT_BPU, PPC_UNIT_BPU, 1, 1, 0 *603e:PPC_UNIT_BPU, PPC_UNIT_BPU, 1, 1, 0 @@ -1515,13 +1497,13 @@ void::function::invalid_arithemetic_operation:cpu *processor, unsigned_word cia, # # I.2.4.2 System Call Instruction # -0.17,6./,11./,16./,30.1,31./:SC:t::System Call +0.17,6./,11./,16./,30.1,31./:SC:::System Call *601: PPC_UNIT_IU, PPC_UNIT_IU, 1, 1, 0 *603: PPC_UNIT_SRU, PPC_UNIT_SRU, 3, 3, 0 *603e:PPC_UNIT_SRU, PPC_UNIT_SRU, 3, 3, 0 *604: PPC_UNIT_SCIU1, PPC_UNIT_SCIU2, 1, 1, 0 if (CURRENT_MODEL_ISSUE > 0) - model_serialize(my_index, cpu_model(processor)); + model_serialize(MY_INDEX, cpu_model(processor)); system_call_interrupt(processor, cia); # @@ -2143,22 +2125,22 @@ void::function::invalid_arithemetic_operation:cpu *processor, unsigned_word cia, # I.3.3.5 Fixed-Point Load and Store Multiple Instrctions # -0.46,6.RT,11.RA,16.D:D:be::Load Multiple Word +0.46,6.RT,11.RA,16.D:D:::Load Multiple Word -0.47,6.RS,11.RA,16.D:D:be::Store Multiple Word +0.47,6.RS,11.RA,16.D:D:::Store Multiple Word # # I.3.3.6 Fixed-Point Move Assist Instructions # -0.31,6.RT,11.RA,16.NB,21.597,31./:X:be::Load String Word Immediate +0.31,6.RT,11.RA,16.NB,21.597,31./:X:::Load String Word Immediate -0.31,6.RT,11.RA,16.RB,21.533,31./:X:be::Load String Word Indexed +0.31,6.RT,11.RA,16.RB,21.533,31./:X:::Load String Word Indexed -0.31,6.RS,11.RA,16.NB,21.725,31./:X:be::Store String Word Immedate +0.31,6.RS,11.RA,16.NB,21.725,31./:X:::Store String Word Immedate -0.31,6.RS,11.RA,16.RB,21.661,31./:X:be::Store String Word Indexed +0.31,6.RS,11.RA,16.RB,21.661,31./:X:::Store String Word Indexed # @@ -2259,7 +2241,7 @@ void::function::invalid_arithemetic_operation:cpu *processor, unsigned_word cia, # I.3.3.9 Fixed-Point Arithmetic Instructions # -0.14,6.RT,11.RA,16.SI:D:T::Add Immediate +0.14,6.RT,11.RA,16.SI:D:::Add Immediate *601: PPC_UNIT_IU, PPC_UNIT_IU, 1, 1, 0 *603: PPC_UNIT_IU, PPC_UNIT_IU, 1, 1, 0 *603e:PPC_UNIT_IU, PPC_UNIT_SRU, 1, 1, 0 @@ -4028,28 +4010,32 @@ void::function::invalid_arithemetic_operation:cpu *processor, unsigned_word cia, int sign; int exp; unsigned64 frac_grx; - /* split off cases for what to do */ - if (EXTRACTED64(*frB, 1, 11) < 897 - && EXTRACTED64(*frB, 1, 63) > 0) { - if ((FPSCR & fpscr_ue) == 0) goto Disabled_Exponent_Underflow; - if ((FPSCR & fpscr_ue) != 0) goto Enabled_Exponent_Underflow; - } - if (EXTRACTED64(*frB, 1, 11) > 1150 - && EXTRACTED64(*frB, 1, 11) < 2047) { - if ((FPSCR & fpscr_oe) == 0) goto Disabled_Exponent_Overflow; - if ((FPSCR & fpscr_oe) != 0) goto Enabled_Exponent_Overflow; - } - if (EXTRACTED64(*frB, 1, 11) > 896 - && EXTRACTED64(*frB, 1, 11) < 1151) goto Normal_Operand; - if (EXTRACTED64(*frB, 1, 63) == 0) goto Zero_Operand; - if (EXTRACTED64(*frB, 1, 11) == 2047) { - if (EXTRACTED64(*frB, 12, 63) == 0) goto Infinity_Operand; - if (EXTRACTED64(*frB, 12, 12) == 1) goto QNaN_Operand; - if (EXTRACTED64(*frB, 12, 12) == 0 - && EXTRACTED64(*frB, 13, 63) > 0) goto SNaN_Operand; - } - /* handle them */ - Disabled_Exponent_Underflow: + enum { start, finish, Disabled_Exponent_Underflow, Enabled_Exponent_Underflow, Disabled_Exponent_Overflow, Enabled_Exponent_Overflow, Normal_Operand, Zero_Operand, Infinity_Operand, QNaN_Operand, SNaN_Operand, Enabled_Overflow, Done } label = start; + while (label != finish) switch (label) { + case finish: + error("Unhandled switch\n"); + case start: + /* split off cases for what to do */ + if (EXTRACTED64(*frB, 1, 11) < 897 + && EXTRACTED64(*frB, 1, 63) > 0) { + if ((FPSCR & fpscr_ue) == 0) { label = Disabled_Exponent_Underflow; break; } + if ((FPSCR & fpscr_ue) != 0) { label = Enabled_Exponent_Underflow; break; } + } + if (EXTRACTED64(*frB, 1, 11) > 1150 + && EXTRACTED64(*frB, 1, 11) < 2047) { + if ((FPSCR & fpscr_oe) == 0) { label = Disabled_Exponent_Overflow; break; } + if ((FPSCR & fpscr_oe) != 0) { label = Enabled_Exponent_Overflow; break; } + } + if (EXTRACTED64(*frB, 1, 11) > 896 + && EXTRACTED64(*frB, 1, 11) < 1151) { label = Normal_Operand; break; } + if (EXTRACTED64(*frB, 1, 63) == 0) { label = Zero_Operand; break; } + if (EXTRACTED64(*frB, 1, 11) == 2047) { + if (EXTRACTED64(*frB, 12, 63) == 0) { label = Infinity_Operand; break; } + if (EXTRACTED64(*frB, 12, 12) == 1) { label = QNaN_Operand; break; } + if (EXTRACTED64(*frB, 12, 12) == 0 + && EXTRACTED64(*frB, 13, 63) > 0) { label = SNaN_Operand; break; } + } + case Disabled_Exponent_Underflow: sign = EXTRACTED64(*frB, 0, 0); if (EXTRACTED64(*frB, 1, 11) == 0) { exp = -1022; @@ -4091,8 +4077,8 @@ void::function::invalid_arithemetic_operation:cpu *processor, unsigned_word cia, | INSERTED64(exp + 1023, 1, 11) | INSERTED64(EXTRACTED64(frac_grx, 1, 52), 12, 63)); } - goto Done; - Enabled_Exponent_Underflow: + { label = Done; break; } + case Enabled_Exponent_Underflow: FPSCR_SET_UX(1); sign = EXTRACTED64(*frB, 0, 0); if (EXTRACTED64(*frB, 1, 11) == 0) { @@ -4117,8 +4103,8 @@ void::function::invalid_arithemetic_operation:cpu *processor, unsigned_word cia, | INSERTED64(EXTRACTED64(frac_grx, 1, 52), 12, 63)); if (sign == 0) FPSCR_SET_FPRF(fpscr_rf_pos_normal_number); if (sign == 1) FPSCR_SET_FPRF(fpscr_rf_neg_normal_number); - goto Done; - Disabled_Exponent_Overflow: + { label = Done; break; } + case Disabled_Exponent_Overflow: FPSCR_SET_OX(1); if ((FPSCR & fpscr_rn) == fpscr_rn_round_to_nearest) { if (EXTRACTED64(*frB, 0, 0) == 0) { @@ -4163,43 +4149,43 @@ void::function::invalid_arithemetic_operation:cpu *processor, unsigned_word cia, /* FPSCR[FR] <- undefined */ FPSCR_SET_FI(1); FPSCR_SET_XX(1); - goto Done; - Enabled_Exponent_Overflow: + { label = Done; break; } + case Enabled_Exponent_Overflow: sign = EXTRACTED64(*frB, 0, 0); exp = EXTRACTED64(*frB, 1, 11) - 1023; frac_grx = BIT64(0) | INSERTED64(EXTRACTED64(*frB, 12, 63), 1, 52); Round_Single(processor, sign, &exp, &frac_grx); FPSCR_SET_XX(FPSCR & fpscr_fi); - Enabled_Overflow: - FPSCR_SET_OX(1); - exp = exp - 192; - *frT = (INSERTED64(sign, 0, 0) - | INSERTED64(exp + 1023, 1, 11) - | INSERTED64(EXTRACTED64(frac_grx, 1, 52), 12, 63)); - if (sign == 0) FPSCR_SET_FPRF(fpscr_rf_pos_normal_number); - if (sign == 1) FPSCR_SET_FPRF(fpscr_rf_neg_normal_number); - goto Done; - Zero_Operand: + case Enabled_Overflow: + FPSCR_SET_OX(1); + exp = exp - 192; + *frT = (INSERTED64(sign, 0, 0) + | INSERTED64(exp + 1023, 1, 11) + | INSERTED64(EXTRACTED64(frac_grx, 1, 52), 12, 63)); + if (sign == 0) FPSCR_SET_FPRF(fpscr_rf_pos_normal_number); + if (sign == 1) FPSCR_SET_FPRF(fpscr_rf_neg_normal_number); + { label = Done; break; } + case Zero_Operand: *frT = *frB; if (EXTRACTED64(*frB, 0, 0) == 0) FPSCR_SET_FPRF(fpscr_rf_pos_zero); if (EXTRACTED64(*frB, 0, 0) == 1) FPSCR_SET_FPRF(fpscr_rf_neg_zero); FPSCR_SET_FR(0); FPSCR_SET_FI(0); - goto Done; - Infinity_Operand: + { label = Done; break; } + case Infinity_Operand: *frT = *frB; if (EXTRACTED64(*frB, 0, 0) == 0) FPSCR_SET_FPRF(fpscr_rf_pos_infinity); if (EXTRACTED64(*frB, 0, 0) == 1) FPSCR_SET_FPRF(fpscr_rf_neg_infinity); FPSCR_SET_FR(0); FPSCR_SET_FI(0); - goto Done; - QNaN_Operand: + { label = Done; break; } + case QNaN_Operand: *frT = INSERTED64(EXTRACTED64(*frB, 0, 34), 0, 34); FPSCR_SET_FPRF(fpscr_rf_quiet_nan); FPSCR_SET_FR(0); FPSCR_SET_FI(0); - goto Done; - SNaN_Operand: + { label = Done; break; } + case SNaN_Operand: FPSCR_OR_VX(fpscr_vxsnan); if ((FPSCR & fpscr_ve) == 0) { *frT = (MASKED64(*frB, 0, 11) @@ -4209,23 +4195,25 @@ void::function::invalid_arithemetic_operation:cpu *processor, unsigned_word cia, } FPSCR_SET_FR(0); FPSCR_SET_FI(0); - goto Done; - Normal_Operand: + { label = Done; break; } + case Normal_Operand: sign = EXTRACTED64(*frB, 0, 0); exp = EXTRACTED64(*frB, 1, 11) - 1023; frac_grx = BIT64(0) | INSERTED64(EXTRACTED64(*frB, 12, 63), 1, 52); Round_Single(processor, sign, &exp, &frac_grx); FPSCR_SET_XX(FPSCR & fpscr_fi); - if (exp > 127 && (FPSCR & fpscr_oe) == 0) goto Disabled_Exponent_Overflow; - if (exp > 127 && (FPSCR & fpscr_oe) != 0) goto Enabled_Overflow; + if (exp > 127 && (FPSCR & fpscr_oe) == 0) { label = Disabled_Exponent_Overflow; break; } + if (exp > 127 && (FPSCR & fpscr_oe) != 0) { label = Enabled_Overflow; break; } *frT = (INSERTED64(sign, 0, 0) | INSERTED64(exp + 1023, 1, 11) | INSERTED64(EXTRACTED64(frac_grx, 1, 52), 12, 63)); if (sign == 0) FPSCR_SET_FPRF(fpscr_rf_pos_normal_number); if (sign == 1) FPSCR_SET_FPRF(fpscr_rf_neg_normal_number); - goto Done; - Done: - PPC_INSN_FLOAT(FRT_BITMASK, FRB_BITMASK, Rc); + { label = Done; break; } + case Done: + PPC_INSN_FLOAT(FRT_BITMASK, FRB_BITMASK, Rc); + { label = finish; break; } + } 0.63,6.FRT,11./,16.FRB,21.814,31.Rc:X:64,f::Floating Convert To Integer Doubleword @@ -4249,30 +4237,37 @@ void::function::invalid_arithemetic_operation:cpu *processor, unsigned_word cia, int sign = EXTRACTED64(*frB, 0, 0); int exp = 63; unsigned64 frac = *frB; - if (frac == 0) goto Zero_Operand; - if (sign == 1) frac = ~frac + 1; - while (EXTRACTED64(frac, 0, 0) == 0) { - /*??? do the loop 0 times if (FRB) = max negative integer */ - frac = INSERTED64(EXTRACTED64(frac, 1, 63), 0, 62); - exp = exp - 1; - } - Round_Float(processor, sign, &exp, &frac, FPSCR & fpscr_rn); - if (sign == 0) FPSCR_SET_FPRF(fpscr_rf_pos_normal_number); - if (sign == 1) FPSCR_SET_FPRF(fpscr_rf_pos_normal_number); - *frT = (INSERTED64(sign, 0, 0) - | INSERTED64(exp + 1023, 1, 11) - | INSERTED64(EXTRACTED64(frac, 1, 52), 12, 63)); - goto Done; + enum { start, finish, Zero_Operand, Done } label = start; + while (label != finish) switch (label) { + case finish: + error("Unhandled switch\n"); + case start: + if (frac == 0) { label = Zero_Operand; break; } + if (sign == 1) frac = ~frac + 1; + while (EXTRACTED64(frac, 0, 0) == 0) { + /*??? do the loop 0 times if (FRB) = max negative integer */ + frac = INSERTED64(EXTRACTED64(frac, 1, 63), 0, 62); + exp = exp - 1; + } + Round_Float(processor, sign, &exp, &frac, FPSCR & fpscr_rn); + if (sign == 0) FPSCR_SET_FPRF(fpscr_rf_pos_normal_number); + if (sign == 1) FPSCR_SET_FPRF(fpscr_rf_pos_normal_number); + *frT = (INSERTED64(sign, 0, 0) + | INSERTED64(exp + 1023, 1, 11) + | INSERTED64(EXTRACTED64(frac, 1, 52), 12, 63)); + { label = Done; break; } /**/ - Zero_Operand: + case Zero_Operand: FPSCR_SET_FR(0); FPSCR_SET_FI(0); FPSCR_SET_FPRF(fpscr_rf_pos_zero); *frT = 0; - goto Done; + { label = Done; break; } /**/ - Done: - PPC_INSN_FLOAT(FRT_BITMASK, FRB_BITMASK, Rc); + case Done: + PPC_INSN_FLOAT(FRT_BITMASK, FRB_BITMASK, Rc); + { label = finish; break; } + } # # I.4.6.7 Floating-Point Compare Instructions @@ -4487,6 +4482,7 @@ void::function::invalid_arithemetic_operation:cpu *processor, unsigned_word cia, | MASKED(SRR1, 48, 63)); NIA = MASKED(SRR0, 0, 61); cpu_synchronize_context(processor); + check_masked_interrupts(processor); } # @@ -4503,8 +4499,10 @@ void::function::invalid_arithemetic_operation:cpu *processor, unsigned_word cia, if (IS_PROBLEM_STATE(processor)) program_interrupt(processor, cia, privileged_instruction_program_interrupt); - else + else { MSR = *rS; + check_masked_interrupts(processor); + } 0.31,6.RT,11./,16./,21.83,31./:X:::Move From Machine State Register *601: PPC_UNIT_IU, PPC_UNIT_IU, 1, 1, 0 @@ -4514,8 +4512,10 @@ void::function::invalid_arithemetic_operation:cpu *processor, unsigned_word cia, if (IS_PROBLEM_STATE(processor)) program_interrupt(processor, cia, privileged_instruction_program_interrupt); - else + else { *rT = MSR; + check_masked_interrupts(processor); + } # @@ -4591,11 +4591,37 @@ void::function::invalid_arithemetic_operation:cpu *processor, unsigned_word cia, 0.31,6./,11./,16./,21.498,31./:X:64::SLB Invalidate All 0.31,6./,11./,16.RB,21.306,31./:X:::TLB Invalidate Entry + if (IS_PROBLEM_STATE(processor)) + program_interrupt(processor, cia, + privileged_instruction_program_interrupt); + else { + int nr = 0; + cpu *proc; + while (1) { + proc = psim_cpu(cpu_system(processor), nr); + if (proc == NULL) break; + cpu_page_tlb_invalidate_entry(proc, *rB); + nr++; + } + } 0.31,6./,11./,16./,21.370,31./:X:::TLB Invalidate All + if (IS_PROBLEM_STATE(processor)) + program_interrupt(processor, cia, + privileged_instruction_program_interrupt); + else { + int nr = 0; + cpu *proc; + while (1) { + proc = psim_cpu(cpu_system(processor), nr); + if (proc == NULL) break; + cpu_page_tlb_invalidate_all(proc); + nr++; + } + } -0.31,6./,11./,16./,21.566,31./:X:::TLB Sychronize - +0.31,6./,11./,16./,21.566,31./:X:::TLB Synchronize + /* nothing happens here - always in sync */ # # III.A.1.2 External Access Instructions diff --git a/sim/ppc/ppc-opcode-complex b/sim/ppc/ppc-opcode-complex index 0435846005a..333c6ae8474 100644 --- a/sim/ppc/ppc-opcode-complex +++ b/sim/ppc/ppc-opcode-complex @@ -17,79 +17,11 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # -# Instruction decode: -# -# The table that follows is used by gen to construct a decision tree -# that can identify each possible instruction. Gen then outputs this -# decision tree as (according to config) a table or switch statement -# as the function idecode. -# -# In parallel to this, as mentioned above, WITH_EXPANDED_SEMANTICS -# determines of the semantic functions themselves should be expanded -# in a similar way. -# -# The table contains the following entries: -# -# -# -# Must be 1 for the entry to be considered. The last entry must be -# zero. -# -# -# -# -# Range of bits (within the instruction) that should be searched for -# an instruction field. Within such ranges, gen looks for opcodes -# (constants), registers (strings) and reserved bits (slash) and -# according to the rules that follows includes or excludes them from -# a possible instruction field. -# -# -# -# -# If an instructioin field was found, enlarge the field size so that -# it is forced to at least include bits starting from -# (). To stop this occuring, use = -# + 1 and = - 1. -# -# -# -# Treat `/' fields as a constant instead of variable when looking for -# an instruction field. -# -# -# -# Treat any contained register (string) fields as constant when -# determining the instruction field. For the instruction decode (and -# controled by IDECODE_EXPAND_SEMANTICS) this forces the expansion of -# what would otherwize be non constant bits of an instruction. -# -# -# -# Should this table be expanded using a switch statement (val 1) and -# if so, should it be padded with entries so as to force the compiler -# to generate a jump table (val 2). -# -# -# -# -# -# Special rule to fine tune how specific (or groups) of instructions -# are expanded. The applicability of the rule is determined by -# -# != 0 && (instruction> & ) == -# -# Where is obtained by looking only at constant fields -# with in an instructions spec. When determining an expansion, the -# rule is only considered when a node contains a single instruction. -# can be any of: -# -# 0: for this instruction, expand by earlier rules -# 1: expand bits .. only -# 2: boolean expansion of only zero/non-zero cases -# - 0: 5: 0: 5:0:: 0:0x00000000:0x00000000:0 -21:31:32:-1:0:OE,LR,AA,Rc,LK:0:0x00000000:0x00000000:0 - 6: 9: 6: 9:0:BO: 0:0xfc000000:0x40000000:1 -11:15:11:15:0:RA: 0:0xfc000000:0x38000000:2 -11:15:11:15:0:RA: 0:0xfc000000:0x3c000000:2 +array,normal: 0: 5: 0: 5: +array,normal: 21:31:32:-1:OE,LR,AA,Rc,LK: +array,expand-forced: 6: 9: 6: 9:BO: 0xfc000000:0x40000000 +array,boolean: 11:15:11:15:0RA: 0xfc000000:0x38000000:0 +array,boolean: 11:15:11:15:RA: 0xfc000000:0x3c000000:0 +# BLR instruction - LR=8 is munged into 0x100 +array,boolean: 11:20:11:20:SPR: 0xfc0007ff:0x7c0003a6:0x100 +array,boolean: 11:20:11:20:SPR: 0xfc0007ff:0x7c0002a6:0x100 diff --git a/sim/ppc/ppc-opcode-flat b/sim/ppc/ppc-opcode-flat index 21079f845e9..54a84339577 100644 --- a/sim/ppc/ppc-opcode-flat +++ b/sim/ppc/ppc-opcode-flat @@ -17,79 +17,13 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # -# Instruction decode: -# -# The table that follows is used by gen to construct a decision tree -# that can identify each possible instruction. Gen then outputs this -# decision tree as (according to config) a table or switch statement -# as the function idecode. -# -# In parallel to this, as mentioned above, WITH_EXPANDED_SEMANTICS -# determines of the semantic functions themselves should be expanded -# in a similar way. -# -# The table contains the following entries: -# -# -# -# Must be 1 for the entry to be considered. The last entry must be -# zero. -# -# -# -# -# Range of bits (within the instruction) that should be searched for -# an instruction field. Within such ranges, gen looks for opcodes -# (constants), registers (strings) and reserved bits (slash) and -# according to the rules that follows includes or excludes them from -# a possible instruction field. -# -# -# -# -# If an instructioin field was found, enlarge the field size so that -# it is forced to at least include bits starting from -# (). To stop this occuring, use = -# + 1 and = - 1. -# -# -# -# Treat `/' fields as a constant instead of variable when looking for -# an instruction field. -# -# -# -# Treat any contained register (string) fields as constant when -# determining the instruction field. For the instruction decode (and -# controled by IDECODE_EXPAND_SEMANTICS) this forces the expansion of -# what would otherwize be non constant bits of an instruction. -# -# -# -# Should this table be expanded using a switch statement (val 1) and -# if so, should it be padded with entries so as to force the compiler -# to generate a jump table (val 2). -# -# -# -# -# -# Special rule to fine tune how specific (or groups) of instructions -# are expanded. The applicability of the rule is determined by -# -# != 0 && (instruction> & ) == -# -# Where is obtained by looking only at constant fields -# with in an instructions spec. When determining an expansion, the -# rule is only considered when a node contains a single instruction. -# can be any of: -# -# 0: for this instruction, expand by earlier rules -# 1: expand bits .. only -# 2: boolean expansion of only zero/non-zero cases -# - 0: 5: 0: 5:0:: 2:0x00000000:0x00000000:0 -21:31:32:-1:0:OE,LR,AA,Rc,LK:1:0x00000000:0x00000000:0 - 6: 9: 6: 9:0:BO: 1:0xfc000000:0x40000000:1 -11:15:11:15:0:RA: 1:0xfc000000:0x38000000:2 -11:15:11:15:0:RA: 1:0xfc000000:0x3c000000:2 +# sed < ppc-opcode-complex > ppc-opcode-flat -e 's/array/switch/' +# +padded-switch,normal: 0: 5: 0: 5: +padded-switch,normal: 21:31:32:-1:OE,LR,AA,Rc,LK: +padded-switch,expand-forced: 6: 9: 6: 9:BO: 0xfc000000:0x40000000 +switch,boolean: 11:15:11:15:0RA: 0xfc000000:0x38000000:0 +switch,boolean: 11:15:11:15:RA: 0xfc000000:0x3c000000:0 +# BLR instruction +switch,boolean: 11:20:11:20:SPR: 0xfc0007ff:0x7c0003a6:0x100 +switch,boolean: 11:20:11:20:SPR: 0xfc0007ff:0x7c0002a6:0x100 diff --git a/sim/ppc/ppc-opcode-jump b/sim/ppc/ppc-opcode-jump new file mode 100644 index 00000000000..1851887bfc6 --- /dev/null +++ b/sim/ppc/ppc-opcode-jump @@ -0,0 +1,21 @@ +# +# This file is part of the program psim. +# +# Copyright (C) 1994-1995, Andrew Cagney +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +array: 0: 5: 0: 5 +array:21:31 diff --git a/sim/ppc/ppc-opcode-simple b/sim/ppc/ppc-opcode-simple index b3a1316711a..9ea823e66c0 100644 --- a/sim/ppc/ppc-opcode-simple +++ b/sim/ppc/ppc-opcode-simple @@ -17,76 +17,9 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # -# Instruction decode: # -# The table that follows is used by gen to construct a decision tree -# that can identify each possible instruction. Gen then outputs this -# decision tree as (according to config) a table or switch statement -# as the function idecode. +# Create a two level switch statement. The first level branches on bits +# 0..5 while the second level branches on bits 21..31 # -# In parallel to this, as mentioned above, WITH_EXPANDED_SEMANTICS -# determines of the semantic functions themselves should be expanded -# in a similar way. -# -# The table contains the following entries: -# -# -# -# Must be 1 for the entry to be considered. The last entry must be -# zero. -# -# -# -# -# Range of bits (within the instruction) that should be searched for -# an instruction field. Within such ranges, gen looks for opcodes -# (constants), registers (strings) and reserved bits (slash) and -# according to the rules that follows includes or excludes them from -# a possible instruction field. -# -# -# -# -# If an instructioin field was found, enlarge the field size so that -# it is forced to at least include bits starting from -# (). To stop this occuring, use = -# + 1 and = - 1. -# -# -# -# Treat `/' fields as a constant instead of variable when looking for -# an instruction field. -# -# -# -# Treat any contained register (string) fields as constant when -# determining the instruction field. For the instruction decode (and -# controled by IDECODE_EXPAND_SEMANTICS) this forces the expansion of -# what would otherwize be non constant bits of an instruction. -# -# -# -# Should this table be expanded using a switch statement (val 1) and -# if so, should it be padded with entries so as to force the compiler -# to generate a jump table (val 2). -# -# -# -# -# -# Special rule to fine tune how specific (or groups) of instructions -# are expanded. The applicability of the rule is determined by -# -# != 0 && (instruction> & ) == -# -# Where is obtained by looking only at constant fields -# with in an instructions spec. When determining an expansion, the -# rule is only considered when a node contains a single instruction. -# can be any of: -# -# 0: for this instruction, expand by earlier rules -# 1: expand bits .. only -# 2: boolean expansion of only zero/non-zero cases -# - 0: 5: 0: 5:0:: 1:0x00000000:0x00000000:0 -21:31:32:-1:0:: 1:0x00000000:0x00000000:0 +switch: 0: 5: 0: 5 +switch:21:31 diff --git a/sim/ppc/ppc-opcode-stupid b/sim/ppc/ppc-opcode-stupid index 39795c87baa..849379101e1 100644 --- a/sim/ppc/ppc-opcode-stupid +++ b/sim/ppc/ppc-opcode-stupid @@ -16,77 +16,6 @@ # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -# Instruction decode: -# -# The table that follows is used by gen to construct a decision tree -# that can identify each possible instruction. Gen then outputs this -# decision tree as (according to config) a table or switch statement -# as the function idecode. -# -# In parallel to this, as mentioned above, WITH_EXPANDED_SEMANTICS -# determines of the semantic functions themselves should be expanded -# in a similar way. -# -# The table contains the following entries: -# -# -# -# Must be 1 for the entry to be considered. The last entry must be -# zero. -# -# -# -# -# Range of bits (within the instruction) that should be searched for -# an instruction field. Within such ranges, gen looks for opcodes -# (constants), registers (strings) and reserved bits (slash) and -# according to the rules that follows includes or excludes them from -# a possible instruction field. -# -# -# -# -# If an instructioin field was found, enlarge the field size so that -# it is forced to at least include bits starting from -# (). To stop this occuring, use = -# + 1 and = - 1. -# -# -# -# Treat `/' fields as a constant instead of variable when looking for -# an instruction field. -# -# -# -# Treat any contained register (string) fields as constant when -# determining the instruction field. For the instruction decode (and -# controled by IDECODE_EXPAND_SEMANTICS) this forces the expansion of -# what would otherwize be non constant bits of an instruction. -# -# -# -# Should this table be expanded using a switch statement (val 1) and -# if so, should it be padded with entries so as to force the compiler -# to generate a jump table (val 2). -# -# -# -# -# -# Special rule to fine tune how specific (or groups) of instructions -# are expanded. The applicability of the rule is determined by -# -# != 0 && (instruction> & ) == -# -# Where is obtained by looking only at constant fields -# with in an instructions spec. When determining an expansion, the -# rule is only considered when a node contains a single instruction. -# can be any of: -# -# 0: for this instruction, expand by earlier rules -# 1: expand bits .. only -# 2: boolean expansion of only zero/non-zero cases # 0: 5: 0: 5:0:0: 0:0x00000000:0x00000000:0 21:31:32:-1:0:OE,LR,AA,Rc,LK:0:0x00000000:0x00000000:0 diff --git a/sim/ppc/ppc-opcode-test-1 b/sim/ppc/ppc-opcode-test-1 index 00b7f2cfba8..df8c175cc0d 100644 --- a/sim/ppc/ppc-opcode-test-1 +++ b/sim/ppc/ppc-opcode-test-1 @@ -16,77 +16,6 @@ # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -# Instruction decode: -# -# The table that follows is used by gen to construct a decision tree -# that can identify each possible instruction. Gen then outputs this -# decision tree as (according to config) a table or switch statement -# as the function idecode. -# -# In parallel to this, as mentioned above, WITH_EXPANDED_SEMANTICS -# determines of the semantic functions themselves should be expanded -# in a similar way. -# -# The table contains the following entries: -# -# -# -# Must be 1 for the entry to be considered. The last entry must be -# zero. -# -# -# -# -# Range of bits (within the instruction) that should be searched for -# an instruction field. Within such ranges, gen looks for opcodes -# (constants), registers (strings) and reserved bits (slash) and -# according to the rules that follows includes or excludes them from -# a possible instruction field. -# -# -# -# -# If an instructioin field was found, enlarge the field size so that -# it is forced to at least include bits starting from -# (). To stop this occuring, use = -# + 1 and = - 1. -# -# -# -# Treat `/' fields as a constant instead of variable when looking for -# an instruction field. -# -# -# -# Treat any contained register (string) fields as constant when -# determining the instruction field. For the instruction decode (and -# controled by IDECODE_EXPAND_SEMANTICS) this forces the expansion of -# what would otherwize be non constant bits of an instruction. -# -# -# -# Should this table be expanded using a switch statement (val 1) and -# if so, should it be padded with entries so as to force the compiler -# to generate a jump table (val 2). -# -# -# -# -# -# Special rule to fine tune how specific (or groups) of instructions -# are expanded. The applicability of the rule is determined by -# -# != 0 && (instruction> & ) == -# -# Where is obtained by looking only at constant fields -# with in an instructions spec. When determining an expansion, the -# rule is only considered when a node contains a single instruction. -# can be any of: -# -# 0: for this instruction, expand by earlier rules -# 1: expand bits .. only -# 2: boolean expansion of only zero/non-zero cases # 0: 5: 0: 5:0:: 2:0x00000000:0x00000000:0 21:31:32:-1:0:OE,LR,AA,Rc,LK:0:0x00000000:0x00000000:0 diff --git a/sim/ppc/ppc-opcode-test-2 b/sim/ppc/ppc-opcode-test-2 index 1af4bebfb66..a98d0a78e2c 100644 --- a/sim/ppc/ppc-opcode-test-2 +++ b/sim/ppc/ppc-opcode-test-2 @@ -16,77 +16,6 @@ # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -# Instruction decode: -# -# The table that follows is used by gen to construct a decision tree -# that can identify each possible instruction. Gen then outputs this -# decision tree as (according to config) a table or switch statement -# as the function idecode. -# -# In parallel to this, as mentioned above, WITH_EXPANDED_SEMANTICS -# determines of the semantic functions themselves should be expanded -# in a similar way. -# -# The table contains the following entries: -# -# -# -# Must be 1 for the entry to be considered. The last entry must be -# zero. -# -# -# -# -# Range of bits (within the instruction) that should be searched for -# an instruction field. Within such ranges, gen looks for opcodes -# (constants), registers (strings) and reserved bits (slash) and -# according to the rules that follows includes or excludes them from -# a possible instruction field. -# -# -# -# -# If an instructioin field was found, enlarge the field size so that -# it is forced to at least include bits starting from -# (). To stop this occuring, use = -# + 1 and = - 1. -# -# -# -# Treat `/' fields as a constant instead of variable when looking for -# an instruction field. -# -# -# -# Treat any contained register (string) fields as constant when -# determining the instruction field. For the instruction decode (and -# controled by IDECODE_EXPAND_SEMANTICS) this forces the expansion of -# what would otherwize be non constant bits of an instruction. -# -# -# -# Should this table be expanded using a switch statement (val 1) and -# if so, should it be padded with entries so as to force the compiler -# to generate a jump table (val 2). -# -# -# -# -# -# Special rule to fine tune how specific (or groups) of instructions -# are expanded. The applicability of the rule is determined by -# -# != 0 && (instruction> & ) == -# -# Where is obtained by looking only at constant fields -# with in an instructions spec. When determining an expansion, the -# rule is only considered when a node contains a single instruction. -# can be any of: -# -# 0: for this instruction, expand by earlier rules -# 1: expand bits .. only -# 2: boolean expansion of only zero/non-zero cases # 0: 5: 0: 5:0:: 0:0x00000000:0x00000000:0 21:31:32:-1:0:OE,LR,AA,Rc,LK:0:0x00000000:0x00000000:0 diff --git a/sim/ppc/psim.c b/sim/ppc/psim.c index 2a89782deb2..0c7024e50cd 100644 --- a/sim/ppc/psim.c +++ b/sim/ppc/psim.c @@ -22,7 +22,10 @@ #ifndef _PSIM_C_ #define _PSIM_C_ -#include "inline.c" +#include "cpu.h" /* includes psim.h */ +#include "idecode.h" +#include "options.h" + #include #include @@ -33,10 +36,6 @@ #include -#include "cpu.h" /* includes psim.h */ -#include "idecode.h" -#include "options.h" - #ifdef HAVE_STRING_H #include #else @@ -45,6 +44,7 @@ #endif #endif + #include "bfd.h" @@ -87,7 +87,7 @@ INLINE_PSIM\ (device *) psim_tree(void) { - device *root = core_device_create(); + device *root = device_tree_add_parsed(NULL, "core"); device_tree_add_parsed(root, "/aliases"); device_tree_add_parsed(root, "/options"); device_tree_add_parsed(root, "/chosen"); @@ -245,7 +245,8 @@ psim_options(device *root, argp += 1; } /* force the trace node to (re)process its options */ - device_init_data(device_tree_find_device(root, "/openprom/trace"), NULL); + device_ioctl(device_tree_find_device(root, "/openprom/trace"), NULL, 0); + /* return where the options end */ return argv + argp; } @@ -345,7 +346,7 @@ psim_create(const char *file_name, /* create things */ system = ZALLOC(psim); system->events = event_queue_create(); - system->memory = core_create(root); + system->memory = core_from_device(root); system->monitor = mon_create(); system->nr_cpus = nr_cpus; system->os_emulation = os_emulation; @@ -373,7 +374,7 @@ psim_create(const char *file_name, /* allow the simulation to stop/restart abnormaly */ -STATIC_INLINE_PSIM\ +INLINE_PSIM\ (void) psim_set_halt_and_restart(psim *system, void *halt_jmp_buf, @@ -383,7 +384,7 @@ psim_set_halt_and_restart(psim *system, system->path_to_restart = restart_jmp_buf; } -STATIC_INLINE_PSIM\ +INLINE_PSIM\ (void) psim_clear_halt_and_restart(psim *system) { @@ -418,6 +419,20 @@ psim_halt(psim *system, longjmp(*(jmp_buf*)(system->path_to_halt), current_cpu + 1); } +INLINE_PSIM\ +(int) +psim_last_cpu(psim *system) +{ + return system->last_cpu; +} + +INLINE_PSIM\ +(int) +psim_nr_cpus(psim *system) +{ + return system->nr_cpus; +} + INLINE_PSIM\ (psim_status) psim_get_status(psim *system) @@ -463,7 +478,8 @@ psim_init(psim *system) /* scrub the monitor */ mon_init(system->monitor, system->nr_cpus); - os_emul_init(system->os_emulation, system->nr_cpus); + + /* trash any pending events */ event_queue_init(system->events); /* scrub all the cpus */ @@ -473,6 +489,9 @@ psim_init(psim *system) /* init all the devices (which updates the cpus) */ device_tree_init(system->devices, system); + /* and the emulation (which needs an initialized device tree) */ + os_emul_init(system->os_emulation, system->nr_cpus); + /* now sync each cpu against the initialized state of its registers */ for (cpu_nr = 0; cpu_nr < system->nr_cpus; cpu_nr++) { cpu_synchronize_context(system->processors[cpu_nr]); @@ -480,7 +499,7 @@ psim_init(psim *system) } /* force loop to restart */ - system->last_cpu = system->nr_cpus - 1; + system->last_cpu = -1; /* when incremented will become 0 - first CPU */ } INLINE_PSIM\ @@ -497,7 +516,6 @@ psim_stack(psim *system, unsigned_word stack_pointer; psim_read_register(system, 0, &stack_pointer, "sp", cooked_transfer); device_ioctl(stack_device, - system, NULL, /*cpu*/ 0, /*cia*/ stack_pointer, @@ -508,219 +526,6 @@ psim_stack(psim *system, -/* EXECUTE REAL CODE: - - Unfortunatly, there are multiple cases to consider vis: - - X X X X ... - - Consequently this function is written in multiple different ways */ - -STATIC_INLINE_PSIM\ -(void) -run_until_stop(psim *system, - volatile int *keep_running) -{ - jmp_buf halt; - jmp_buf restart; -#if WITH_IDECODE_CACHE_SIZE - int cpu_nr; - for (cpu_nr = 0; cpu_nr < system->nr_cpus; cpu_nr++) - cpu_flush_icache(system->processors[cpu_nr]); -#endif - psim_set_halt_and_restart(system, &halt, &restart); - -#if (!WITH_IDECODE_CACHE_SIZE && WITH_SMP == 0) - - /* CASE 1: No instruction cache and no SMP. - - In this case, we can take advantage of the fact that the current - instruction address does not need to be returned to the cpu - object after every execution of an instruction. Instead it only - needs to be saved when either A. the main loop exits or B. a - cpu-{halt,restart} call forces the loop to be re-entered. The - later functions always save the current cpu instruction - address. */ - - if (!setjmp(halt)) { - do { - if (!setjmp(restart)) { - cpu *const processor = system->processors[0]; - unsigned_word cia = cpu_get_program_counter(processor); - do { - if (WITH_EVENTS) { - if (event_queue_tick(system->events)) { - cpu_set_program_counter(processor, cia); - event_queue_process(system->events); - cia = cpu_get_program_counter(processor); - } - } - { - instruction_word const instruction - = vm_instruction_map_read(cpu_instruction_map(processor), - processor, cia); - cia = idecode_issue(processor, instruction, cia); - } - } while (keep_running == NULL || *keep_running); - cpu_set_program_counter(processor, cia); - } - } while(keep_running == NULL || *keep_running); - } -#endif - - -#if (WITH_IDECODE_CACHE_SIZE && WITH_SMP == 0) - - /* CASE 2: Instruction case but no SMP - - Here, the additional complexity comes from there being two - different cache implementations. A simple function address cache - or a full cracked instruction cache */ - - if (!setjmp(halt)) { - do { - if (!setjmp(restart)) { - cpu *const processor = system->processors[0]; - unsigned_word cia = cpu_get_program_counter(processor); - do { - if (WITH_EVENTS) - if (event_queue_tick(system->events)) { - cpu_set_program_counter(processor, cia); - event_queue_process(system->events); - cia = cpu_get_program_counter(processor); - } - { - idecode_cache *const cache_entry = cpu_icache_entry(processor, - cia); - if (cache_entry->address == cia) { - idecode_semantic *const semantic = cache_entry->semantic; - cia = semantic(processor, cache_entry, cia); - } - else { - instruction_word const instruction - = vm_instruction_map_read(cpu_instruction_map(processor), - processor, - cia); - idecode_semantic *const semantic = idecode(processor, - instruction, - cia, - cache_entry); - - if (WITH_MON != 0) - mon_event(mon_event_icache_miss, processor, cia); - cache_entry->address = cia; - cache_entry->semantic = semantic; - cia = semantic(processor, cache_entry, cia); - } - } - } while (keep_running == NULL || *keep_running); - cpu_set_program_counter(processor, cia); - } - } while(keep_running == NULL || *keep_running); - } -#endif - - -#if (!WITH_IDECODE_CACHE_SIZE && WITH_SMP > 0) - - /* CASE 3: No ICACHE but SMP - - The complexity here comes from needing to correctly restart the - system when it is aborted. In particular if cpu0 requests a - restart, the next cpu is still cpu1. Cpu0 being restarted after - all the other CPU's and the event queue have been processed */ - - if (!setjmp(halt)) { - int first_cpu = setjmp(restart); - if (first_cpu == 0) - first_cpu = system->last_cpu + 1; - do { - int current_cpu; - for (current_cpu = first_cpu, first_cpu = 0; - current_cpu < system->nr_cpus + (WITH_EVENTS ? 1 : 0); - current_cpu++) { - if (WITH_EVENTS && current_cpu == system->nr_cpus) { - if (event_queue_tick(system->events)) - event_queue_process(system->events); - } - else { - cpu *const processor = system->processors[current_cpu]; - unsigned_word const cia = cpu_get_program_counter(processor); - instruction_word instruction = - vm_instruction_map_read(cpu_instruction_map(processor), - processor, - cia); - cpu_set_program_counter(processor, - idecode_issue(processor, instruction, cia)); - } - if (!(keep_running == NULL || *keep_running)) { - system->last_cpu = current_cpu; - break; - } - } - } while (keep_running == NULL || *keep_running); - } -#endif - -#if (WITH_IDECODE_CACHE_SIZE && WITH_SMP > 0) - - /* CASE 4: ICACHE and SMP ... - - This time, everything goes wrong. Need to restart loops - correctly, need to save the program counter and finally need to - keep track of each processors current address! */ - - if (!setjmp(halt)) { - int first_cpu = setjmp(restart); - if (!first_cpu) - first_cpu = system->last_cpu + 1; - do { - int current_cpu; - for (current_cpu = first_cpu, first_cpu = 0; - current_cpu < system->nr_cpus + (WITH_EVENTS ? 1 : 0); - current_cpu++) { - if (WITH_EVENTS && current_cpu == system->nr_cpus) { - if (event_queue_tick(system->events)) - event_queue_process(system->events); - } - else { - cpu *processor = system->processors[current_cpu]; - unsigned_word const cia = cpu_get_program_counter(processor); - idecode_cache *cache_entry = cpu_icache_entry(processor, cia); - if (cache_entry->address == cia) { - idecode_semantic *semantic = cache_entry->semantic; - cpu_set_program_counter(processor, - semantic(processor, cache_entry, cia)); - } - else { - instruction_word instruction = - vm_instruction_map_read(cpu_instruction_map(processor), - processor, - cia); - idecode_semantic *semantic = idecode(processor, - instruction, - cia, - cache_entry); - - if (WITH_MON != 0) - mon_event(mon_event_icache_miss, system->processors[current_cpu], cia); - cache_entry->address = cia; - cache_entry->semantic = semantic; - cpu_set_program_counter(processor, - semantic(processor, cache_entry, cia)); - } - } - if (!(keep_running == NULL || *keep_running)) - break; - } - } while (keep_running == NULL || *keep_running); - } -#endif - - psim_clear_halt_and_restart(system); -} - - /* SIMULATE INSTRUCTIONS, various different ways of achieving the same thing */ @@ -729,14 +534,16 @@ INLINE_PSIM\ psim_step(psim *system) { volatile int keep_running = 0; - run_until_stop(system, &keep_running); + idecode_run_until_stop(system, &keep_running, + system->events, system->processors, system->nr_cpus); } INLINE_PSIM\ (void) psim_run(psim *system) { - run_until_stop(system, NULL); + idecode_run(system, + system->events, system->processors, system->nr_cpus); } INLINE_PSIM\ @@ -744,7 +551,8 @@ INLINE_PSIM\ psim_run_until_stop(psim *system, volatile int *keep_running) { - run_until_stop(system, keep_running); + idecode_run_until_stop(system, keep_running, + system->events, system->processors, system->nr_cpus); } @@ -806,6 +614,23 @@ psim_read_register(psim *system, *(msreg*)cooked_buf = cpu_registers(processor)->msr; break; + case reg_insns: + *(unsigned_word*)cooked_buf = mon_get_number_of_insns(system->monitor, + which_cpu); + break; + + case reg_stalls: + if (cpu_model(processor) == NULL) + error("$stalls only valid if processor unit model enabled (-I)\n"); + *(unsigned_word*)cooked_buf = model_get_number_of_stalls(cpu_model(processor)); + break; + + case reg_cycles: + if (cpu_model(processor) == NULL) + error("$cycles only valid if processor unit model enabled (-I)\n"); + *(unsigned_word*)cooked_buf = model_get_number_of_cycles(cpu_model(processor)); + break; + default: printf_filtered("psim_read_register(processor=0x%lx,buf=0x%lx,reg=%s) %s\n", (unsigned long)processor, (unsigned long)buf, reg, diff --git a/sim/ppc/sim_calls.c b/sim/ppc/sim_calls.c index c2cef9a4897..6fdca6a3aa6 100644 --- a/sim/ppc/sim_calls.c +++ b/sim/ppc/sim_calls.c @@ -1,6 +1,6 @@ /* This file is part of the program psim. - Copyright (C) 1994-1995, Andrew Cagney + Copyright (C) 1994-1996, Andrew Cagney This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -23,7 +23,6 @@ #include #include -#include "cpu.h" #include "psim.h" #include "options.h" @@ -41,8 +40,6 @@ #include "../../gdb/defs.h" -#include "devices.h" - #include "../../gdb/remote-sim.h" #include "../../gdb/callback.h" @@ -50,79 +47,30 @@ /* Structures used by the simulator, for gdb just have static structures */ static psim *simulator; -static char *register_names[] = REGISTER_NAMES; -static int print_info = 0; +static device *root_device; +static const char *register_names[] = REGISTER_NAMES; void sim_open (char *args) { + /* Note: The simulation is not created by sim_open() because + complete information is not yet available */ /* trace the call */ TRACE(trace_gdb, ("sim_open(args=%s) called\n", args ? args : "(null)")); + if (root_device != NULL) + printf_filtered("Warning - re-open of simulator leaks memory\n"); + root_device = psim_tree(); + simulator = NULL; + if (args) { char **argv = buildargv(args); - int argp = 0; - int argc; - for (argc = 0; argv[argc]; argc++); - - while (argp < argc) { - if (*argv[argp] != '-') - error ("Argument is not an option '%s'", argv[argp]); - - else { - /* check arguments -- note, main.c also contains argument processing - code for the standalone emulator. */ - char *p = argv[argp] + 1; - while (*p != '\0') { - switch (*p) { - default: - printf_filtered("Usage:\n\ttarget sim [ -t ] [-m model] [-i] [-I]\n"); - trace_usage(); - error (""); - break; - case 't': - if (p[1]) - trace_option(p+1); - else { - argp += 1; - if (argv[argp] == NULL) - error("Missing option for -t\n"); - else - trace_option(argv[argp]); - } - break; - case 'm': - if (p[1]) - model_set(p+1); - else { - argp += 1; - if (argv[argp] == NULL) - error("Missing option for -t\n"); - else - model_set(argv[argp]); - } - break; - case 'i': - print_info = 1; - break; - case 'I': - current_model_issue = MODEL_ISSUE_PROCESS; - print_info = 2; - break; - } - p += 1; - } - } - argp += 1; - } + psim_options(root_device, argv); + freeargv(argv); } if (ppc_trace[trace_opts]) print_options (); - - /* do something */ - TRACE(trace_tbd, ("sim_open() - TBD - should parse the arguments\n")); - TRACE(trace_tbd, ("sim_open() - TBD - can not create simulator here as do not have description of it\n")); } @@ -130,10 +78,8 @@ void sim_close (int quitting) { TRACE(trace_gdb, ("sim_close(quitting=%d) called\n", quitting)); - if (print_info) - psim_print_info (simulator, print_info); - - /* nothing to do */ + if (ppc_trace[trace_print_info] && simulator != NULL) + psim_print_info (simulator, ppc_trace[trace_print_info]); } @@ -151,7 +97,7 @@ sim_load (char *prog, int from_tty) /* create the simulator */ TRACE(trace_gdb, ("sim_load() - first time, create the simulator\n")); - simulator = psim_create(argv[0]); + simulator = psim_create(argv[0], root_device); /* bring in all the data section */ psim_init(simulator); @@ -323,9 +269,15 @@ sim_resume (int step, int siggnal) } void -sim_do_command(char *cmd) +sim_do_command (char *cmd) { - TRACE(trace_gdb, ("sim_do_commands(cmd=%s) called\n", cmd)); + TRACE(trace_gdb, ("sim_do_commands(cmd=%s) called\n", + cmd ? cmd : "(null)")); + if (cmd) { + char **argv = buildargv(cmd); + psim_options(root_device, argv); + freeargv(argv); + } } void @@ -350,3 +302,8 @@ void zfree(void *data) { mfree(NULL, data); } + +void flush_stdoutput(void) +{ + gdb_flush (gdb_stdout); +} diff --git a/sim/ppc/std-config.h b/sim/ppc/std-config.h index 2ee1ecc8f85..76750f941cb 100644 --- a/sim/ppc/std-config.h +++ b/sim/ppc/std-config.h @@ -287,6 +287,15 @@ extern int current_model_issue; ? WITH_MODEL_ISSUE \ : current_model_issue) +/* Whether or not input/output just uses stdio, or uses printf_filtered for + output, and polling input for input. */ +#define DONT_USE_STDIO 0 +#define DO_USE_STDIO 1 + +#ifndef WITH_STDIO +#define WITH_STDIO DONT_USE_STDIO +#endif + /* INLINE CODE SELECTION: GCC -O3 attempts to inline any function or procedure in scope. The @@ -308,18 +317,30 @@ extern int current_model_issue; The following additional values are `bit fields' and can be combined. - 1 Include the C file for the module into the file being compiled + REVEAL_MODULE: + + Include the C file for the module into the file being compiled but do not make the functions within the module inline. While of no apparent benefit, this makes it possible for the included module, when compiled to inline its calls to what would otherwize be external functions. - 2 Make external functions within the module `inline'. Thus if + INLINE_MODULE: + + Make external functions within the module `inline'. Thus if the module is included into a file being compiled, calls to its funtions can be eliminated. 2 implies 1. - 4 Make internal (static) functions within the module `inline'. + INLINE_LOCALS: + + Make internal (static) functions within the module `inline'. + + The following abreviations are available: + + INCLUDE_MODULE == (REVEAL_MODULE | INLINE_MODULE) + + ALL_INLINE == (REVEAL_MODULE | INLINE_MODULE | INLINE_LOCALS) In addition to this, modules have been put into two categories. @@ -401,7 +422,7 @@ extern int current_model_issue; REALITY CHECK: - This is not for the faint hearted. I've seen GCC get up to 200mb + This is not for the faint hearted. I've seen GCC get up to 500mb trying to compile what this can create. Some of the modules do not yet implement the WITH_INLINE_STATIC @@ -433,6 +454,18 @@ extern int current_model_issue; #endif #endif +/* Your compilers pass parameters in registers reserved word */ + +#if !defined REGPARM +#if (defined(i386) || defined(i486) || defined(i586) || defined(__i386__) || defined(__i486__) || defined(__i586__)) && WITH_REGPARM +#define REGPARM __attribute__((__regparm__(WITH_REGPARM))) +#else +#define REGPARM +#endif +#endif + + + /* Default prefix for static functions */ #ifndef STATIC_INLINE @@ -513,14 +546,10 @@ extern int current_model_issue; real hardware instead of RAM. Also, most of the functions in devices.c are always called through - a jump table. - - There seems to be some problem with making either device_tree or - devices inline. It reports the message: device_tree_find_node() - not a leaf */ + a jump table. */ #ifndef DEVICE_INLINE -#define DEVICE_INLINE DEFAULT_INLINE +#define DEVICE_INLINE INLINE_LOCALS #endif /* Code called whenever information on a Special Purpose Register is @@ -546,11 +575,21 @@ extern int current_model_issue; #define SEMANTICS_INLINE DEFAULT_INLINE #endif -/* Code to decode an instruction. Normally called on every instruction - cycle */ +/* When using the instruction cache, code to decode an instruction and + install it into the cache. Normally called when ever there is a + miss in the instruction cache. */ + +#ifndef ICACHE_INLINE +#define ICACHE_INLINE DEFAULT_INLINE +#endif + +/* General functions called by semantics functions but part of the + instruction table. Although called by the semantic functions the + frequency of calls is low. Consequently the need to inline this + code is reduced. */ -#ifndef IDECODE_INLINE -#define IDECODE_INLINE DEFAULT_INLINE +#ifndef SUPPORT_INLINE +#define SUPPORT_INLINE INLINE_LOCALS #endif /* Model specific code used in simulating functional units. Note, it actaully @@ -559,7 +598,7 @@ extern int current_model_issue; of the code, which is not friendly to the cache. */ #ifndef MODEL_INLINE -#define MODEL_INLINE DEFAULT_INLINE +#define MODEL_INLINE (DEFAULT_INLINE & ~INLINE_MODULE) #endif /* Code to print out what options we were compiled with. Because this @@ -568,11 +607,24 @@ extern int current_model_issue; routines will be pulled in twice. */ #ifndef OPTIONS_INLINE -#define OPTIONS_INLINE DEFAULT_INLINE +#define OPTIONS_INLINE MODEL_INLINE +#endif + +/* idecode acts as the hub of the system, everything else is imported + into this file */ + +#ifndef IDECOCE_INLINE +#define IDECODE_INLINE INLINE_LOCALS +#endif + +/* psim, isn't actually inlined */ + +#ifndef PSIM_INLINE +#define PSIM_INLINE INLINE_LOCALS #endif -/* Code to emulate os or rom compatibility. Called on the rare - occasion that the OS or ROM code is being emulated. */ +/* Code to emulate os or rom compatibility. This code is called via a + table and hence there is little benefit in making it inline */ #ifndef OS_EMUL_INLINE #define OS_EMUL_INLINE 0