diff options
-rw-r--r-- | LICENSE | 2 | ||||
-rw-r--r-- | SConscript | 421 | ||||
-rw-r--r-- | SConstruct | 438 | ||||
-rw-r--r-- | arch/SConscript | 146 | ||||
-rw-r--r-- | arch/alpha/SConscript | 91 | ||||
-rw-r--r-- | arch/alpha/arguments.cc | 66 | ||||
-rw-r--r-- | arch/alpha/arguments.hh | 143 | ||||
-rw-r--r-- | arch/alpha/ev5.cc | 593 | ||||
-rw-r--r-- | arch/alpha/freebsd/system.cc | 167 | ||||
-rw-r--r-- | arch/alpha/isa/branch.isa | 259 | ||||
-rw-r--r-- | arch/alpha/isa/decoder.isa | 819 | ||||
-rw-r--r-- | arch/alpha/isa/fp.isa | 301 | ||||
-rw-r--r-- | arch/alpha/isa/int.isa | 128 | ||||
-rw-r--r-- | arch/alpha/isa/main.isa | 448 | ||||
-rw-r--r-- | arch/alpha/isa/mem.isa | 702 | ||||
-rw-r--r-- | arch/alpha/isa/opcdec.isa | 72 | ||||
-rw-r--r-- | arch/alpha/isa/pal.isa | 273 | ||||
-rw-r--r-- | arch/alpha/isa/unimp.isa | 165 | ||||
-rw-r--r-- | arch/alpha/isa/unknown.isa | 52 | ||||
-rw-r--r-- | arch/alpha/isa/util.isa | 112 | ||||
-rw-r--r-- | arch/alpha/isa_traits.hh | 384 | ||||
-rw-r--r-- | arch/alpha/linux/process.cc | 589 | ||||
-rw-r--r-- | arch/alpha/linux/process.hh | 58 | ||||
-rw-r--r-- | arch/alpha/linux/system.cc | 289 | ||||
-rw-r--r-- | arch/alpha/linux/system.hh | 146 | ||||
-rw-r--r-- | arch/alpha/process.cc | 61 | ||||
-rw-r--r-- | arch/alpha/process.hh | 48 | ||||
-rw-r--r-- | arch/alpha/stacktrace.cc | 348 | ||||
-rw-r--r-- | arch/alpha/system.cc | 299 | ||||
-rw-r--r-- | arch/alpha/system.hh | 109 | ||||
-rw-r--r-- | arch/alpha/tlb.cc | 643 | ||||
-rw-r--r-- | arch/alpha/tlb.hh | 121 | ||||
-rw-r--r-- | arch/alpha/tru64/process.cc | 542 | ||||
-rw-r--r-- | arch/alpha/tru64/process.hh | 58 | ||||
-rw-r--r-- | arch/alpha/tru64/system.cc | 159 | ||||
-rw-r--r-- | arch/alpha/vtophys.cc | 268 | ||||
-rw-r--r-- | arch/alpha/vtophys.hh | 50 | ||||
-rwxr-xr-x | arch/isa_parser.py | 1772 | ||||
-rw-r--r-- | arch/isa_specific.hh | 62 | ||||
-rw-r--r-- | arch/mips/SConscript | 83 | ||||
-rw-r--r-- | arch/mips/faults.cc | 80 | ||||
-rw-r--r-- | arch/mips/faults.hh | 160 | ||||
-rw-r--r-- | arch/mips/isa/base.isa | 96 | ||||
-rw-r--r-- | arch/mips/isa/bitfields.isa | 67 | ||||
-rw-r--r-- | arch/mips/isa/decoder.isa | 930 | ||||
-rw-r--r-- | arch/mips/isa/formats.isa | 35 | ||||
-rw-r--r-- | arch/mips/isa/formats/branch.isa | 322 | ||||
-rw-r--r-- | arch/mips/isa/formats/fp.isa | 49 | ||||
-rw-r--r-- | arch/mips/isa/formats/int.isa | 130 | ||||
-rw-r--r-- | arch/mips/isa/formats/mem.isa | 469 | ||||
-rw-r--r-- | arch/mips/isa/formats/noop.isa | 90 | ||||
-rw-r--r-- | arch/mips/isa/formats/unimp.isa | 165 | ||||
-rw-r--r-- | arch/mips/isa/formats/unknown.isa | 52 | ||||
-rw-r--r-- | arch/mips/isa/formats/util.isa | 148 | ||||
-rw-r--r-- | arch/mips/isa/includes.isa | 39 | ||||
-rw-r--r-- | arch/mips/isa/main.isa | 52 | ||||
-rw-r--r-- | arch/mips/isa/operands.isa | 33 | ||||
-rw-r--r-- | arch/mips/isa_traits.cc | 403 | ||||
-rw-r--r-- | arch/mips/isa_traits.hh | 546 | ||||
-rw-r--r-- | arch/mips/linux_process.cc | 588 | ||||
-rw-r--r-- | arch/mips/linux_process.hh | 58 | ||||
-rw-r--r-- | arch/mips/process.cc | 56 | ||||
-rw-r--r-- | arch/mips/process.hh | 45 | ||||
-rw-r--r-- | arch/sparc/SConscript | 82 | ||||
-rw-r--r-- | arch/sparc/faults.cc | 248 | ||||
-rw-r--r-- | arch/sparc/faults.hh | 587 | ||||
-rw-r--r-- | arch/sparc/isa/base.isa | 129 | ||||
-rw-r--r-- | arch/sparc/isa/bitfields.isa | 50 | ||||
-rw-r--r-- | arch/sparc/isa/decoder.isa | 662 | ||||
-rw-r--r-- | arch/sparc/isa/formats.isa | 19 | ||||
-rw-r--r-- | arch/sparc/isa/formats/basic.isa | 68 | ||||
-rw-r--r-- | arch/sparc/isa/formats/branch.isa | 62 | ||||
-rw-r--r-- | arch/sparc/isa/formats/integerop.isa | 112 | ||||
-rw-r--r-- | arch/sparc/isa/formats/mem.isa | 73 | ||||
-rw-r--r-- | arch/sparc/isa/formats/noop.isa | 50 | ||||
-rw-r--r-- | arch/sparc/isa/formats/trap.isa | 51 | ||||
-rw-r--r-- | arch/sparc/isa/includes.isa | 43 | ||||
-rw-r--r-- | arch/sparc/isa/main.isa | 52 | ||||
-rw-r--r-- | arch/sparc/isa/operands.isa | 31 | ||||
-rw-r--r-- | arch/sparc/isa_traits.hh | 527 | ||||
-rw-r--r-- | arch/sparc/linux/process.cc | 374 | ||||
-rw-r--r-- | arch/sparc/linux/process.hh | 58 | ||||
-rw-r--r-- | arch/sparc/process.cc | 56 | ||||
-rw-r--r-- | arch/sparc/process.hh | 45 | ||||
-rw-r--r-- | base/cprintf.hh | 198 | ||||
-rw-r--r-- | base/cprintf_formats.hh | 346 | ||||
-rw-r--r-- | base/crc.cc | 115 | ||||
-rw-r--r-- | base/hostinfo.cc | 86 | ||||
-rw-r--r-- | base/inet.cc | 208 | ||||
-rw-r--r-- | base/inet.hh | 407 | ||||
-rw-r--r-- | base/intmath.hh | 230 | ||||
-rw-r--r-- | base/loader/aout_object.cc | 114 | ||||
-rw-r--r-- | base/loader/aout_object.hh | 58 | ||||
-rw-r--r-- | base/loader/coff_sym.h | 489 | ||||
-rw-r--r-- | base/loader/coff_symconst.h | 170 | ||||
-rw-r--r-- | base/loader/ecoff_object.cc | 171 | ||||
-rw-r--r-- | base/loader/ecoff_object.hh | 62 | ||||
-rw-r--r-- | base/loader/elf_object.cc | 331 | ||||
-rw-r--r-- | base/loader/elf_object.hh | 60 | ||||
-rw-r--r-- | base/loader/object_file.cc | 117 | ||||
-rw-r--r-- | base/loader/object_file.hh | 113 | ||||
-rw-r--r-- | base/loader/symtab.hh | 173 | ||||
-rw-r--r-- | base/remote_gdb.cc | 1232 | ||||
-rw-r--r-- | base/statistics.cc | 357 | ||||
-rw-r--r-- | base/statistics.hh | 2897 | ||||
-rw-r--r-- | base/stats/text.cc | 735 | ||||
-rw-r--r-- | base/traceflags.py | 325 | ||||
-rw-r--r-- | build/SConstruct | 421 | ||||
-rw-r--r-- | build_opts/ALPHA_FS (renamed from build/default_options/ALPHA_FS) | 0 | ||||
-rw-r--r-- | build_opts/ALPHA_FS_TL (renamed from build/default_options/ALPHA_FS_TL) | 0 | ||||
-rw-r--r-- | build_opts/ALPHA_SE (renamed from build/default_options/ALPHA_SE) | 0 | ||||
-rw-r--r-- | build_opts/MIPS_SE (renamed from build/default_options/MIPS_SE) | 0 | ||||
-rw-r--r-- | build_opts/SPARC_FS | 2 | ||||
-rw-r--r-- | build_opts/SPARC_SE (renamed from build/default_options/SPARC_SE) | 0 | ||||
-rw-r--r-- | configs/test/SysPaths.py | 32 | ||||
-rw-r--r-- | configs/test/fs.py | 215 | ||||
-rwxr-xr-x | configs/test/hello | bin | 0 -> 312176 bytes | |||
-rwxr-xr-x | configs/test/hello_mips | bin | 0 -> 837626 bytes | |||
-rwxr-xr-x | configs/test/hello_sparc | bin | 0 -> 644149 bytes | |||
-rw-r--r-- | configs/test/test.py | 12 | ||||
-rw-r--r-- | cpu/SConscript | 167 | ||||
-rw-r--r-- | cpu/base.cc | 378 | ||||
-rw-r--r-- | cpu/base.hh | 238 | ||||
-rw-r--r-- | cpu/cpu_exec_context.cc | 315 | ||||
-rw-r--r-- | cpu/cpu_exec_context.hh | 524 | ||||
-rw-r--r-- | cpu/cpu_models.py | 80 | ||||
-rw-r--r-- | cpu/exec_context.hh | 382 | ||||
-rw-r--r-- | cpu/exetrace.cc | 231 | ||||
-rw-r--r-- | cpu/exetrace.hh | 189 | ||||
-rw-r--r-- | cpu/memtest/memtest.cc | 441 | ||||
-rw-r--r-- | cpu/o3/alpha_cpu.hh | 430 | ||||
-rw-r--r-- | cpu/o3/alpha_cpu_impl.hh | 776 | ||||
-rw-r--r-- | cpu/o3/alpha_dyn_inst.hh | 268 | ||||
-rw-r--r-- | cpu/o3/cpu.cc | 1183 | ||||
-rw-r--r-- | cpu/o3/cpu.hh | 521 | ||||
-rw-r--r-- | cpu/o3/regfile.hh | 266 | ||||
-rw-r--r-- | cpu/pc_event.hh | 143 | ||||
-rw-r--r-- | cpu/simple/cpu.cc | 955 | ||||
-rw-r--r-- | cpu/simple/cpu.hh | 363 | ||||
-rw-r--r-- | cpu/static_inst.hh | 475 | ||||
-rw-r--r-- | dev/alpha_console.cc | 356 | ||||
-rw-r--r-- | dev/alpha_console.hh | 127 | ||||
-rw-r--r-- | dev/baddev.cc | 116 | ||||
-rw-r--r-- | dev/baddev.hh | 95 | ||||
-rw-r--r-- | dev/disk_image.cc | 471 | ||||
-rw-r--r-- | dev/etherbus.cc | 125 | ||||
-rw-r--r-- | dev/etherbus.hh | 79 | ||||
-rw-r--r-- | dev/etherdump.cc | 136 | ||||
-rw-r--r-- | dev/etherdump.hh | 59 | ||||
-rw-r--r-- | dev/etherint.hh | 66 | ||||
-rw-r--r-- | dev/etherlink.cc | 300 | ||||
-rw-r--r-- | dev/etherlink.hh | 130 | ||||
-rw-r--r-- | dev/etherpkt.cc | 53 | ||||
-rw-r--r-- | dev/etherpkt.hh | 84 | ||||
-rw-r--r-- | dev/ethertap.cc | 345 | ||||
-rw-r--r-- | dev/ethertap.hh | 107 | ||||
-rw-r--r-- | dev/ide_ctrl.cc | 813 | ||||
-rw-r--r-- | dev/ide_ctrl.hh | 246 | ||||
-rw-r--r-- | dev/ide_disk.cc | 1286 | ||||
-rw-r--r-- | dev/ide_disk.hh | 373 | ||||
-rw-r--r-- | dev/io_device.cc | 57 | ||||
-rw-r--r-- | dev/io_device.hh | 62 | ||||
-rw-r--r-- | dev/isa_fake.cc | 140 | ||||
-rw-r--r-- | dev/isa_fake.hh | 87 | ||||
-rw-r--r-- | dev/ns_gige.cc | 3105 | ||||
-rw-r--r-- | dev/ns_gige.hh | 487 | ||||
-rw-r--r-- | dev/pciconfigall.cc | 229 | ||||
-rw-r--r-- | dev/pciconfigall.hh | 147 | ||||
-rw-r--r-- | dev/pcidev.cc | 427 | ||||
-rw-r--r-- | dev/pcidev.hh | 298 | ||||
-rw-r--r-- | dev/pktfifo.cc | 99 | ||||
-rw-r--r-- | dev/pktfifo.hh | 168 | ||||
-rw-r--r-- | dev/platform.cc | 64 | ||||
-rw-r--r-- | dev/platform.hh | 68 | ||||
-rw-r--r-- | dev/simconsole.cc | 415 | ||||
-rw-r--r-- | dev/simconsole.hh | 165 | ||||
-rw-r--r-- | dev/simple_disk.cc | 109 | ||||
-rw-r--r-- | dev/simple_disk.hh | 62 | ||||
-rw-r--r-- | dev/sinic.cc | 1905 | ||||
-rw-r--r-- | dev/sinic.hh | 401 | ||||
-rw-r--r-- | dev/tsunami.cc | 132 | ||||
-rw-r--r-- | dev/tsunami.hh | 134 | ||||
-rw-r--r-- | dev/tsunami_cchip.cc | 580 | ||||
-rw-r--r-- | dev/tsunami_cchip.hh | 176 | ||||
-rw-r--r-- | dev/tsunami_io.cc | 719 | ||||
-rw-r--r-- | dev/tsunami_io.hh | 371 | ||||
-rw-r--r-- | dev/tsunami_pchip.cc | 388 | ||||
-rw-r--r-- | dev/tsunami_pchip.hh | 133 | ||||
-rw-r--r-- | dev/uart.cc | 78 | ||||
-rw-r--r-- | dev/uart.hh | 85 | ||||
-rw-r--r-- | dev/uart8250.cc | 349 | ||||
-rw-r--r-- | dev/uart8250.hh | 107 | ||||
-rw-r--r-- | encumbered/cpu/full/op_class.hh | 64 | ||||
-rw-r--r-- | ext/dnet/LICENSE | 28 | ||||
-rw-r--r-- | ext/dnet/dnet/addr.h | 67 | ||||
-rw-r--r-- | ext/dnet/dnet/arp.h | 103 | ||||
-rw-r--r-- | ext/dnet/dnet/blob.h | 56 | ||||
-rw-r--r-- | ext/dnet/dnet/eth.h | 77 | ||||
-rw-r--r-- | ext/dnet/dnet/fw.h | 54 | ||||
-rw-r--r-- | ext/dnet/dnet/icmp.h | 265 | ||||
-rw-r--r-- | ext/dnet/dnet/intf.h | 68 | ||||
-rw-r--r-- | ext/dnet/dnet/ip.h | 487 | ||||
-rw-r--r-- | ext/dnet/dnet/ip6.h | 183 | ||||
-rw-r--r-- | ext/dnet/dnet/os.h | 117 | ||||
-rw-r--r-- | ext/dnet/dnet/rand.h | 33 | ||||
-rw-r--r-- | ext/dnet/dnet/route.h | 35 | ||||
-rw-r--r-- | ext/dnet/dnet/tcp.h | 158 | ||||
-rw-r--r-- | ext/dnet/dnet/udp.h | 32 | ||||
-rw-r--r-- | ext/ply/CHANGES | 158 | ||||
-rw-r--r-- | ext/ply/COPYING | 504 | ||||
-rw-r--r-- | ext/ply/README | 249 | ||||
-rw-r--r-- | ext/ply/TODO | 22 | ||||
-rw-r--r-- | ext/ply/doc/ply.html | 1642 | ||||
-rw-r--r-- | ext/ply/example/ansic/README | 2 | ||||
-rw-r--r-- | ext/ply/example/ansic/clex.py | 161 | ||||
-rw-r--r-- | ext/ply/example/ansic/cparse.py | 859 | ||||
-rw-r--r-- | ext/ply/example/calc/calc.py | 108 | ||||
-rw-r--r-- | ext/ply/example/hedit/hedit.py | 44 | ||||
-rw-r--r-- | ext/ply/example/optcalc/README | 9 | ||||
-rw-r--r-- | ext/ply/example/optcalc/calc.py | 110 | ||||
-rw-r--r-- | ext/ply/lex.py | 681 | ||||
-rw-r--r-- | ext/ply/test/README | 9 | ||||
-rw-r--r-- | ext/ply/test/calclex.py | 46 | ||||
-rw-r--r-- | ext/ply/test/lex_doc1.exp | 1 | ||||
-rw-r--r-- | ext/ply/test/lex_doc1.py | 27 | ||||
-rw-r--r-- | ext/ply/test/lex_dup1.exp | 2 | ||||
-rw-r--r-- | ext/ply/test/lex_dup1.py | 27 | ||||
-rw-r--r-- | ext/ply/test/lex_dup2.exp | 2 | ||||
-rw-r--r-- | ext/ply/test/lex_dup2.py | 31 | ||||
-rw-r--r-- | ext/ply/test/lex_dup3.exp | 2 | ||||
-rw-r--r-- | ext/ply/test/lex_dup3.py | 29 | ||||
-rw-r--r-- | ext/ply/test/lex_empty.exp | 1 | ||||
-rw-r--r-- | ext/ply/test/lex_empty.py | 18 | ||||
-rw-r--r-- | ext/ply/test/lex_error1.exp | 1 | ||||
-rw-r--r-- | ext/ply/test/lex_error1.py | 22 | ||||
-rw-r--r-- | ext/ply/test/lex_error2.exp | 1 | ||||
-rw-r--r-- | ext/ply/test/lex_error2.py | 24 | ||||
-rw-r--r-- | ext/ply/test/lex_error3.exp | 2 | ||||
-rw-r--r-- | ext/ply/test/lex_error3.py | 25 | ||||
-rw-r--r-- | ext/ply/test/lex_error4.exp | 2 | ||||
-rw-r--r-- | ext/ply/test/lex_error4.py | 25 | ||||
-rw-r--r-- | ext/ply/test/lex_hedit.exp | 3 | ||||
-rw-r--r-- | ext/ply/test/lex_hedit.py | 44 | ||||
-rw-r--r-- | ext/ply/test/lex_ignore.exp | 2 | ||||
-rw-r--r-- | ext/ply/test/lex_ignore.py | 29 | ||||
-rw-r--r-- | ext/ply/test/lex_re1.exp | 2 | ||||
-rw-r--r-- | ext/ply/test/lex_re1.py | 25 | ||||
-rw-r--r-- | ext/ply/test/lex_rule1.exp | 2 | ||||
-rw-r--r-- | ext/ply/test/lex_rule1.py | 25 | ||||
-rw-r--r-- | ext/ply/test/lex_token1.exp | 1 | ||||
-rw-r--r-- | ext/ply/test/lex_token1.py | 19 | ||||
-rw-r--r-- | ext/ply/test/lex_token2.exp | 1 | ||||
-rw-r--r-- | ext/ply/test/lex_token2.py | 21 | ||||
-rw-r--r-- | ext/ply/test/lex_token3.exp | 2 | ||||
-rw-r--r-- | ext/ply/test/lex_token3.py | 24 | ||||
-rw-r--r-- | ext/ply/test/lex_token4.exp | 2 | ||||
-rw-r--r-- | ext/ply/test/lex_token4.py | 26 | ||||
-rw-r--r-- | ext/ply/test/lex_token5.exp | 1 | ||||
-rw-r--r-- | ext/ply/test/lex_token5.py | 31 | ||||
-rwxr-xr-x | ext/ply/test/testlex.py | 57 | ||||
-rw-r--r-- | ext/ply/test/testyacc.py | 58 | ||||
-rw-r--r-- | ext/ply/test/yacc_badargs.exp | 3 | ||||
-rw-r--r-- | ext/ply/test/yacc_badargs.py | 67 | ||||
-rw-r--r-- | ext/ply/test/yacc_badprec.exp | 1 | ||||
-rw-r--r-- | ext/ply/test/yacc_badprec.py | 63 | ||||
-rw-r--r-- | ext/ply/test/yacc_badprec2.exp | 3 | ||||
-rw-r--r-- | ext/ply/test/yacc_badprec2.py | 67 | ||||
-rw-r--r-- | ext/ply/test/yacc_badrule.exp | 5 | ||||
-rw-r--r-- | ext/ply/test/yacc_badrule.py | 67 | ||||
-rw-r--r-- | ext/ply/test/yacc_badtok.exp | 1 | ||||
-rw-r--r-- | ext/ply/test/yacc_badtok.py | 68 | ||||
-rw-r--r-- | ext/ply/test/yacc_dup.exp | 4 | ||||
-rw-r--r-- | ext/ply/test/yacc_dup.py | 67 | ||||
-rw-r--r-- | ext/ply/test/yacc_error1.exp | 1 | ||||
-rw-r--r-- | ext/ply/test/yacc_error1.py | 67 | ||||
-rw-r--r-- | ext/ply/test/yacc_error2.exp | 1 | ||||
-rw-r--r-- | ext/ply/test/yacc_error2.py | 67 | ||||
-rw-r--r-- | ext/ply/test/yacc_error3.exp | 1 | ||||
-rw-r--r-- | ext/ply/test/yacc_error3.py | 66 | ||||
-rw-r--r-- | ext/ply/test/yacc_inf.exp | 5 | ||||
-rw-r--r-- | ext/ply/test/yacc_inf.py | 55 | ||||
-rw-r--r-- | ext/ply/test/yacc_missing1.exp | 2 | ||||
-rw-r--r-- | ext/ply/test/yacc_missing1.py | 67 | ||||
-rw-r--r-- | ext/ply/test/yacc_nodoc.exp | 2 | ||||
-rw-r--r-- | ext/ply/test/yacc_nodoc.py | 66 | ||||
-rw-r--r-- | ext/ply/test/yacc_noerror.exp | 2 | ||||
-rw-r--r-- | ext/ply/test/yacc_noerror.py | 64 | ||||
-rw-r--r-- | ext/ply/test/yacc_nop.exp | 2 | ||||
-rw-r--r-- | ext/ply/test/yacc_nop.py | 67 | ||||
-rw-r--r-- | ext/ply/test/yacc_notfunc.exp | 4 | ||||
-rw-r--r-- | ext/ply/test/yacc_notfunc.py | 65 | ||||
-rw-r--r-- | ext/ply/test/yacc_notok.exp | 1 | ||||
-rw-r--r-- | ext/ply/test/yacc_notok.py | 66 | ||||
-rw-r--r-- | ext/ply/test/yacc_rr.exp | 2 | ||||
-rw-r--r-- | ext/ply/test/yacc_rr.py | 71 | ||||
-rw-r--r-- | ext/ply/test/yacc_simple.exp | 1 | ||||
-rw-r--r-- | ext/ply/test/yacc_simple.py | 67 | ||||
-rw-r--r-- | ext/ply/test/yacc_sr.exp | 2 | ||||
-rw-r--r-- | ext/ply/test/yacc_sr.py | 62 | ||||
-rw-r--r-- | ext/ply/test/yacc_term1.exp | 2 | ||||
-rw-r--r-- | ext/ply/test/yacc_term1.py | 67 | ||||
-rw-r--r-- | ext/ply/test/yacc_unused.exp | 4 | ||||
-rw-r--r-- | ext/ply/test/yacc_unused.py | 76 | ||||
-rw-r--r-- | ext/ply/test/yacc_uprec.exp | 2 | ||||
-rw-r--r-- | ext/ply/test/yacc_uprec.py | 62 | ||||
-rw-r--r-- | ext/ply/yacc.py | 1846 | ||||
-rw-r--r-- | kern/linux/events.cc | 55 | ||||
-rw-r--r-- | kern/linux/linux.hh | 341 | ||||
-rw-r--r-- | kern/linux/printk.cc | 261 | ||||
-rw-r--r-- | kern/linux/printk.hh | 36 | ||||
-rw-r--r-- | kern/system_events.cc | 90 | ||||
-rw-r--r-- | kern/tru64/dump_mbuf.hh | 38 | ||||
-rw-r--r-- | kern/tru64/printf.cc | 266 | ||||
-rw-r--r-- | kern/tru64/printf.hh | 38 | ||||
-rw-r--r-- | kern/tru64/tru64.hh | 1324 | ||||
-rw-r--r-- | kern/tru64/tru64_events.cc | 95 | ||||
-rw-r--r-- | python/SConscript | 207 | ||||
-rw-r--r-- | python/m5/objects/AlphaConsole.py | 9 | ||||
-rw-r--r-- | python/m5/objects/BadDevice.py | 6 | ||||
-rw-r--r-- | python/m5/objects/BaseCPU.py | 29 | ||||
-rw-r--r-- | python/m5/objects/Bus.py | 7 | ||||
-rw-r--r-- | python/m5/objects/Device.py | 35 | ||||
-rw-r--r-- | python/m5/objects/Ethernet.py | 119 | ||||
-rw-r--r-- | python/m5/objects/Ide.py | 15 | ||||
-rw-r--r-- | python/m5/objects/Pci.py | 55 | ||||
-rw-r--r-- | python/m5/objects/PhysicalMemory.py | 8 | ||||
-rw-r--r-- | python/m5/objects/Process.py | 17 | ||||
-rw-r--r-- | python/m5/objects/Root.py | 25 | ||||
-rw-r--r-- | python/m5/objects/SimpleDisk.py | 5 | ||||
-rw-r--r-- | python/m5/objects/System.py | 21 | ||||
-rw-r--r-- | python/m5/objects/Tsunami.py | 27 | ||||
-rw-r--r-- | python/m5/objects/Uart.py | 16 | ||||
-rw-r--r-- | sim/byteswap.hh | 146 | ||||
-rw-r--r-- | sim/eventq.cc | 259 | ||||
-rw-r--r-- | sim/faults.cc | 46 | ||||
-rw-r--r-- | sim/faults.hh | 67 | ||||
-rw-r--r-- | sim/host.hh | 65 | ||||
-rw-r--r-- | sim/main.cc | 429 | ||||
-rw-r--r-- | sim/param.cc | 794 | ||||
-rw-r--r-- | sim/process.cc | 446 | ||||
-rw-r--r-- | sim/process.hh | 219 | ||||
-rw-r--r-- | sim/pseudo_inst.cc | 291 | ||||
-rw-r--r-- | sim/sim_object.cc | 231 | ||||
-rw-r--r-- | sim/sim_object.hh | 108 | ||||
-rw-r--r-- | sim/syscall_emul.cc | 441 | ||||
-rw-r--r-- | sim/syscall_emul.hh | 832 | ||||
-rw-r--r-- | sim/system.cc | 185 | ||||
-rw-r--r-- | sim/system.hh | 194 | ||||
-rw-r--r-- | sim/vptr.hh | 116 | ||||
-rw-r--r-- | src/Doxyfile (renamed from Doxyfile) | 0 | ||||
-rw-r--r-- | src/SConscript | 400 | ||||
-rw-r--r-- | src/arch/SConscript | 150 | ||||
-rw-r--r-- | src/arch/alpha/SConscript | 93 | ||||
-rw-r--r-- | src/arch/alpha/aout_machdep.h (renamed from arch/alpha/aout_machdep.h) | 0 | ||||
-rw-r--r-- | src/arch/alpha/arguments.cc | 68 | ||||
-rw-r--r-- | src/arch/alpha/arguments.hh | 147 | ||||
-rw-r--r-- | src/arch/alpha/ecoff_machdep.h (renamed from arch/alpha/ecoff_machdep.h) | 0 | ||||
-rw-r--r-- | src/arch/alpha/ev5.cc | 584 | ||||
-rw-r--r-- | src/arch/alpha/ev5.hh (renamed from arch/alpha/ev5.hh) | 0 | ||||
-rw-r--r-- | src/arch/alpha/faults.cc (renamed from arch/alpha/faults.cc) | 0 | ||||
-rw-r--r-- | src/arch/alpha/faults.hh (renamed from arch/alpha/faults.hh) | 0 | ||||
-rw-r--r-- | src/arch/alpha/freebsd/system.cc | 156 | ||||
-rw-r--r-- | src/arch/alpha/freebsd/system.hh (renamed from arch/alpha/freebsd/system.hh) | 0 | ||||
-rw-r--r-- | src/arch/alpha/isa/branch.isa | 264 | ||||
-rw-r--r-- | src/arch/alpha/isa/decoder.isa | 824 | ||||
-rw-r--r-- | src/arch/alpha/isa/fp.isa | 310 | ||||
-rw-r--r-- | src/arch/alpha/isa/int.isa | 133 | ||||
-rw-r--r-- | src/arch/alpha/isa/main.isa | 461 | ||||
-rw-r--r-- | src/arch/alpha/isa/mem.isa | 734 | ||||
-rw-r--r-- | src/arch/alpha/isa/opcdec.isa | 77 | ||||
-rw-r--r-- | src/arch/alpha/isa/pal.isa | 278 | ||||
-rw-r--r-- | src/arch/alpha/isa/unimp.isa | 170 | ||||
-rw-r--r-- | src/arch/alpha/isa/unknown.isa | 57 | ||||
-rw-r--r-- | src/arch/alpha/isa/util.isa | 117 | ||||
-rw-r--r-- | src/arch/alpha/isa_traits.hh | 112 | ||||
-rw-r--r-- | src/arch/alpha/linux/aligned.hh (renamed from arch/alpha/linux/aligned.hh) | 0 | ||||
-rw-r--r-- | src/arch/alpha/linux/hwrpb.hh (renamed from arch/alpha/linux/hwrpb.hh) | 0 | ||||
-rw-r--r-- | src/arch/alpha/linux/linux.cc | 70 | ||||
-rw-r--r-- | src/arch/alpha/linux/linux.hh | 128 | ||||
-rw-r--r-- | src/arch/alpha/linux/process.cc | 591 | ||||
-rw-r--r-- | src/arch/alpha/linux/process.hh | 60 | ||||
-rw-r--r-- | src/arch/alpha/linux/system.cc | 265 | ||||
-rw-r--r-- | src/arch/alpha/linux/system.hh | 145 | ||||
-rw-r--r-- | src/arch/alpha/linux/thread_info.hh (renamed from arch/alpha/linux/thread_info.hh) | 0 | ||||
-rw-r--r-- | src/arch/alpha/linux/threadinfo.hh (renamed from arch/alpha/linux/threadinfo.hh) | 0 | ||||
-rw-r--r-- | src/arch/alpha/osfpal.cc (renamed from arch/alpha/osfpal.cc) | 0 | ||||
-rw-r--r-- | src/arch/alpha/osfpal.hh (renamed from arch/alpha/osfpal.hh) | 0 | ||||
-rw-r--r-- | src/arch/alpha/process.cc | 167 | ||||
-rw-r--r-- | src/arch/alpha/process.hh | 64 | ||||
-rw-r--r-- | src/arch/alpha/regfile.hh | 278 | ||||
-rw-r--r-- | src/arch/alpha/stacktrace.cc | 344 | ||||
-rw-r--r-- | src/arch/alpha/stacktrace.hh (renamed from arch/alpha/stacktrace.hh) | 0 | ||||
-rw-r--r-- | src/arch/alpha/system.cc | 280 | ||||
-rw-r--r-- | src/arch/alpha/system.hh | 108 | ||||
-rw-r--r-- | src/arch/alpha/tlb.cc | 628 | ||||
-rw-r--r-- | src/arch/alpha/tlb.hh | 121 | ||||
-rw-r--r-- | src/arch/alpha/tru64/process.cc | 586 | ||||
-rw-r--r-- | src/arch/alpha/tru64/process.hh | 61 | ||||
-rw-r--r-- | src/arch/alpha/tru64/system.cc | 151 | ||||
-rw-r--r-- | src/arch/alpha/tru64/system.hh (renamed from arch/alpha/tru64/system.hh) | 0 | ||||
-rw-r--r-- | src/arch/alpha/tru64/tru64.cc | 70 | ||||
-rw-r--r-- | src/arch/alpha/tru64/tru64.hh | 127 | ||||
-rw-r--r-- | src/arch/alpha/types.hh | 64 | ||||
-rw-r--r-- | src/arch/alpha/utility.hh | 156 | ||||
-rw-r--r-- | src/arch/alpha/vtophys.cc | 162 | ||||
-rw-r--r-- | src/arch/alpha/vtophys.hh | 52 | ||||
-rwxr-xr-x | src/arch/isa_parser.py | 1810 | ||||
-rw-r--r-- | src/arch/isa_specific.hh | 62 | ||||
-rw-r--r-- | src/arch/mips/SConscript | 83 | ||||
-rw-r--r-- | src/arch/mips/faults.cc | 131 | ||||
-rw-r--r-- | src/arch/mips/faults.hh | 269 | ||||
-rw-r--r-- | src/arch/mips/isa/base.isa | 88 | ||||
-rw-r--r-- | src/arch/mips/isa/bitfields.isa | 71 | ||||
-rw-r--r-- | src/arch/mips/isa/decoder.isa | 1688 | ||||
-rw-r--r-- | src/arch/mips/isa/formats/basic.isa (renamed from arch/mips/isa/formats/basic.isa) | 0 | ||||
-rw-r--r-- | src/arch/mips/isa/formats/branch.isa | 324 | ||||
-rw-r--r-- | src/arch/mips/isa/formats/formats.isa | 35 | ||||
-rw-r--r-- | src/arch/mips/isa/formats/fp.isa | 109 | ||||
-rw-r--r-- | src/arch/mips/isa/formats/int.isa | 131 | ||||
-rw-r--r-- | src/arch/mips/isa/formats/mem.isa | 478 | ||||
-rw-r--r-- | src/arch/mips/isa/formats/noop.isa | 94 | ||||
-rw-r--r-- | src/arch/mips/isa/formats/tlbop.isa (renamed from arch/mips/isa/formats/tlbop.isa) | 0 | ||||
-rw-r--r-- | src/arch/mips/isa/formats/trap.isa (renamed from arch/mips/isa/formats/trap.isa) | 0 | ||||
-rw-r--r-- | src/arch/mips/isa/formats/unimp.isa | 171 | ||||
-rw-r--r-- | src/arch/mips/isa/formats/unknown.isa | 79 | ||||
-rw-r--r-- | src/arch/mips/isa/formats/util.isa | 129 | ||||
-rw-r--r-- | src/arch/mips/isa/includes.isa | 48 | ||||
-rw-r--r-- | src/arch/mips/isa/main.isa | 59 | ||||
-rw-r--r-- | src/arch/mips/isa/operands.isa | 61 | ||||
-rw-r--r-- | src/arch/mips/isa_traits.cc | 229 | ||||
-rw-r--r-- | src/arch/mips/isa_traits.hh | 199 | ||||
-rw-r--r-- | src/arch/mips/linux/linux.cc | 72 | ||||
-rw-r--r-- | src/arch/mips/linux/linux.hh | 126 | ||||
-rw-r--r-- | src/arch/mips/linux/process.cc | 429 | ||||
-rw-r--r-- | src/arch/mips/linux/process.hh | 59 | ||||
-rw-r--r-- | src/arch/mips/process.cc | 161 | ||||
-rw-r--r-- | src/arch/mips/process.hh | 64 | ||||
-rw-r--r-- | src/arch/mips/regfile/float_regfile.hh | 159 | ||||
-rw-r--r-- | src/arch/mips/regfile/int_regfile.hh | 73 | ||||
-rw-r--r-- | src/arch/mips/regfile/misc_regfile.hh | 96 | ||||
-rw-r--r-- | src/arch/mips/regfile/regfile.hh | 199 | ||||
-rw-r--r-- | src/arch/mips/stacktrace.hh (renamed from arch/mips/stacktrace.hh) | 0 | ||||
-rw-r--r-- | src/arch/mips/types.hh | 92 | ||||
-rw-r--r-- | src/arch/mips/utility.hh | 44 | ||||
-rw-r--r-- | src/arch/sparc/SConscript | 80 | ||||
-rw-r--r-- | src/arch/sparc/faults.cc | 255 | ||||
-rw-r--r-- | src/arch/sparc/faults.hh | 591 | ||||
-rw-r--r-- | src/arch/sparc/isa/base.isa | 252 | ||||
-rw-r--r-- | src/arch/sparc/isa/bitfields.isa | 78 | ||||
-rw-r--r-- | src/arch/sparc/isa/decoder.isa | 669 | ||||
-rw-r--r-- | src/arch/sparc/isa/formats.isa | 28 | ||||
-rw-r--r-- | src/arch/sparc/isa/formats/basic.isa | 97 | ||||
-rw-r--r-- | src/arch/sparc/isa/formats/branch.isa | 337 | ||||
-rw-r--r-- | src/arch/sparc/isa/formats/integerop.isa | 395 | ||||
-rw-r--r-- | src/arch/sparc/isa/formats/mem.isa | 171 | ||||
-rw-r--r-- | src/arch/sparc/isa/formats/nop.isa | 98 | ||||
-rw-r--r-- | src/arch/sparc/isa/formats/priv.isa | 125 | ||||
-rw-r--r-- | src/arch/sparc/isa/formats/trap.isa | 93 | ||||
-rw-r--r-- | src/arch/sparc/isa/formats/unknown.isa | 75 | ||||
-rw-r--r-- | src/arch/sparc/isa/includes.isa | 76 | ||||
-rw-r--r-- | src/arch/sparc/isa/main.isa | 59 | ||||
-rw-r--r-- | src/arch/sparc/isa/operands.isa | 88 | ||||
-rw-r--r-- | src/arch/sparc/isa_traits.hh | 190 | ||||
-rw-r--r-- | src/arch/sparc/linux/linux.cc | 68 | ||||
-rw-r--r-- | src/arch/sparc/linux/linux.hh | 61 | ||||
-rw-r--r-- | src/arch/sparc/linux/process.cc | 407 | ||||
-rw-r--r-- | src/arch/sparc/linux/process.hh | 65 | ||||
-rw-r--r-- | src/arch/sparc/process.cc | 379 | ||||
-rw-r--r-- | src/arch/sparc/process.hh | 79 | ||||
-rw-r--r-- | src/arch/sparc/regfile.hh | 861 | ||||
-rw-r--r-- | src/arch/sparc/solaris/process.cc | 347 | ||||
-rw-r--r-- | src/arch/sparc/solaris/process.hh | 63 | ||||
-rw-r--r-- | src/arch/sparc/solaris/solaris.cc | 74 | ||||
-rw-r--r-- | src/arch/sparc/solaris/solaris.hh | 62 | ||||
-rw-r--r-- | src/arch/sparc/stacktrace.hh (renamed from arch/sparc/stacktrace.hh) | 0 | ||||
-rw-r--r-- | src/arch/sparc/system.cc | 201 | ||||
-rw-r--r-- | src/arch/sparc/system.hh | 117 | ||||
-rw-r--r-- | src/arch/sparc/tlb.hh | 35 | ||||
-rw-r--r-- | src/arch/sparc/ua2005.cc | 222 | ||||
-rw-r--r-- | src/arch/sparc/utility.hh | 89 | ||||
-rw-r--r-- | src/arch/sparc/vtophys.cc | 162 | ||||
-rw-r--r-- | src/arch/sparc/vtophys.hh | 52 | ||||
-rw-r--r-- | src/base/bitfield.hh (renamed from base/bitfield.hh) | 0 | ||||
-rw-r--r-- | src/base/callback.hh (renamed from base/callback.hh) | 0 | ||||
-rw-r--r-- | src/base/chunk_generator.hh | 141 | ||||
-rw-r--r-- | src/base/circlebuf.cc (renamed from base/circlebuf.cc) | 0 | ||||
-rw-r--r-- | src/base/circlebuf.hh (renamed from base/circlebuf.hh) | 0 | ||||
-rw-r--r-- | src/base/compression/lzss_compression.cc (renamed from base/compression/lzss_compression.cc) | 0 | ||||
-rw-r--r-- | src/base/compression/lzss_compression.hh (renamed from base/compression/lzss_compression.hh) | 0 | ||||
-rw-r--r-- | src/base/compression/null_compression.hh (renamed from base/compression/null_compression.hh) | 0 | ||||
-rw-r--r-- | src/base/cprintf.cc (renamed from base/cprintf.cc) | 0 | ||||
-rw-r--r-- | src/base/cprintf.hh | 197 | ||||
-rw-r--r-- | src/base/cprintf_formats.hh | 353 | ||||
-rw-r--r-- | src/base/crc.cc | 114 | ||||
-rw-r--r-- | src/base/crc.hh (renamed from base/crc.hh) | 0 | ||||
-rw-r--r-- | src/base/date.cc (renamed from base/date.cc) | 0 | ||||
-rw-r--r-- | src/base/dbl_list.hh (renamed from base/dbl_list.hh) | 0 | ||||
-rw-r--r-- | src/base/endian.hh (renamed from base/endian.hh) | 0 | ||||
-rw-r--r-- | src/base/fast_alloc.cc (renamed from base/fast_alloc.cc) | 0 | ||||
-rw-r--r-- | src/base/fast_alloc.hh (renamed from base/fast_alloc.hh) | 0 | ||||
-rw-r--r-- | src/base/fenv.hh (renamed from base/fenv.hh) | 0 | ||||
-rw-r--r-- | src/base/fifo_buffer.cc (renamed from base/fifo_buffer.cc) | 0 | ||||
-rw-r--r-- | src/base/fifo_buffer.hh (renamed from base/fifo_buffer.hh) | 0 | ||||
-rw-r--r-- | src/base/hashmap.hh (renamed from base/hashmap.hh) | 0 | ||||
-rw-r--r-- | src/base/hostinfo.cc | 85 | ||||
-rw-r--r-- | src/base/hostinfo.hh (renamed from base/hostinfo.hh) | 0 | ||||
-rw-r--r-- | src/base/hybrid_pred.cc (renamed from base/hybrid_pred.cc) | 0 | ||||
-rw-r--r-- | src/base/hybrid_pred.hh (renamed from base/hybrid_pred.hh) | 0 | ||||
-rw-r--r-- | src/base/inet.cc | 207 | ||||
-rw-r--r-- | src/base/inet.hh | 407 | ||||
-rw-r--r-- | src/base/inifile.cc (renamed from base/inifile.cc) | 0 | ||||
-rw-r--r-- | src/base/inifile.hh (renamed from base/inifile.hh) | 0 | ||||
-rw-r--r-- | src/base/intmath.cc (renamed from base/intmath.cc) | 0 | ||||
-rw-r--r-- | src/base/intmath.hh | 230 | ||||
-rw-r--r-- | src/base/kgdb.h (renamed from base/kgdb.h) | 0 | ||||
-rw-r--r-- | src/base/loader/aout_object.cc | 94 | ||||
-rw-r--r-- | src/base/loader/aout_object.hh | 56 | ||||
-rw-r--r-- | src/base/loader/coff_sym.h | 519 | ||||
-rw-r--r-- | src/base/loader/coff_symconst.h | 200 | ||||
-rw-r--r-- | src/base/loader/ecoff_object.cc | 153 | ||||
-rw-r--r-- | src/base/loader/ecoff_object.hh | 60 | ||||
-rw-r--r-- | src/base/loader/elf_object.cc | 309 | ||||
-rw-r--r-- | src/base/loader/elf_object.hh | 55 | ||||
-rw-r--r-- | src/base/loader/exec_aout.h (renamed from base/loader/exec_aout.h) | 0 | ||||
-rw-r--r-- | src/base/loader/exec_ecoff.h (renamed from base/loader/exec_ecoff.h) | 0 | ||||
-rw-r--r-- | src/base/loader/object_file.cc | 145 | ||||
-rw-r--r-- | src/base/loader/object_file.hh | 119 | ||||
-rw-r--r-- | src/base/loader/symtab.cc (renamed from base/loader/symtab.cc) | 0 | ||||
-rw-r--r-- | src/base/loader/symtab.hh | 173 | ||||
-rw-r--r-- | src/base/match.cc (renamed from base/match.cc) | 0 | ||||
-rw-r--r-- | src/base/match.hh (renamed from base/match.hh) | 0 | ||||
-rw-r--r-- | src/base/misc.cc (renamed from base/misc.cc) | 0 | ||||
-rw-r--r-- | src/base/misc.hh (renamed from base/misc.hh) | 0 | ||||
-rw-r--r-- | src/base/mod_num.hh (renamed from base/mod_num.hh) | 0 | ||||
-rw-r--r-- | src/base/mysql.cc (renamed from base/mysql.cc) | 0 | ||||
-rw-r--r-- | src/base/mysql.hh (renamed from base/mysql.hh) | 0 | ||||
-rw-r--r-- | src/base/output.cc (renamed from base/output.cc) | 0 | ||||
-rw-r--r-- | src/base/output.hh (renamed from base/output.hh) | 0 | ||||
-rw-r--r-- | src/base/pollevent.cc (renamed from base/pollevent.cc) | 0 | ||||
-rw-r--r-- | src/base/pollevent.hh (renamed from base/pollevent.hh) | 0 | ||||
-rw-r--r-- | src/base/predictor.hh (renamed from base/predictor.hh) | 0 | ||||
-rw-r--r-- | src/base/random.cc (renamed from base/random.cc) | 0 | ||||
-rw-r--r-- | src/base/random.hh (renamed from base/random.hh) | 0 | ||||
-rw-r--r-- | src/base/range.cc (renamed from base/range.cc) | 0 | ||||
-rw-r--r-- | src/base/range.hh (renamed from base/range.hh) | 0 | ||||
-rw-r--r-- | src/base/refcnt.hh (renamed from base/refcnt.hh) | 0 | ||||
-rw-r--r-- | src/base/remote_gdb.cc | 1175 | ||||
-rw-r--r-- | src/base/remote_gdb.hh (renamed from base/remote_gdb.hh) | 0 | ||||
-rw-r--r-- | src/base/res_list.hh (renamed from base/res_list.hh) | 0 | ||||
-rw-r--r-- | src/base/sat_counter.cc (renamed from base/sat_counter.cc) | 0 | ||||
-rw-r--r-- | src/base/sat_counter.hh (renamed from base/sat_counter.hh) | 0 | ||||
-rw-r--r-- | src/base/sched_list.hh (renamed from base/sched_list.hh) | 0 | ||||
-rw-r--r-- | src/base/socket.cc (renamed from base/socket.cc) | 0 | ||||
-rw-r--r-- | src/base/socket.hh (renamed from base/socket.hh) | 0 | ||||
-rw-r--r-- | src/base/statistics.cc | 356 | ||||
-rw-r--r-- | src/base/statistics.hh | 2896 | ||||
-rw-r--r-- | src/base/stats/events.cc (renamed from base/stats/events.cc) | 0 | ||||
-rw-r--r-- | src/base/stats/events.hh (renamed from base/stats/events.hh) | 0 | ||||
-rw-r--r-- | src/base/stats/flags.hh (renamed from base/stats/flags.hh) | 0 | ||||
-rw-r--r-- | src/base/stats/mysql.cc (renamed from base/stats/mysql.cc) | 0 | ||||
-rw-r--r-- | src/base/stats/mysql.hh (renamed from base/stats/mysql.hh) | 0 | ||||
-rw-r--r-- | src/base/stats/mysql_run.hh (renamed from base/stats/mysql_run.hh) | 0 | ||||
-rw-r--r-- | src/base/stats/output.hh (renamed from base/stats/output.hh) | 0 | ||||
-rw-r--r-- | src/base/stats/statdb.cc (renamed from base/stats/statdb.cc) | 0 | ||||
-rw-r--r-- | src/base/stats/statdb.hh (renamed from base/stats/statdb.hh) | 0 | ||||
-rw-r--r-- | src/base/stats/text.cc | 736 | ||||
-rw-r--r-- | src/base/stats/text.hh (renamed from base/stats/text.hh) | 0 | ||||
-rw-r--r-- | src/base/stats/types.hh (renamed from base/stats/types.hh) | 0 | ||||
-rw-r--r-- | src/base/stats/visit.cc (renamed from base/stats/visit.cc) | 0 | ||||
-rw-r--r-- | src/base/stats/visit.hh (renamed from base/stats/visit.hh) | 0 | ||||
-rw-r--r-- | src/base/str.cc (renamed from base/str.cc) | 0 | ||||
-rw-r--r-- | src/base/str.hh (renamed from base/str.hh) | 0 | ||||
-rw-r--r-- | src/base/time.cc (renamed from base/time.cc) | 0 | ||||
-rw-r--r-- | src/base/time.hh (renamed from base/time.hh) | 0 | ||||
-rw-r--r-- | src/base/timebuf.hh (renamed from base/timebuf.hh) | 0 | ||||
-rw-r--r-- | src/base/trace.cc (renamed from base/trace.cc) | 0 | ||||
-rw-r--r-- | src/base/trace.hh (renamed from base/trace.hh) | 0 | ||||
-rw-r--r-- | src/base/traceflags.py | 289 | ||||
-rw-r--r-- | src/base/userinfo.cc (renamed from base/userinfo.cc) | 0 | ||||
-rw-r--r-- | src/base/userinfo.hh (renamed from base/userinfo.hh) | 0 | ||||
-rw-r--r-- | src/cpu/SConscript | 179 | ||||
-rw-r--r-- | src/cpu/base.cc | 381 | ||||
-rw-r--r-- | src/cpu/base.hh | 238 | ||||
-rw-r--r-- | src/cpu/base_dyn_inst.cc (renamed from cpu/base_dyn_inst.cc) | 0 | ||||
-rw-r--r-- | src/cpu/base_dyn_inst.hh (renamed from cpu/base_dyn_inst.hh) | 0 | ||||
-rw-r--r-- | src/cpu/cpu_exec_context.cc | 340 | ||||
-rw-r--r-- | src/cpu/cpu_exec_context.hh | 540 | ||||
-rw-r--r-- | src/cpu/cpu_models.py | 80 | ||||
-rw-r--r-- | src/cpu/cpuevent.cc | 61 | ||||
-rw-r--r-- | src/cpu/cpuevent.hh | 88 | ||||
-rw-r--r-- | src/cpu/exec_context.hh | 417 | ||||
-rw-r--r-- | src/cpu/exetrace.cc | 230 | ||||
-rw-r--r-- | src/cpu/exetrace.hh | 189 | ||||
-rw-r--r-- | src/cpu/inst_seq.hh (renamed from cpu/inst_seq.hh) | 0 | ||||
-rw-r--r-- | src/cpu/intr_control.cc (renamed from cpu/intr_control.cc) | 0 | ||||
-rw-r--r-- | src/cpu/intr_control.hh (renamed from cpu/intr_control.hh) | 0 | ||||
-rw-r--r-- | src/cpu/memtest/memtest.cc | 440 | ||||
-rw-r--r-- | src/cpu/memtest/memtest.hh (renamed from cpu/memtest/memtest.hh) | 0 | ||||
-rw-r--r-- | src/cpu/o3/2bit_local_pred.cc (renamed from cpu/o3/2bit_local_pred.cc) | 0 | ||||
-rw-r--r-- | src/cpu/o3/2bit_local_pred.hh (renamed from cpu/o3/2bit_local_pred.hh) | 0 | ||||
-rw-r--r-- | src/cpu/o3/alpha_cpu.cc (renamed from cpu/o3/alpha_cpu.cc) | 0 | ||||
-rw-r--r-- | src/cpu/o3/alpha_cpu.hh | 430 | ||||
-rw-r--r-- | src/cpu/o3/alpha_cpu_builder.cc (renamed from cpu/o3/alpha_cpu_builder.cc) | 0 | ||||
-rw-r--r-- | src/cpu/o3/alpha_cpu_impl.hh | 775 | ||||
-rw-r--r-- | src/cpu/o3/alpha_dyn_inst.cc (renamed from cpu/o3/alpha_dyn_inst.cc) | 0 | ||||
-rw-r--r-- | src/cpu/o3/alpha_dyn_inst.hh | 280 | ||||
-rw-r--r-- | src/cpu/o3/alpha_dyn_inst_impl.hh (renamed from cpu/o3/alpha_dyn_inst_impl.hh) | 0 | ||||
-rw-r--r-- | src/cpu/o3/alpha_impl.hh (renamed from cpu/o3/alpha_impl.hh) | 0 | ||||
-rw-r--r-- | src/cpu/o3/alpha_params.hh (renamed from cpu/o3/alpha_params.hh) | 0 | ||||
-rw-r--r-- | src/cpu/o3/bpred_unit.cc (renamed from cpu/o3/bpred_unit.cc) | 0 | ||||
-rw-r--r-- | src/cpu/o3/bpred_unit.hh (renamed from cpu/o3/bpred_unit.hh) | 0 | ||||
-rw-r--r-- | src/cpu/o3/bpred_unit_impl.hh (renamed from cpu/o3/bpred_unit_impl.hh) | 0 | ||||
-rw-r--r-- | src/cpu/o3/btb.cc (renamed from cpu/o3/btb.cc) | 0 | ||||
-rw-r--r-- | src/cpu/o3/btb.hh (renamed from cpu/o3/btb.hh) | 0 | ||||
-rw-r--r-- | src/cpu/o3/comm.hh (renamed from cpu/o3/comm.hh) | 0 | ||||
-rw-r--r-- | src/cpu/o3/commit.cc (renamed from cpu/o3/commit.cc) | 0 | ||||
-rw-r--r-- | src/cpu/o3/commit.hh (renamed from cpu/o3/commit.hh) | 0 | ||||
-rw-r--r-- | src/cpu/o3/commit_impl.hh (renamed from cpu/o3/commit_impl.hh) | 0 | ||||
-rw-r--r-- | src/cpu/o3/cpu.cc | 1196 | ||||
-rw-r--r-- | src/cpu/o3/cpu.hh | 525 | ||||
-rw-r--r-- | src/cpu/o3/cpu_policy.hh (renamed from cpu/o3/cpu_policy.hh) | 0 | ||||
-rw-r--r-- | src/cpu/o3/decode.cc (renamed from cpu/o3/decode.cc) | 0 | ||||
-rw-r--r-- | src/cpu/o3/decode.hh (renamed from cpu/o3/decode.hh) | 0 | ||||
-rw-r--r-- | src/cpu/o3/decode_impl.hh (renamed from cpu/o3/decode_impl.hh) | 0 | ||||
-rw-r--r-- | src/cpu/o3/fetch.cc (renamed from cpu/o3/fetch.cc) | 0 | ||||
-rw-r--r-- | src/cpu/o3/fetch.hh (renamed from cpu/o3/fetch.hh) | 0 | ||||
-rw-r--r-- | src/cpu/o3/fetch_impl.hh (renamed from cpu/o3/fetch_impl.hh) | 0 | ||||
-rw-r--r-- | src/cpu/o3/free_list.cc (renamed from cpu/o3/free_list.cc) | 0 | ||||
-rw-r--r-- | src/cpu/o3/free_list.hh (renamed from cpu/o3/free_list.hh) | 0 | ||||
-rw-r--r-- | src/cpu/o3/iew.cc (renamed from cpu/o3/iew.cc) | 0 | ||||
-rw-r--r-- | src/cpu/o3/iew.hh (renamed from cpu/o3/iew.hh) | 0 | ||||
-rw-r--r-- | src/cpu/o3/iew_impl.hh (renamed from cpu/o3/iew_impl.hh) | 0 | ||||
-rw-r--r-- | src/cpu/o3/inst_queue.cc (renamed from cpu/o3/inst_queue.cc) | 0 | ||||
-rw-r--r-- | src/cpu/o3/inst_queue.hh (renamed from cpu/o3/inst_queue.hh) | 0 | ||||
-rw-r--r-- | src/cpu/o3/inst_queue_impl.hh (renamed from cpu/o3/inst_queue_impl.hh) | 0 | ||||
-rw-r--r-- | src/cpu/o3/mem_dep_unit.cc (renamed from cpu/o3/mem_dep_unit.cc) | 0 | ||||
-rw-r--r-- | src/cpu/o3/mem_dep_unit.hh (renamed from cpu/o3/mem_dep_unit.hh) | 0 | ||||
-rw-r--r-- | src/cpu/o3/mem_dep_unit_impl.hh (renamed from cpu/o3/mem_dep_unit_impl.hh) | 0 | ||||
-rw-r--r-- | src/cpu/o3/ras.cc (renamed from cpu/o3/ras.cc) | 0 | ||||
-rw-r--r-- | src/cpu/o3/ras.hh (renamed from cpu/o3/ras.hh) | 0 | ||||
-rw-r--r-- | src/cpu/o3/regfile.hh | 289 | ||||
-rw-r--r-- | src/cpu/o3/rename.cc (renamed from cpu/o3/rename.cc) | 0 | ||||
-rw-r--r-- | src/cpu/o3/rename.hh (renamed from cpu/o3/rename.hh) | 0 | ||||
-rw-r--r-- | src/cpu/o3/rename_impl.hh (renamed from cpu/o3/rename_impl.hh) | 0 | ||||
-rw-r--r-- | src/cpu/o3/rename_map.cc (renamed from cpu/o3/rename_map.cc) | 0 | ||||
-rw-r--r-- | src/cpu/o3/rename_map.hh (renamed from cpu/o3/rename_map.hh) | 0 | ||||
-rw-r--r-- | src/cpu/o3/rob.cc (renamed from cpu/o3/rob.cc) | 0 | ||||
-rw-r--r-- | src/cpu/o3/rob.hh (renamed from cpu/o3/rob.hh) | 0 | ||||
-rw-r--r-- | src/cpu/o3/rob_impl.hh (renamed from cpu/o3/rob_impl.hh) | 0 | ||||
-rw-r--r-- | src/cpu/o3/sat_counter.cc | 55 | ||||
-rw-r--r-- | src/cpu/o3/sat_counter.hh (renamed from cpu/o3/sat_counter.hh) | 0 | ||||
-rw-r--r-- | src/cpu/o3/store_set.cc (renamed from cpu/o3/store_set.cc) | 0 | ||||
-rw-r--r-- | src/cpu/o3/store_set.hh (renamed from cpu/o3/store_set.hh) | 0 | ||||
-rw-r--r-- | src/cpu/o3/tournament_pred.cc (renamed from cpu/o3/tournament_pred.cc) | 0 | ||||
-rw-r--r-- | src/cpu/o3/tournament_pred.hh (renamed from cpu/o3/tournament_pred.hh) | 0 | ||||
-rw-r--r-- | src/cpu/op_class.cc | 50 | ||||
-rw-r--r-- | src/cpu/op_class.hh | 64 | ||||
-rw-r--r-- | src/cpu/ozone/cpu.cc (renamed from cpu/ozone/cpu.cc) | 0 | ||||
-rw-r--r-- | src/cpu/ozone/cpu.hh (renamed from cpu/ozone/cpu.hh) | 0 | ||||
-rw-r--r-- | src/cpu/ozone/cpu_impl.hh (renamed from cpu/ozone/cpu_impl.hh) | 0 | ||||
-rw-r--r-- | src/cpu/ozone/ea_list.cc (renamed from cpu/ozone/ea_list.cc) | 0 | ||||
-rw-r--r-- | src/cpu/ozone/ea_list.hh (renamed from cpu/ozone/ea_list.hh) | 0 | ||||
-rw-r--r-- | src/cpu/pc_event.cc (renamed from cpu/pc_event.cc) | 0 | ||||
-rw-r--r-- | src/cpu/pc_event.hh | 140 | ||||
-rw-r--r-- | src/cpu/profile.cc (renamed from cpu/profile.cc) | 0 | ||||
-rw-r--r-- | src/cpu/profile.hh (renamed from cpu/profile.hh) | 0 | ||||
-rw-r--r-- | src/cpu/simple/atomic.cc | 546 | ||||
-rw-r--r-- | src/cpu/simple/atomic.hh | 139 | ||||
-rw-r--r-- | src/cpu/simple/base.cc | 482 | ||||
-rw-r--r-- | src/cpu/simple/base.hh | 316 | ||||
-rw-r--r-- | src/cpu/simple/timing.cc | 570 | ||||
-rw-r--r-- | src/cpu/simple/timing.hh | 150 | ||||
-rw-r--r-- | src/cpu/smt.hh (renamed from cpu/smt.hh) | 0 | ||||
-rw-r--r-- | src/cpu/static_inst.cc (renamed from cpu/static_inst.cc) | 0 | ||||
-rw-r--r-- | src/cpu/static_inst.hh | 490 | ||||
-rw-r--r-- | src/cpu/trace/opt_cpu.cc (renamed from cpu/trace/opt_cpu.cc) | 0 | ||||
-rw-r--r-- | src/cpu/trace/opt_cpu.hh (renamed from cpu/trace/opt_cpu.hh) | 0 | ||||
-rw-r--r-- | src/cpu/trace/reader/ibm_reader.cc (renamed from cpu/trace/reader/ibm_reader.cc) | 0 | ||||
-rw-r--r-- | src/cpu/trace/reader/ibm_reader.hh (renamed from cpu/trace/reader/ibm_reader.hh) | 0 | ||||
-rw-r--r-- | src/cpu/trace/reader/itx_reader.cc (renamed from cpu/trace/reader/itx_reader.cc) | 0 | ||||
-rw-r--r-- | src/cpu/trace/reader/itx_reader.hh (renamed from cpu/trace/reader/itx_reader.hh) | 0 | ||||
-rw-r--r-- | src/cpu/trace/reader/m5_reader.cc (renamed from cpu/trace/reader/m5_reader.cc) | 0 | ||||
-rw-r--r-- | src/cpu/trace/reader/m5_reader.hh (renamed from cpu/trace/reader/m5_reader.hh) | 0 | ||||
-rw-r--r-- | src/cpu/trace/reader/mem_trace_reader.cc (renamed from cpu/trace/reader/mem_trace_reader.cc) | 0 | ||||
-rw-r--r-- | src/cpu/trace/reader/mem_trace_reader.hh (renamed from cpu/trace/reader/mem_trace_reader.hh) | 0 | ||||
-rw-r--r-- | src/cpu/trace/trace_cpu.cc (renamed from cpu/trace/trace_cpu.cc) | 0 | ||||
-rw-r--r-- | src/cpu/trace/trace_cpu.hh (renamed from cpu/trace/trace_cpu.hh) | 0 | ||||
-rw-r--r-- | src/dev/alpha_access.h (renamed from dev/alpha_access.h) | 0 | ||||
-rw-r--r-- | src/dev/alpha_console.cc | 344 | ||||
-rw-r--r-- | src/dev/alpha_console.hh | 129 | ||||
-rw-r--r-- | src/dev/baddev.cc | 97 | ||||
-rw-r--r-- | src/dev/baddev.hh | 72 | ||||
-rw-r--r-- | src/dev/disk_image.cc | 470 | ||||
-rw-r--r-- | src/dev/disk_image.hh (renamed from dev/disk_image.hh) | 0 | ||||
-rw-r--r-- | src/dev/etherbus.cc | 125 | ||||
-rw-r--r-- | src/dev/etherbus.hh | 79 | ||||
-rw-r--r-- | src/dev/etherdump.cc | 136 | ||||
-rw-r--r-- | src/dev/etherdump.hh | 59 | ||||
-rw-r--r-- | src/dev/etherint.cc (renamed from dev/etherint.cc) | 0 | ||||
-rw-r--r-- | src/dev/etherint.hh | 66 | ||||
-rw-r--r-- | src/dev/etherlink.cc | 300 | ||||
-rw-r--r-- | src/dev/etherlink.hh | 130 | ||||
-rw-r--r-- | src/dev/etherpkt.cc | 53 | ||||
-rw-r--r-- | src/dev/etherpkt.hh | 84 | ||||
-rw-r--r-- | src/dev/ethertap.cc | 345 | ||||
-rw-r--r-- | src/dev/ethertap.hh | 107 | ||||
-rw-r--r-- | src/dev/ide_atareg.h (renamed from dev/ide_atareg.h) | 0 | ||||
-rw-r--r-- | src/dev/ide_ctrl.cc | 814 | ||||
-rw-r--r-- | src/dev/ide_ctrl.hh | 241 | ||||
-rw-r--r-- | src/dev/ide_disk.cc | 1146 | ||||
-rw-r--r-- | src/dev/ide_disk.hh | 367 | ||||
-rw-r--r-- | src/dev/ide_wdcreg.h (renamed from dev/ide_wdcreg.h) | 0 | ||||
-rw-r--r-- | src/dev/io_device.cc | 225 | ||||
-rw-r--r-- | src/dev/io_device.hh | 335 | ||||
-rw-r--r-- | src/dev/isa_fake.cc | 121 | ||||
-rw-r--r-- | src/dev/isa_fake.hh | 78 | ||||
-rw-r--r-- | src/dev/ns_gige.cc | 2914 | ||||
-rw-r--r-- | src/dev/ns_gige.hh | 463 | ||||
-rw-r--r-- | src/dev/ns_gige_reg.h (renamed from dev/ns_gige_reg.h) | 0 | ||||
-rw-r--r-- | src/dev/pciconfigall.cc | 224 | ||||
-rw-r--r-- | src/dev/pciconfigall.hh | 128 | ||||
-rw-r--r-- | src/dev/pcidev.cc | 386 | ||||
-rw-r--r-- | src/dev/pcidev.hh | 230 | ||||
-rw-r--r-- | src/dev/pcireg.h (renamed from dev/pcireg.h) | 0 | ||||
-rw-r--r-- | src/dev/pitreg.h (renamed from dev/pitreg.h) | 0 | ||||
-rw-r--r-- | src/dev/pktfifo.cc | 99 | ||||
-rw-r--r-- | src/dev/pktfifo.hh | 168 | ||||
-rw-r--r-- | src/dev/platform.cc | 64 | ||||
-rw-r--r-- | src/dev/platform.hh | 73 | ||||
-rw-r--r-- | src/dev/rtcreg.h (renamed from dev/rtcreg.h) | 0 | ||||
-rw-r--r-- | src/dev/simconsole.cc | 413 | ||||
-rw-r--r-- | src/dev/simconsole.hh | 165 | ||||
-rw-r--r-- | src/dev/simple_disk.cc | 111 | ||||
-rw-r--r-- | src/dev/simple_disk.hh | 62 | ||||
-rw-r--r-- | src/dev/sinic.cc | 1756 | ||||
-rw-r--r-- | src/dev/sinic.hh | 371 | ||||
-rw-r--r-- | src/dev/sinicreg.hh (renamed from dev/sinicreg.hh) | 0 | ||||
-rw-r--r-- | src/dev/tsunami.cc | 127 | ||||
-rw-r--r-- | src/dev/tsunami.hh | 130 | ||||
-rw-r--r-- | src/dev/tsunami_cchip.cc | 554 | ||||
-rw-r--r-- | src/dev/tsunami_cchip.hh | 150 | ||||
-rw-r--r-- | src/dev/tsunami_io.cc | 685 | ||||
-rw-r--r-- | src/dev/tsunami_io.hh | 351 | ||||
-rw-r--r-- | src/dev/tsunami_pchip.cc | 358 | ||||
-rw-r--r-- | src/dev/tsunami_pchip.hh | 98 | ||||
-rw-r--r-- | src/dev/tsunamireg.h (renamed from dev/tsunamireg.h) | 0 | ||||
-rw-r--r-- | src/dev/uart.cc | 52 | ||||
-rw-r--r-- | src/dev/uart.hh | 79 | ||||
-rw-r--r-- | src/dev/uart8250.cc | 366 | ||||
-rw-r--r-- | src/dev/uart8250.hh | 105 | ||||
-rw-r--r-- | src/kern/kernel_stats.cc (renamed from kern/kernel_stats.cc) | 0 | ||||
-rw-r--r-- | src/kern/kernel_stats.hh (renamed from kern/kernel_stats.hh) | 0 | ||||
-rw-r--r-- | src/kern/linux/events.cc | 55 | ||||
-rw-r--r-- | src/kern/linux/events.hh (renamed from kern/linux/events.hh) | 0 | ||||
-rw-r--r-- | src/kern/linux/linux.hh | 283 | ||||
-rw-r--r-- | src/kern/linux/linux_syscalls.cc (renamed from kern/linux/linux_syscalls.cc) | 0 | ||||
-rw-r--r-- | src/kern/linux/linux_syscalls.hh (renamed from kern/linux/linux_syscalls.hh) | 0 | ||||
-rw-r--r-- | src/kern/linux/printk.cc | 261 | ||||
-rw-r--r-- | src/kern/linux/printk.hh | 36 | ||||
-rw-r--r-- | src/kern/linux/sched.hh (renamed from kern/linux/sched.hh) | 0 | ||||
-rw-r--r-- | src/kern/solaris/solaris.hh | 304 | ||||
-rw-r--r-- | src/kern/system_events.cc | 94 | ||||
-rw-r--r-- | src/kern/system_events.hh (renamed from kern/system_events.hh) | 0 | ||||
-rw-r--r-- | src/kern/tru64/dump_mbuf.cc (renamed from kern/tru64/dump_mbuf.cc) | 0 | ||||
-rw-r--r-- | src/kern/tru64/dump_mbuf.hh | 38 | ||||
-rw-r--r-- | src/kern/tru64/mbuf.hh (renamed from kern/tru64/mbuf.hh) | 0 | ||||
-rw-r--r-- | src/kern/tru64/printf.cc | 266 | ||||
-rw-r--r-- | src/kern/tru64/printf.hh | 38 | ||||
-rw-r--r-- | src/kern/tru64/tru64.hh | 1240 | ||||
-rw-r--r-- | src/kern/tru64/tru64_events.cc | 105 | ||||
-rw-r--r-- | src/kern/tru64/tru64_events.hh (renamed from kern/tru64/tru64_events.hh) | 0 | ||||
-rw-r--r-- | src/kern/tru64/tru64_syscalls.cc (renamed from kern/tru64/tru64_syscalls.cc) | 0 | ||||
-rw-r--r-- | src/kern/tru64/tru64_syscalls.hh (renamed from kern/tru64/tru64_syscalls.hh) | 0 | ||||
-rw-r--r-- | src/mem/bridge.cc | 263 | ||||
-rw-r--r-- | src/mem/bridge.hh | 184 | ||||
-rw-r--r-- | src/mem/bus.cc | 206 | ||||
-rw-r--r-- | src/mem/bus.hh | 158 | ||||
-rw-r--r-- | src/mem/cache/prefetch/tagged_prefetcher_impl.hh (renamed from mem/cache/prefetch/tagged_prefetcher_impl.hh) | 0 | ||||
-rw-r--r-- | src/mem/config/prefetch.hh (renamed from mem/config/prefetch.hh) | 0 | ||||
-rw-r--r-- | src/mem/mem_object.cc | 37 | ||||
-rw-r--r-- | src/mem/mem_object.hh | 54 | ||||
-rw-r--r-- | src/mem/packet.cc | 118 | ||||
-rw-r--r-- | src/mem/packet.hh | 256 | ||||
-rw-r--r-- | src/mem/page_table.cc | 134 | ||||
-rw-r--r-- | src/mem/page_table.hh | 90 | ||||
-rw-r--r-- | src/mem/physical.cc | 377 | ||||
-rw-r--r-- | src/mem/physical.hh | 127 | ||||
-rw-r--r-- | src/mem/port.cc | 84 | ||||
-rw-r--r-- | src/mem/port.hh | 270 | ||||
-rw-r--r-- | src/mem/request.hh | 201 | ||||
-rw-r--r-- | src/mem/translating_port.cc | 187 | ||||
-rw-r--r-- | src/mem/translating_port.hh | 61 | ||||
-rw-r--r-- | src/mem/vport.cc | 69 | ||||
-rw-r--r-- | src/mem/vport.hh | 76 | ||||
-rw-r--r-- | src/python/SConscript | 207 | ||||
-rw-r--r-- | src/python/m5/__init__.py (renamed from python/m5/__init__.py) | 0 | ||||
-rw-r--r-- | src/python/m5/config.py (renamed from python/m5/config.py) | 0 | ||||
-rw-r--r-- | src/python/m5/convert.py (renamed from python/m5/convert.py) | 0 | ||||
-rw-r--r-- | src/python/m5/multidict.py (renamed from python/m5/multidict.py) | 0 | ||||
-rw-r--r-- | src/python/m5/objects/AlphaConsole.py | 9 | ||||
-rw-r--r-- | src/python/m5/objects/AlphaFullCPU.py (renamed from python/m5/objects/AlphaFullCPU.py) | 0 | ||||
-rw-r--r-- | src/python/m5/objects/AlphaTLB.py (renamed from python/m5/objects/AlphaTLB.py) | 0 | ||||
-rw-r--r-- | src/python/m5/objects/BadDevice.py | 6 | ||||
-rw-r--r-- | src/python/m5/objects/BaseCPU.py | 27 | ||||
-rw-r--r-- | src/python/m5/objects/BaseCache.py (renamed from python/m5/objects/BaseCache.py) | 0 | ||||
-rw-r--r-- | src/python/m5/objects/Bridge.py | 9 | ||||
-rw-r--r-- | src/python/m5/objects/Bus.py | 6 | ||||
-rw-r--r-- | src/python/m5/objects/CoherenceProtocol.py (renamed from python/m5/objects/CoherenceProtocol.py) | 0 | ||||
-rw-r--r-- | src/python/m5/objects/Device.py | 18 | ||||
-rw-r--r-- | src/python/m5/objects/DiskImage.py (renamed from python/m5/objects/DiskImage.py) | 0 | ||||
-rw-r--r-- | src/python/m5/objects/Ethernet.py | 115 | ||||
-rw-r--r-- | src/python/m5/objects/Ide.py | 14 | ||||
-rw-r--r-- | src/python/m5/objects/IntrControl.py (renamed from python/m5/objects/IntrControl.py) | 0 | ||||
-rw-r--r-- | src/python/m5/objects/MemObject.py | 5 | ||||
-rw-r--r-- | src/python/m5/objects/MemTest.py (renamed from python/m5/objects/MemTest.py) | 0 | ||||
-rw-r--r-- | src/python/m5/objects/Pci.py | 55 | ||||
-rw-r--r-- | src/python/m5/objects/PhysicalMemory.py | 8 | ||||
-rw-r--r-- | src/python/m5/objects/Platform.py (renamed from python/m5/objects/Platform.py) | 0 | ||||
-rw-r--r-- | src/python/m5/objects/Process.py | 27 | ||||
-rw-r--r-- | src/python/m5/objects/Repl.py (renamed from python/m5/objects/Repl.py) | 0 | ||||
-rw-r--r-- | src/python/m5/objects/Root.py | 23 | ||||
-rw-r--r-- | src/python/m5/objects/SimConsole.py (renamed from python/m5/objects/SimConsole.py) | 0 | ||||
-rw-r--r-- | src/python/m5/objects/SimpleDisk.py | 5 | ||||
-rw-r--r-- | src/python/m5/objects/System.py | 21 | ||||
-rw-r--r-- | src/python/m5/objects/Tsunami.py | 27 | ||||
-rw-r--r-- | src/python/m5/objects/Uart.py | 15 | ||||
-rw-r--r-- | src/python/m5/smartdict.py (renamed from python/m5/smartdict.py) | 0 | ||||
-rw-r--r-- | src/sim/async.hh (renamed from sim/async.hh) | 0 | ||||
-rw-r--r-- | src/sim/builder.cc (renamed from sim/builder.cc) | 0 | ||||
-rw-r--r-- | src/sim/builder.hh (renamed from sim/builder.hh) | 0 | ||||
-rw-r--r-- | src/sim/byteswap.hh | 163 | ||||
-rw-r--r-- | src/sim/debug.cc (renamed from sim/debug.cc) | 0 | ||||
-rw-r--r-- | src/sim/debug.hh (renamed from sim/debug.hh) | 0 | ||||
-rw-r--r-- | src/sim/eventq.cc | 258 | ||||
-rw-r--r-- | src/sim/eventq.hh (renamed from sim/eventq.hh) | 0 | ||||
-rw-r--r-- | src/sim/faults.cc | 52 | ||||
-rw-r--r-- | src/sim/faults.hh | 80 | ||||
-rw-r--r-- | src/sim/host.hh | 67 | ||||
-rw-r--r-- | src/sim/main.cc | 433 | ||||
-rw-r--r-- | src/sim/param.cc | 793 | ||||
-rw-r--r-- | src/sim/param.hh (renamed from sim/param.hh) | 0 | ||||
-rw-r--r-- | src/sim/process.cc | 361 | ||||
-rw-r--r-- | src/sim/process.hh | 192 | ||||
-rw-r--r-- | src/sim/pseudo_inst.cc | 290 | ||||
-rw-r--r-- | src/sim/pseudo_inst.hh (renamed from sim/pseudo_inst.hh) | 0 | ||||
-rw-r--r-- | src/sim/root.cc (renamed from sim/root.cc) | 0 | ||||
-rw-r--r-- | src/sim/serialize.cc (renamed from sim/serialize.cc) | 0 | ||||
-rw-r--r-- | src/sim/serialize.hh (renamed from sim/serialize.hh) | 0 | ||||
-rw-r--r-- | src/sim/sim_events.cc (renamed from sim/sim_events.cc) | 0 | ||||
-rw-r--r-- | src/sim/sim_events.hh (renamed from sim/sim_events.hh) | 0 | ||||
-rw-r--r-- | src/sim/sim_exit.hh (renamed from sim/sim_exit.hh) | 0 | ||||
-rw-r--r-- | src/sim/sim_object.cc | 258 | ||||
-rw-r--r-- | src/sim/sim_object.hh | 119 | ||||
-rw-r--r-- | src/sim/startup.cc (renamed from sim/startup.cc) | 0 | ||||
-rw-r--r-- | src/sim/startup.hh (renamed from sim/startup.hh) | 0 | ||||
-rw-r--r-- | src/sim/stat_control.cc (renamed from sim/stat_control.cc) | 0 | ||||
-rw-r--r-- | src/sim/stat_control.hh (renamed from sim/stat_control.hh) | 0 | ||||
-rw-r--r-- | src/sim/stats.hh (renamed from sim/stats.hh) | 0 | ||||
-rw-r--r-- | src/sim/syscall_emul.cc | 454 | ||||
-rw-r--r-- | src/sim/syscall_emul.hh | 849 | ||||
-rw-r--r-- | src/sim/system.cc | 267 | ||||
-rw-r--r-- | src/sim/system.hh | 229 | ||||
-rw-r--r-- | src/sim/vptr.hh | 122 | ||||
-rw-r--r-- | src/unittest/Makefile | 98 | ||||
-rw-r--r-- | src/unittest/bitvectest.cc (renamed from test/bitvectest.cc) | 0 | ||||
-rw-r--r-- | src/unittest/circletest.cc (renamed from test/circletest.cc) | 0 | ||||
-rw-r--r-- | src/unittest/cprintftest.cc | 163 | ||||
-rw-r--r-- | src/unittest/foo.ini (renamed from test/foo.ini) | 0 | ||||
-rwxr-xr-x | src/unittest/genini.py (renamed from test/genini.py) | 0 | ||||
-rw-r--r-- | src/unittest/initest.cc (renamed from test/initest.cc) | 0 | ||||
-rw-r--r-- | src/unittest/initest.ini (renamed from test/initest.ini) | 0 | ||||
-rw-r--r-- | src/unittest/lru_test.cc (renamed from test/lru_test.cc) | 0 | ||||
-rw-r--r-- | src/unittest/nmtest.cc (renamed from test/nmtest.cc) | 0 | ||||
-rw-r--r-- | src/unittest/offtest.cc (renamed from test/offtest.cc) | 0 | ||||
-rw-r--r-- | src/unittest/paramtest.cc (renamed from test/paramtest.cc) | 0 | ||||
-rw-r--r-- | src/unittest/rangetest.cc (renamed from test/rangetest.cc) | 0 | ||||
-rw-r--r-- | src/unittest/sized_test.cc (renamed from test/sized_test.cc) | 0 | ||||
-rw-r--r-- | src/unittest/stattest.cc (renamed from test/stattest.cc) | 0 | ||||
-rw-r--r-- | src/unittest/strnumtest.cc (renamed from test/strnumtest.cc) | 0 | ||||
-rw-r--r-- | src/unittest/symtest.cc (renamed from test/symtest.cc) | 0 | ||||
-rw-r--r-- | src/unittest/tokentest.cc (renamed from test/tokentest.cc) | 0 | ||||
-rw-r--r-- | src/unittest/tracetest.cc (renamed from test/tracetest.cc) | 0 | ||||
-rw-r--r-- | test/Makefile | 69 | ||||
-rw-r--r-- | test/cprintftest.cc | 164 | ||||
-rwxr-xr-x | util/qdo | 4 |
885 files changed, 82744 insertions, 62207 deletions
@@ -1,4 +1,4 @@ -Copyright (c) 2000-2005 The Regents of The University of Michigan +Copyright (c) 2000-2006 The Regents of The University of Michigan All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/SConscript b/SConscript deleted file mode 100644 index e5ca7c380..000000000 --- a/SConscript +++ /dev/null @@ -1,421 +0,0 @@ -# -*- mode:python -*- - -# Copyright (c) 2004-2005 The Regents of The University of Michigan -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer; -# redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution; -# neither the name of the copyright holders nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -import os -import sys -from os.path import isdir - -# This file defines how to build a particular configuration of M5 -# based on variable settings in the 'env' build environment. - -# Import build environment variable from SConstruct. -Import('env') - -################################################### -# -# Define needed sources. -# -################################################### - -# Base sources used by all configurations. - -base_sources = Split(''' - base/circlebuf.cc - base/copyright.cc - base/cprintf.cc - base/embedfile.cc - base/fast_alloc.cc - base/fifo_buffer.cc - base/hostinfo.cc - base/hybrid_pred.cc - base/inifile.cc - base/intmath.cc - base/match.cc - base/misc.cc - base/output.cc - base/pollevent.cc - base/range.cc - base/random.cc - base/sat_counter.cc - base/socket.cc - base/statistics.cc - base/str.cc - base/time.cc - base/trace.cc - base/traceflags.cc - base/userinfo.cc - base/compression/lzss_compression.cc - base/loader/aout_object.cc - base/loader/ecoff_object.cc - base/loader/elf_object.cc - base/loader/object_file.cc - base/loader/symtab.cc - base/stats/events.cc - base/stats/statdb.cc - base/stats/visit.cc - base/stats/text.cc - - cpu/activity.cc - cpu/base.cc - cpu/base_dyn_inst.cc - cpu/cpu_exec_context.cc - cpu/exetrace.cc - cpu/pc_event.cc - cpu/quiesce_event.cc - cpu/static_inst.cc - cpu/sampler/sampler.cc - cpu/trace/reader/mem_trace_reader.cc - cpu/trace/reader/ibm_reader.cc - cpu/trace/reader/itx_reader.cc - cpu/trace/reader/m5_reader.cc - cpu/trace/opt_cpu.cc - cpu/trace/trace_cpu.cc - - encumbered/mem/functional/main.cc - - mem/base_hier.cc - mem/base_mem.cc - mem/hier_params.cc - mem/mem_cmd.cc - mem/mem_debug.cc - mem/mem_req.cc - mem/memory_interface.cc - mem/bus/base_interface.cc - mem/bus/bus.cc - mem/bus/bus_bridge.cc - mem/bus/bus_bridge_master.cc - mem/bus/bus_bridge_slave.cc - mem/bus/bus_interface.cc - mem/bus/dma_bus_interface.cc - mem/bus/dma_interface.cc - mem/bus/master_interface.cc - mem/bus/slave_interface.cc - mem/cache/base_cache.cc - mem/cache/cache.cc - mem/cache/cache_builder.cc - mem/cache/coherence/coherence_protocol.cc - mem/cache/coherence/uni_coherence.cc - mem/cache/miss/blocking_buffer.cc - mem/cache/miss/miss_queue.cc - mem/cache/miss/mshr.cc - mem/cache/miss/mshr_queue.cc - mem/cache/prefetch/base_prefetcher.cc - mem/cache/prefetch/prefetcher.cc - mem/cache/prefetch/tagged_prefetcher.cc - mem/cache/tags/base_tags.cc - mem/cache/tags/cache_tags.cc - mem/cache/tags/fa_lru.cc - mem/cache/tags/iic.cc - mem/cache/tags/lru.cc - mem/cache/tags/repl/gen.cc - mem/cache/tags/repl/repl.cc - mem/cache/tags/split.cc - mem/cache/tags/split_lru.cc - mem/cache/tags/split_lifo.cc - mem/functional/functional.cc - mem/timing/base_memory.cc - mem/timing/dram_memory.cc - mem/timing/dram_mem_bank.cc - mem/timing/dram_memory_builder.cc - mem/timing/memory_builder.cc - mem/timing/simple_mem_bank.cc - mem/trace/itx_writer.cc - mem/trace/mem_trace_writer.cc - mem/trace/m5_writer.cc - - python/pyconfig.cc - python/embedded_py.cc - - sim/builder.cc - sim/configfile.cc - sim/debug.cc - sim/eventq.cc - sim/faults.cc - sim/main.cc - sim/param.cc - sim/profile.cc - sim/root.cc - sim/serialize.cc - sim/sim_events.cc - sim/sim_exit.cc - sim/sim_object.cc - sim/startup.cc - sim/stat_context.cc - sim/stat_control.cc - sim/trace_context.cc - ''') - -# Old FullCPU sources -full_cpu_sources = Split(''' - encumbered/cpu/full/bpred.cc - encumbered/cpu/full/commit.cc - encumbered/cpu/full/cpu.cc - encumbered/cpu/full/create_vector.cc - encumbered/cpu/full/cv_spec_state.cc - encumbered/cpu/full/dd_queue.cc - encumbered/cpu/full/dep_link.cc - encumbered/cpu/full/dispatch.cc - encumbered/cpu/full/dyn_inst.cc - encumbered/cpu/full/execute.cc - encumbered/cpu/full/fetch.cc - encumbered/cpu/full/floss_reasons.cc - encumbered/cpu/full/fu_pool.cc - encumbered/cpu/full/inst_fifo.cc - encumbered/cpu/full/instpipe.cc - encumbered/cpu/full/issue.cc - encumbered/cpu/full/ls_queue.cc - encumbered/cpu/full/machine_queue.cc - encumbered/cpu/full/pipetrace.cc - encumbered/cpu/full/readyq.cc - encumbered/cpu/full/reg_info.cc - encumbered/cpu/full/rob_station.cc - encumbered/cpu/full/spec_memory.cc - encumbered/cpu/full/spec_state.cc - encumbered/cpu/full/storebuffer.cc - encumbered/cpu/full/writeback.cc - encumbered/cpu/full/iq/iq_station.cc - encumbered/cpu/full/iq/iqueue.cc - encumbered/cpu/full/iq/segmented/chain_info.cc - encumbered/cpu/full/iq/segmented/chain_wire.cc - encumbered/cpu/full/iq/segmented/iq_seg.cc - encumbered/cpu/full/iq/segmented/iq_segmented.cc - encumbered/cpu/full/iq/segmented/seg_chain.cc - encumbered/cpu/full/iq/seznec/iq_seznec.cc - encumbered/cpu/full/iq/standard/iq_standard.cc - ''') - -# MySql sources -mysql_sources = Split(''' - base/mysql.cc - base/stats/mysql.cc - ''') - -# Full-system sources -full_system_sources = Split(''' - base/crc.cc - base/inet.cc - base/remote_gdb.cc - - cpu/intr_control.cc - cpu/profile.cc - - dev/alpha_console.cc - dev/baddev.cc - dev/simconsole.cc - dev/disk_image.cc - dev/etherbus.cc - dev/etherdump.cc - dev/etherint.cc - dev/etherlink.cc - dev/etherpkt.cc - dev/ethertap.cc - dev/ide_ctrl.cc - dev/ide_disk.cc - dev/io_device.cc - dev/ns_gige.cc - dev/pciconfigall.cc - dev/pcidev.cc - dev/pcifake.cc - dev/pktfifo.cc - dev/platform.cc - dev/sinic.cc - dev/simple_disk.cc - dev/tsunami.cc - dev/tsunami_cchip.cc - dev/isa_fake.cc - dev/tsunami_io.cc - dev/tsunami_pchip.cc - dev/uart.cc - dev/uart8250.cc - - kern/kernel_binning.cc - kern/kernel_stats.cc - kern/system_events.cc - kern/linux/events.cc - kern/linux/linux_syscalls.cc - kern/linux/printk.cc - kern/tru64/dump_mbuf.cc - kern/tru64/printf.cc - kern/tru64/tru64_events.cc - kern/tru64/tru64_syscalls.cc - - mem/functional/memory_control.cc - mem/functional/physical.cc - - sim/system.cc - sim/pseudo_inst.cc - ''') - -# turbolaser encumbered sources -turbolaser_sources = Split(''' - encumbered/dev/dma.cc - encumbered/dev/etherdev.cc - encumbered/dev/scsi.cc - encumbered/dev/scsi_ctrl.cc - encumbered/dev/scsi_disk.cc - encumbered/dev/scsi_none.cc - encumbered/dev/tlaser_clock.cc - encumbered/dev/tlaser_ipi.cc - encumbered/dev/tlaser_mbox.cc - encumbered/dev/tlaser_mc146818.cc - encumbered/dev/tlaser_node.cc - encumbered/dev/tlaser_pcia.cc - encumbered/dev/tlaser_pcidev.cc - encumbered/dev/tlaser_serial.cc - encumbered/dev/turbolaser.cc - encumbered/dev/uart8530.cc - ''') - -# Syscall emulation (non-full-system) sources -syscall_emulation_sources = Split(''' - cpu/memtest/memtest.cc - encumbered/eio/eio.cc - encumbered/eio/exolex.cc - encumbered/eio/libexo.cc - kern/linux/linux.cc - kern/tru64/tru64.cc - sim/process.cc - sim/syscall_emul.cc - ''') - -# Add a flag defining what THE_ISA should be for all compilation -env.Append(CPPDEFINES=[('THE_ISA','%s_ISA' % env['TARGET_ISA'].upper())]) - -arch_sources = SConscript('arch/SConscript', - exports = 'env', duplicate = False) - -cpu_sources = SConscript('cpu/SConscript', - exports = 'env', duplicate = False) - -# This is outside of cpu/SConscript since the source directory isn't -# underneath 'cpu'. -if 'FullCPU' in env['CPU_MODELS']: - cpu_sources += full_cpu_sources - -# Set up complete list of sources based on configuration. -sources = base_sources + arch_sources + cpu_sources - -if env['FULL_SYSTEM']: - sources += full_system_sources - if env['ALPHA_TLASER']: - sources += turbolaser_sources -else: - sources += syscall_emulation_sources - -if env['USE_MYSQL']: - sources += mysql_sources - -for opt in env.ExportOptions: - env.ConfigFile(opt) - -################################################### -# -# Special build rules. -# -################################################### - -# base/traceflags.{cc,hh} are generated from base/traceflags.py. -# $TARGET.base will expand to "<build-dir>/base/traceflags". -env.Command(Split('base/traceflags.hh base/traceflags.cc'), - 'base/traceflags.py', - 'python $SOURCE $TARGET.base') - -# libelf build is described in its own SConscript file. -# SConscript-local is the per-config build, which just copies some -# header files into a place where they can be found. -SConscript('libelf/SConscript-local', exports = 'env', duplicate=0) -SConscript('python/SConscript', exports = ['env'], duplicate=0) - -# This function adds the specified sources to the given build -# environment, and returns a list of all the corresponding SCons -# Object nodes (including an extra one for date.cc). We explicitly -# add the Object nodes so we can set up special dependencies for -# date.cc. -def make_objs(sources, env): - objs = [env.Object(s) for s in sources] - # make date.cc depend on all other objects so it always gets - # recompiled whenever anything else does - date_obj = env.Object('base/date.cc') - env.Depends(date_obj, objs) - objs.append(date_obj) - return objs - -################################################### -# -# Define binaries. Each different build type (debug, opt, etc.) gets -# a slightly different build environment. -# -################################################### - -# Include file paths are rooted in this directory. SCons will -# automatically expand '.' to refer to both the source directory and -# the corresponding build directory to pick up generated include -# files. -env.Append(CPPPATH='.') -env.Append(CPPPATH='./libelf') - -# Debug binary -debugEnv = env.Copy(OBJSUFFIX='.do') -debugEnv.Label = 'debug' -debugEnv.Append(CCFLAGS=Split('-g -gdwarf-2 -O0')) -debugEnv.Append(CPPDEFINES='DEBUG') -tlist = debugEnv.Program(target = 'm5.debug', - source = make_objs(sources, debugEnv)) -debugEnv.M5Binary = tlist[0] - -# Optimized binary -optEnv = env.Copy() -optEnv.Label = 'opt' -optEnv.Append(CCFLAGS=Split('-g -O5')) -tlist = optEnv.Program(target = 'm5.opt', - source = make_objs(sources, optEnv)) -optEnv.M5Binary = tlist[0] - -# "Fast" binary -fastEnv = env.Copy(OBJSUFFIX='.fo') -fastEnv.Label = 'fast' -fastEnv.Append(CCFLAGS=Split('-O5')) -fastEnv.Append(CPPDEFINES='NDEBUG') -fastEnv.Program(target = 'm5.fast.unstripped', - source = make_objs(sources, fastEnv)) -tlist = fastEnv.Command(target = 'm5.fast', - source = 'm5.fast.unstripped', - action = 'strip $SOURCE -o $TARGET') -fastEnv.M5Binary = tlist[0] - -# Profiled binary -profEnv = env.Copy(OBJSUFFIX='.po') -profEnv.Label = 'prof' -profEnv.Append(CCFLAGS=Split('-O5 -g -pg'), LINKFLAGS='-pg') -tlist = profEnv.Program(target = 'm5.prof', - source = make_objs(sources, profEnv)) -profEnv.M5Binary = tlist[0] - -envList = [debugEnv, optEnv, fastEnv, profEnv] - -Return('envList') diff --git a/SConstruct b/SConstruct new file mode 100644 index 000000000..f2a41400c --- /dev/null +++ b/SConstruct @@ -0,0 +1,438 @@ +# -*- mode:python -*- + +# Copyright (c) 2004-2005 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +################################################### +# +# SCons top-level build description (SConstruct) file. +# +# While in this directory ('m5'), just type 'scons' to build the default +# configuration (see below), or type 'scons build/<CONFIG>/<binary>' +# to build some other configuration (e.g., 'build/ALPHA_FS/m5.opt' for +# the optimized full-system version). +# +# You can build M5 in a different directory as long as there is a +# 'build/<CONFIG>' somewhere along the target path. The build system +# expdects that all configs under the same build directory are being +# built for the same host system. +# +# Examples: +# These two commands are equivalent. The '-u' option tells scons to +# search up the directory tree for this SConstruct file. +# % cd <path-to-src>/m5 ; scons build/ALPHA_FS/m5.debug +# % cd <path-to-src>/m5/build/ALPHA_FS; scons -u m5.debug +# These two commands are equivalent and demonstrate building in a +# directory outside of the source tree. The '-C' option tells scons +# to chdir to the specified directory to find this SConstruct file. +# % cd <path-to-src>/m5 ; scons /local/foo/build/ALPHA_FS/m5.debug +# % cd /local/foo/build/ALPHA_FS; scons -C <path-to-src>/m5 m5.debug +# +# You can use 'scons -H' to print scons options. If you're in this +# 'm5' directory (or use -u or -C to tell scons where to find this +# file), you can use 'scons -h' to print all the M5-specific build +# options as well. +# +################################################### + +# Python library imports +import sys +import os + +# Check for recent-enough Python and SCons versions +EnsurePythonVersion(2,3) + +# Ironically, SCons 0.96 dies if you give EnsureSconsVersion a +# 3-element version number. +min_scons_version = (0,96,91) +try: + EnsureSConsVersion(*min_scons_version) +except: + print "Error checking current SCons version." + print "SCons", ".".join(map(str,min_scons_version)), "or greater required." + Exit(2) + + +# The absolute path to the current directory (where this file lives). +ROOT = Dir('.').abspath + +# Paths to the M5 and external source trees. +SRCDIR = os.path.join(ROOT, 'src') + +# tell python where to find m5 python code +sys.path.append(os.path.join(ROOT, 'src/python')) + +################################################### +# +# Figure out which configurations to set up based on the path(s) of +# the target(s). +# +################################################### + +# Find default configuration & binary. +Default(os.environ.get('M5_DEFAULT_BINARY', 'build/ALPHA_SE/m5.debug')) + +# Ask SCons which directory it was invoked from. +launch_dir = GetLaunchDir() + +# Make targets relative to invocation directory +abs_targets = map(lambda x: os.path.normpath(os.path.join(launch_dir, str(x))), + BUILD_TARGETS) + +# helper function: find last occurrence of element in list +def rfind(l, elt, offs = -1): + for i in range(len(l)+offs, 0, -1): + if l[i] == elt: + return i + raise ValueError, "element not found" + +# Each target must have 'build' in the interior of the path; the +# directory below this will determine the build parameters. For +# example, for target 'foo/bar/build/ALPHA_SE/arch/alpha/blah.do' we +# recognize that ALPHA_SE specifies the configuration because it +# follow 'build' in the bulid path. + +# Generate a list of the unique build roots and configs that the +# collected targets reference. +build_paths = [] +build_root = None +for t in abs_targets: + path_dirs = t.split('/') + try: + build_top = rfind(path_dirs, 'build', -2) + except: + print "Error: no non-leaf 'build' dir found on target path", t + Exit(1) + this_build_root = os.path.join('/',*path_dirs[:build_top+1]) + if not build_root: + build_root = this_build_root + else: + if this_build_root != build_root: + print "Error: build targets not under same build root\n"\ + " %s\n %s" % (build_root, this_build_root) + Exit(1) + build_path = os.path.join('/',*path_dirs[:build_top+2]) + if build_path not in build_paths: + build_paths.append(build_path) + +################################################### +# +# Set up the default build environment. This environment is copied +# and modified according to each selected configuration. +# +################################################### + +env = Environment(ENV = os.environ, # inherit user's environment vars + ROOT = ROOT, + SRCDIR = SRCDIR) + +env.SConsignFile("sconsign") + +# I waffle on this setting... it does avoid a few painful but +# unnecessary builds, but it also seems to make trivial builds take +# noticeably longer. +if False: + env.TargetSignatures('content') + +# M5_PLY is used by isa_parser.py to find the PLY package. +env.Append(ENV = { 'M5_PLY' : Dir('ext/ply') }) + +# Set up default C++ compiler flags +env.Append(CCFLAGS='-pipe') +env.Append(CCFLAGS='-fno-strict-aliasing') +env.Append(CCFLAGS=Split('-Wall -Wno-sign-compare -Werror -Wundef')) +if sys.platform == 'cygwin': + # cygwin has some header file issues... + env.Append(CCFLAGS=Split("-Wno-uninitialized")) +env.Append(CPPPATH=[Dir('ext/dnet')]) + +# Default libraries +env.Append(LIBS=['z']) + +# Platform-specific configuration. Note again that we assume that all +# builds under a given build root run on the same host platform. +conf = Configure(env, + conf_dir = os.path.join(build_root, '.scons_config'), + log_file = os.path.join(build_root, 'scons_config.log')) + +# Check for <fenv.h> (C99 FP environment control) +have_fenv = conf.CheckHeader('fenv.h', '<>') +if not have_fenv: + print "Warning: Header file <fenv.h> not found." + print " This host has no IEEE FP rounding mode control." + +# Check for mysql. +mysql_config = WhereIs('mysql_config') +have_mysql = mysql_config != None + +# Check MySQL version. +if have_mysql: + mysql_version = os.popen(mysql_config + ' --version').read() + mysql_version = mysql_version.split('.') + mysql_major = int(mysql_version[0]) + mysql_minor = int(mysql_version[1]) + # This version check is probably overly conservative, but it deals + # with the versions we have installed. + if mysql_major < 4 or (mysql_major == 4 and mysql_minor < 1): + print "Warning: MySQL v4.1 or newer required." + have_mysql = False + +# Set up mysql_config commands. +if have_mysql: + mysql_config_include = mysql_config + ' --include' + if os.system(mysql_config_include + ' > /dev/null') != 0: + # older mysql_config versions don't support --include, use + # --cflags instead + mysql_config_include = mysql_config + ' --cflags | sed s/\\\'//g' + # This seems to work in all versions + mysql_config_libs = mysql_config + ' --libs' + +env = conf.Finish() + +# Define the universe of supported ISAs +env['ALL_ISA_LIST'] = ['alpha', 'sparc', 'mips'] + +# Define the universe of supported CPU models +env['ALL_CPU_LIST'] = ['AtomicSimpleCPU', 'TimingSimpleCPU', + 'FullCPU', 'AlphaFullCPU', + 'OzoneSimpleCPU', 'OzoneCPU', 'CheckerCPU'] + +# Sticky options get saved in the options file so they persist from +# one invocation to the next (unless overridden, in which case the new +# value becomes sticky). +sticky_opts = Options(args=ARGUMENTS) +sticky_opts.AddOptions( + EnumOption('TARGET_ISA', 'Target ISA', 'alpha', env['ALL_ISA_LIST']), + BoolOption('FULL_SYSTEM', 'Full-system support', False), + # There's a bug in scons 0.96.1 that causes ListOptions with list + # values (more than one value) not to be able to be restored from + # a saved option file. If this causes trouble then upgrade to + # scons 0.96.90 or later. + ListOption('CPU_MODELS', 'CPU models', 'AtomicSimpleCPU,TimingSimpleCPU', + env['ALL_CPU_LIST']), + BoolOption('ALPHA_TLASER', + 'Model Alpha TurboLaser platform (vs. Tsunami)', False), + BoolOption('NO_FAST_ALLOC', 'Disable fast object allocator', False), + BoolOption('EFENCE', 'Link with Electric Fence malloc debugger', + False), + BoolOption('SS_COMPATIBLE_FP', + 'Make floating-point results compatible with SimpleScalar', + False), + BoolOption('USE_SSE2', + 'Compile for SSE2 (-msse2) to get IEEE FP on x86 hosts', + False), + BoolOption('STATS_BINNING', 'Bin statistics by CPU mode', have_mysql), + BoolOption('USE_MYSQL', 'Use MySQL for stats output', have_mysql), + BoolOption('USE_FENV', 'Use <fenv.h> IEEE mode control', have_fenv), + ('CC', 'C compiler', os.environ.get('CC', env['CC'])), + ('CXX', 'C++ compiler', os.environ.get('CXX', env['CXX'])), + BoolOption('BATCH', 'Use batch pool for build and tests', False), + ('BATCH_CMD', 'Batch pool submission command name', 'qdo') + ) + +# Non-sticky options only apply to the current build. +nonsticky_opts = Options(args=ARGUMENTS) +nonsticky_opts.AddOptions( + BoolOption('update_ref', 'Update test reference outputs', False) + ) + +# These options get exported to #defines in config/*.hh (see m5/SConscript). +env.ExportOptions = ['FULL_SYSTEM', 'ALPHA_TLASER', 'USE_FENV', \ + 'USE_MYSQL', 'NO_FAST_ALLOC', 'SS_COMPATIBLE_FP', \ + 'STATS_BINNING'] + +# Define a handy 'no-op' action +def no_action(target, source, env): + return 0 + +env.NoAction = Action(no_action, None) + +################################################### +# +# Define a SCons builder for configuration flag headers. +# +################################################### + +# This function generates a config header file that #defines the +# option symbol to the current option setting (0 or 1). The source +# operands are the name of the option and a Value node containing the +# value of the option. +def build_config_file(target, source, env): + (option, value) = [s.get_contents() for s in source] + f = file(str(target[0]), 'w') + print >> f, '#define', option, value + f.close() + return None + +# Generate the message to be printed when building the config file. +def build_config_file_string(target, source, env): + (option, value) = [s.get_contents() for s in source] + return "Defining %s as %s in %s." % (option, value, target[0]) + +# Combine the two functions into a scons Action object. +config_action = Action(build_config_file, build_config_file_string) + +# The emitter munges the source & target node lists to reflect what +# we're really doing. +def config_emitter(target, source, env): + # extract option name from Builder arg + option = str(target[0]) + # True target is config header file + target = os.path.join('config', option.lower() + '.hh') + # Force value to 0/1 even if it's a Python bool + val = int(eval(str(env[option]))) + # Sources are option name & value (packaged in SCons Value nodes) + return ([target], [Value(option), Value(val)]) + +config_builder = Builder(emitter = config_emitter, action = config_action) + +env.Append(BUILDERS = { 'ConfigFile' : config_builder }) + +# base help text +help_text = ''' +Usage: scons [scons options] [build options] [target(s)] + +''' + +# libelf build is shared across all configs in the build root. +env.SConscript('ext/libelf/SConscript', + build_dir = os.path.join(build_root, 'libelf'), + exports = 'env') + +################################################### +# +# Define build environments for selected configurations. +# +################################################### + +# rename base env +base_env = env + +for build_path in build_paths: + print "Building in", build_path + # build_dir is the tail component of build path, and is used to + # determine the build parameters (e.g., 'ALPHA_SE') + (build_root, build_dir) = os.path.split(build_path) + # Make a copy of the build-root environment to use for this config. + env = base_env.Copy() + + # Set env options according to the build directory config. + sticky_opts.files = [] + # Options for $BUILD_ROOT/$BUILD_DIR are stored in + # $BUILD_ROOT/options/$BUILD_DIR so you can nuke + # $BUILD_ROOT/$BUILD_DIR without losing your options settings. + current_opts_file = os.path.join(build_root, 'options', build_dir) + if os.path.isfile(current_opts_file): + sticky_opts.files.append(current_opts_file) + print "Using saved options file %s" % current_opts_file + else: + # Build dir-specific options file doesn't exist. + + # Make sure the directory is there so we can create it later + opt_dir = os.path.dirname(current_opts_file) + if not os.path.isdir(opt_dir): + os.mkdir(opt_dir) + + # Get default build options from source tree. Options are + # normally determined by name of $BUILD_DIR, but can be + # overriden by 'default=' arg on command line. + default_opts_file = os.path.join('build_opts', + ARGUMENTS.get('default', build_dir)) + if os.path.isfile(default_opts_file): + sticky_opts.files.append(default_opts_file) + print "Options file %s not found,\n using defaults in %s" \ + % (current_opts_file, default_opts_file) + else: + print "Error: cannot find options file %s or %s" \ + % (current_opts_file, default_opts_file) + Exit(1) + + # Apply current option settings to env + sticky_opts.Update(env) + nonsticky_opts.Update(env) + + help_text += "Sticky options for %s:\n" % build_dir \ + + sticky_opts.GenerateHelpText(env) \ + + "\nNon-sticky options for %s:\n" % build_dir \ + + nonsticky_opts.GenerateHelpText(env) + + # Process option settings. + + if not have_fenv and env['USE_FENV']: + print "Warning: <fenv.h> not available; " \ + "forcing USE_FENV to False in", build_dir + "." + env['USE_FENV'] = False + + if not env['USE_FENV']: + print "Warning: No IEEE FP rounding mode control in", build_dir + "." + print " FP results may deviate slightly from other platforms." + + if env['EFENCE']: + env.Append(LIBS=['efence']) + + if env['USE_MYSQL']: + if not have_mysql: + print "Warning: MySQL not available; " \ + "forcing USE_MYSQL to False in", build_dir + "." + env['USE_MYSQL'] = False + else: + print "Compiling in", build_dir, "with MySQL support." + env.ParseConfig(mysql_config_libs) + env.ParseConfig(mysql_config_include) + + # Save sticky option settings back to current options file + sticky_opts.Save(current_opts_file, env) + + # Do this after we save setting back, or else we'll tack on an + # extra 'qdo' every time we run scons. + if env['BATCH']: + env['CC'] = env['BATCH_CMD'] + ' ' + env['CC'] + env['CXX'] = env['BATCH_CMD'] + ' ' + env['CXX'] + + if env['USE_SSE2']: + env.Append(CCFLAGS='-msse2') + + # The m5/SConscript file sets up the build rules in 'env' according + # to the configured options. It returns a list of environments, + # one for each variant build (debug, opt, etc.) + envList = SConscript('src/SConscript', build_dir = build_path, + exports = 'env', duplicate = False) + + # Set up the regression tests for each build. +# for e in envList: +# SConscript('m5-test/SConscript', +# build_dir = os.path.join(build_dir, 'test', e.Label), +# exports = { 'env' : e }, duplicate = False) + +Help(help_text) + +################################################### +# +# Let SCons do its thing. At this point SCons will use the defined +# build environments to build the requested targets. +# +################################################### + diff --git a/arch/SConscript b/arch/SConscript deleted file mode 100644 index 92547c0ae..000000000 --- a/arch/SConscript +++ /dev/null @@ -1,146 +0,0 @@ -# -*- mode:python -*- - -# Copyright (c) 2006 The Regents of The University of Michigan -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer; -# redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution; -# neither the name of the copyright holders nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -import os.path - -# Import build environment variable from SConstruct. -Import('env') - -# Right now there are no source files immediately in this directory -sources = [] - -################################################################# -# -# ISA "switch header" generation. -# -# Auto-generate arch headers that include the right ISA-specific -# header based on the setting of THE_ISA preprocessor variable. -# -################################################################# - -# List of headers to generate -isa_switch_hdrs = Split(''' - isa_traits.hh - tlb.hh - process.hh - arguments.hh - stacktrace.hh - vtophys.hh - faults.hh - ''') - -# Generate the header. target[0] is the full path of the output -# header to generate. 'source' is a dummy variable, since we get the -# list of ISAs from env['ALL_ISA_LIST']. -def gen_switch_hdr(target, source, env): - fname = str(target[0]) - basename = os.path.basename(fname) - f = open(fname, 'w') - f.write('#include "arch/isa_specific.hh"\n') - cond = '#if' - for isa in env['ALL_ISA_LIST']: - f.write('%s THE_ISA == %s_ISA\n#include "arch/%s/%s"\n' - % (cond, isa.upper(), isa, basename)) - cond = '#elif' - f.write('#else\n#error "THE_ISA not set"\n#endif\n') - f.close() - return 0 - -# String to print when generating header -def gen_switch_hdr_string(target, source, env): - return "Generating ISA switch header " + str(target[0]) - -# Build SCons Action object. 'varlist' specifies env vars that this -# action depends on; when env['ALL_ISA_LIST'] changes these actions -# should get re-executed. -switch_hdr_action = Action(gen_switch_hdr, gen_switch_hdr_string, - varlist=['ALL_ISA_LIST']) - -# Instantiate actions for each header -for hdr in isa_switch_hdrs: - env.Command(hdr, [], switch_hdr_action) - -################################################################# -# -# Include architecture-specific files. -# -################################################################# - -# -# Build a SCons scanner for ISA files -# -import SCons.Scanner - -isa_scanner = SCons.Scanner.Classic("ISAScan", - [".isa", ".ISA"], - "SRCDIR", - r'^\s*##include\s+"([\w/.-]*)"') - -env.Append(SCANNERS = isa_scanner) - -# -# Now create a Builder object that uses isa_parser.py to generate C++ -# output from the ISA description (*.isa) files. -# - -# Convert to File node to fix path -isa_parser = File('isa_parser.py') -cpu_models_file = File('#m5/cpu/cpu_models.py') - -# This sucks in the defintions of the CpuModel objects. -execfile(cpu_models_file.srcnode().abspath) - -# Several files are generated from the ISA description. -# We always get the basic decoder and header file. -isa_desc_gen_files = Split('decoder.cc decoder.hh') -# We also get an execute file for each selected CPU model. -isa_desc_gen_files += [CpuModel.dict[cpu].filename - for cpu in env['CPU_MODELS']] - -# The emitter patches up the sources & targets to include the -# autogenerated files as targets and isa parser itself as a source. -def isa_desc_emitter(target, source, env): - return (isa_desc_gen_files, [isa_parser, cpu_models_file] + source) - -# Pieces are in place, so create the builder. -isa_desc_builder = Builder(action='python $SOURCES $TARGET.dir $CPU_MODELS', - emitter = isa_desc_emitter) - -env.Append(BUILDERS = { 'ISADesc' : isa_desc_builder }) - -# -# Now include other ISA-specific sources from the ISA subdirectories. -# - -isa = env['TARGET_ISA'] # someday this may be a list of ISAs - -# Let the target architecture define what additional sources it needs -sources += SConscript(os.path.join(isa, 'SConscript'), - exports = 'env', duplicate = False) - -Return('sources') diff --git a/arch/alpha/SConscript b/arch/alpha/SConscript deleted file mode 100644 index ed7fd3404..000000000 --- a/arch/alpha/SConscript +++ /dev/null @@ -1,91 +0,0 @@ -# -*- mode:python -*- - -# Copyright (c) 2004-2005 The Regents of The University of Michigan -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer; -# redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution; -# neither the name of the copyright holders nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -import os -import sys -from os.path import isdir - -# This file defines how to build a particular configuration of M5 -# based on variable settings in the 'env' build environment. - -# Import build environment variable from SConstruct. -Import('env') - -################################################### -# -# Define needed sources. -# -################################################### - -# Base sources used by all configurations. -base_sources = Split(''' - faults.cc - isa_traits.cc - ''') - -# Full-system sources -full_system_sources = Split(''' - tlb.cc - arguments.cc - ev5.cc - osfpal.cc - stacktrace.cc - vtophys.cc - system.cc - freebsd/system.cc - linux/system.cc - tru64/system.cc - ''') - - -# Syscall emulation (non-full-system) sources -syscall_emulation_sources = Split(''' - linux/process.cc - tru64/process.cc - process.cc - ''') - -# Set up complete list of sources based on configuration. -sources = base_sources - -if env['FULL_SYSTEM']: - sources += full_system_sources -else: - sources += syscall_emulation_sources - -# Convert file names to SCons File objects. This takes care of the -# path relative to the top of the directory tree. -sources = [File(s) for s in sources] - -# Add in files generated by the ISA description. -isa_desc_files = env.ISADesc('isa/main.isa') -# Only non-header files need to be compiled. -isa_desc_sources = [f for f in isa_desc_files if not f.path.endswith('.hh')] -sources += isa_desc_sources - -Return('sources') diff --git a/arch/alpha/arguments.cc b/arch/alpha/arguments.cc deleted file mode 100644 index 019390aeb..000000000 --- a/arch/alpha/arguments.cc +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "arch/alpha/arguments.hh" -#include "arch/alpha/vtophys.hh" -#include "cpu/exec_context.hh" -#include "mem/functional/physical.hh" - -using namespace AlphaISA; - -AlphaArguments::Data::~Data() -{ - while (!data.empty()) { - delete [] data.front(); - data.pop_front(); - } -} - -char * -AlphaArguments::Data::alloc(size_t size) -{ - char *buf = new char[size]; - data.push_back(buf); - return buf; -} - -uint64_t -AlphaArguments::getArg(bool fp) -{ - if (number < 6) { - if (fp) - return xc->readFloatRegInt(16 + number); - else - return xc->readIntReg(16 + number); - } else { - Addr sp = xc->readIntReg(30); - Addr paddr = vtophys(xc, sp + (number-6) * sizeof(uint64_t)); - return xc->getPhysMemPtr()->phys_read_qword(paddr); - } -} - diff --git a/arch/alpha/arguments.hh b/arch/alpha/arguments.hh deleted file mode 100644 index 75346bf58..000000000 --- a/arch/alpha/arguments.hh +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __ARGUMENTS_HH__ -#define __ARGUMENTS_HH__ - -#include <assert.h> - -#include "arch/alpha/vtophys.hh" -#include "base/refcnt.hh" -#include "sim/host.hh" - -class ExecContext; - -class AlphaArguments -{ - protected: - ExecContext *xc; - int number; - uint64_t getArg(bool fp = false); - - protected: - class Data : public RefCounted - { - public: - Data(){} - ~Data(); - - private: - std::list<char *> data; - - public: - char *alloc(size_t size); - }; - - RefCountingPtr<Data> data; - - public: - AlphaArguments(ExecContext *ctx, int n = 0) - : xc(ctx), number(n), data(NULL) - { assert(number >= 0); data = new Data;} - AlphaArguments(const AlphaArguments &args) - : xc(args.xc), number(args.number), data(args.data) {} - ~AlphaArguments() {} - - ExecContext *getExecContext() const { return xc; } - - const AlphaArguments &operator=(const AlphaArguments &args) { - xc = args.xc; - number = args.number; - data = args.data; - return *this; - } - - AlphaArguments &operator++() { - ++number; - assert(number >= 0); - return *this; - } - - AlphaArguments operator++(int) { - AlphaArguments args = *this; - ++number; - assert(number >= 0); - return args; - } - - AlphaArguments &operator--() { - --number; - assert(number >= 0); - return *this; - } - - AlphaArguments operator--(int) { - AlphaArguments args = *this; - --number; - assert(number >= 0); - return args; - } - - const AlphaArguments &operator+=(int index) { - number += index; - assert(number >= 0); - return *this; - } - - const AlphaArguments &operator-=(int index) { - number -= index; - assert(number >= 0); - return *this; - } - - AlphaArguments operator[](int index) { - return AlphaArguments(xc, index); - } - - template <class T> - operator T() { - assert(sizeof(T) <= sizeof(uint64_t)); - T data = static_cast<T>(getArg()); - return data; - } - - template <class T> - operator T *() { - T *buf = (T *)data->alloc(sizeof(T)); - CopyData(xc, buf, getArg(), sizeof(T)); - return buf; - } - - operator char *() { - char *buf = data->alloc(2048); - CopyString(xc, buf, getArg(), 2048); - return buf; - } -}; - -#endif // __ARGUMENTS_HH__ diff --git a/arch/alpha/ev5.cc b/arch/alpha/ev5.cc deleted file mode 100644 index f113a2767..000000000 --- a/arch/alpha/ev5.cc +++ /dev/null @@ -1,593 +0,0 @@ -/* - * Copyright (c) 2002-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "arch/alpha/tlb.hh" -#include "arch/alpha/isa_traits.hh" -#include "arch/alpha/osfpal.hh" -#include "base/kgdb.h" -#include "base/remote_gdb.hh" -#include "base/stats/events.hh" -#include "config/full_system.hh" -#include "cpu/base.hh" -#include "cpu/cpu_exec_context.hh" -#include "cpu/exec_context.hh" -#include "cpu/fast/cpu.hh" -#include "kern/kernel_stats.hh" -#include "sim/debug.hh" -#include "sim/sim_events.hh" - -#if FULL_SYSTEM - -using namespace EV5; - -//////////////////////////////////////////////////////////////////////// -// -// Machine dependent functions -// -void -AlphaISA::initCPU(ExecContext *xc, int cpuId) -{ - initIPRs(xc, cpuId); - - xc->setIntReg(16, cpuId); - xc->setIntReg(0, cpuId); - - xc->setPC(xc->readMiscReg(IPR_PAL_BASE) + (new ResetFault)->vect()); - xc->setNextPC(xc->readPC() + sizeof(MachInst)); -} - -//////////////////////////////////////////////////////////////////////// -// -// -// -void -AlphaISA::initIPRs(ExecContext *xc, int cpuId) -{ - for (int i = 0; i < NumInternalProcRegs; ++i) { - xc->setMiscReg(i, 0); - } - - xc->setMiscReg(IPR_PAL_BASE, PalBase); - xc->setMiscReg(IPR_MCSR, 0x6); - xc->setMiscReg(IPR_PALtemp16, cpuId); -} - - -template <class CPU> -void -AlphaISA::processInterrupts(CPU *cpu) -{ - //Check if there are any outstanding interrupts - //Handle the interrupts - int ipl = 0; - int summary = 0; - - cpu->checkInterrupts = false; - - if (cpu->readMiscReg(IPR_ASTRR)) - panic("asynchronous traps not implemented\n"); - - if (cpu->readMiscReg(IPR_SIRR)) { - for (int i = INTLEVEL_SOFTWARE_MIN; - i < INTLEVEL_SOFTWARE_MAX; i++) { - if (cpu->readMiscReg(IPR_SIRR) & (ULL(1) << i)) { - // See table 4-19 of the 21164 hardware reference - ipl = (i - INTLEVEL_SOFTWARE_MIN) + 1; - summary |= (ULL(1) << i); - } - } - } - - uint64_t interrupts = cpu->intr_status(); - - if (interrupts) { - for (int i = INTLEVEL_EXTERNAL_MIN; - i < INTLEVEL_EXTERNAL_MAX; i++) { - if (interrupts & (ULL(1) << i)) { - // See table 4-19 of the 21164 hardware reference - ipl = i; - summary |= (ULL(1) << i); - } - } - } - - if (ipl && ipl > cpu->readMiscReg(IPR_IPLR)) { - cpu->setMiscReg(IPR_ISR, summary); - cpu->setMiscReg(IPR_INTID, ipl); - cpu->trap(new InterruptFault); - DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n", - cpu->readMiscReg(IPR_IPLR), ipl, summary); - } - -} - -template <class CPU> -void -AlphaISA::zeroRegisters(CPU *cpu) -{ - // Insure ISA semantics - // (no longer very clean due to the change in setIntReg() in the - // cpu model. Consider changing later.) - cpu->cpuXC->setIntReg(ZeroReg, 0); - cpu->cpuXC->setFloatRegDouble(ZeroReg, 0.0); -} - -Fault -CPUExecContext::hwrei() -{ - if (!inPalMode()) - return new UnimplementedOpcodeFault; - - setNextPC(readMiscReg(AlphaISA::IPR_EXC_ADDR)); - - if (!misspeculating()) { - if (kernelStats) - kernelStats->hwrei(); - - cpu->checkInterrupts = true; - } - - // FIXME: XXX check for interrupts? XXX - return NoFault; -} - -int -AlphaISA::MiscRegFile::getInstAsid() -{ - return EV5::ITB_ASN_ASN(ipr[IPR_ITB_ASN]); -} - -int -AlphaISA::MiscRegFile::getDataAsid() -{ - return EV5::DTB_ASN_ASN(ipr[IPR_DTB_ASN]); -} - -AlphaISA::MiscReg -AlphaISA::MiscRegFile::readIpr(int idx, Fault &fault, ExecContext *xc) -{ - uint64_t retval = 0; // return value, default 0 - - switch (idx) { - case AlphaISA::IPR_PALtemp0: - case AlphaISA::IPR_PALtemp1: - case AlphaISA::IPR_PALtemp2: - case AlphaISA::IPR_PALtemp3: - case AlphaISA::IPR_PALtemp4: - case AlphaISA::IPR_PALtemp5: - case AlphaISA::IPR_PALtemp6: - case AlphaISA::IPR_PALtemp7: - case AlphaISA::IPR_PALtemp8: - case AlphaISA::IPR_PALtemp9: - case AlphaISA::IPR_PALtemp10: - case AlphaISA::IPR_PALtemp11: - case AlphaISA::IPR_PALtemp12: - case AlphaISA::IPR_PALtemp13: - case AlphaISA::IPR_PALtemp14: - case AlphaISA::IPR_PALtemp15: - case AlphaISA::IPR_PALtemp16: - case AlphaISA::IPR_PALtemp17: - case AlphaISA::IPR_PALtemp18: - case AlphaISA::IPR_PALtemp19: - case AlphaISA::IPR_PALtemp20: - case AlphaISA::IPR_PALtemp21: - case AlphaISA::IPR_PALtemp22: - case AlphaISA::IPR_PALtemp23: - case AlphaISA::IPR_PAL_BASE: - - case AlphaISA::IPR_IVPTBR: - case AlphaISA::IPR_DC_MODE: - case AlphaISA::IPR_MAF_MODE: - case AlphaISA::IPR_ISR: - case AlphaISA::IPR_EXC_ADDR: - case AlphaISA::IPR_IC_PERR_STAT: - case AlphaISA::IPR_DC_PERR_STAT: - case AlphaISA::IPR_MCSR: - case AlphaISA::IPR_ASTRR: - case AlphaISA::IPR_ASTER: - case AlphaISA::IPR_SIRR: - case AlphaISA::IPR_ICSR: - case AlphaISA::IPR_ICM: - case AlphaISA::IPR_DTB_CM: - case AlphaISA::IPR_IPLR: - case AlphaISA::IPR_INTID: - case AlphaISA::IPR_PMCTR: - // no side-effect - retval = ipr[idx]; - break; - - case AlphaISA::IPR_CC: - retval |= ipr[idx] & ULL(0xffffffff00000000); - retval |= xc->getCpuPtr()->curCycle() & ULL(0x00000000ffffffff); - break; - - case AlphaISA::IPR_VA: - retval = ipr[idx]; - break; - - case AlphaISA::IPR_VA_FORM: - case AlphaISA::IPR_MM_STAT: - case AlphaISA::IPR_IFAULT_VA_FORM: - case AlphaISA::IPR_EXC_MASK: - case AlphaISA::IPR_EXC_SUM: - retval = ipr[idx]; - break; - - case AlphaISA::IPR_DTB_PTE: - { - AlphaISA::PTE &pte = xc->getDTBPtr()->index(!xc->misspeculating()); - - retval |= ((u_int64_t)pte.ppn & ULL(0x7ffffff)) << 32; - retval |= ((u_int64_t)pte.xre & ULL(0xf)) << 8; - retval |= ((u_int64_t)pte.xwe & ULL(0xf)) << 12; - retval |= ((u_int64_t)pte.fonr & ULL(0x1)) << 1; - retval |= ((u_int64_t)pte.fonw & ULL(0x1))<< 2; - retval |= ((u_int64_t)pte.asma & ULL(0x1)) << 4; - retval |= ((u_int64_t)pte.asn & ULL(0x7f)) << 57; - } - break; - - // write only registers - case AlphaISA::IPR_HWINT_CLR: - case AlphaISA::IPR_SL_XMIT: - case AlphaISA::IPR_DC_FLUSH: - case AlphaISA::IPR_IC_FLUSH: - case AlphaISA::IPR_ALT_MODE: - case AlphaISA::IPR_DTB_IA: - case AlphaISA::IPR_DTB_IAP: - case AlphaISA::IPR_ITB_IA: - case AlphaISA::IPR_ITB_IAP: - fault = new UnimplementedOpcodeFault; - break; - - default: - // invalid IPR - fault = new UnimplementedOpcodeFault; - break; - } - - return retval; -} - -#ifdef DEBUG -// Cause the simulator to break when changing to the following IPL -int break_ipl = -1; -#endif - -Fault -AlphaISA::MiscRegFile::setIpr(int idx, uint64_t val, ExecContext *xc) -{ - uint64_t old; - - if (xc->misspeculating()) - return NoFault; - - switch (idx) { - case AlphaISA::IPR_PALtemp0: - case AlphaISA::IPR_PALtemp1: - case AlphaISA::IPR_PALtemp2: - case AlphaISA::IPR_PALtemp3: - case AlphaISA::IPR_PALtemp4: - case AlphaISA::IPR_PALtemp5: - case AlphaISA::IPR_PALtemp6: - case AlphaISA::IPR_PALtemp7: - case AlphaISA::IPR_PALtemp8: - case AlphaISA::IPR_PALtemp9: - case AlphaISA::IPR_PALtemp10: - case AlphaISA::IPR_PALtemp11: - case AlphaISA::IPR_PALtemp12: - case AlphaISA::IPR_PALtemp13: - case AlphaISA::IPR_PALtemp14: - case AlphaISA::IPR_PALtemp15: - case AlphaISA::IPR_PALtemp16: - case AlphaISA::IPR_PALtemp17: - case AlphaISA::IPR_PALtemp18: - case AlphaISA::IPR_PALtemp19: - case AlphaISA::IPR_PALtemp20: - case AlphaISA::IPR_PALtemp21: - case AlphaISA::IPR_PALtemp22: - case AlphaISA::IPR_PAL_BASE: - case AlphaISA::IPR_IC_PERR_STAT: - case AlphaISA::IPR_DC_PERR_STAT: - case AlphaISA::IPR_PMCTR: - // write entire quad w/ no side-effect - ipr[idx] = val; - break; - - case AlphaISA::IPR_CC_CTL: - // This IPR resets the cycle counter. We assume this only - // happens once... let's verify that. - assert(ipr[idx] == 0); - ipr[idx] = 1; - break; - - case AlphaISA::IPR_CC: - // This IPR only writes the upper 64 bits. It's ok to write - // all 64 here since we mask out the lower 32 in rpcc (see - // isa_desc). - ipr[idx] = val; - break; - - case AlphaISA::IPR_PALtemp23: - // write entire quad w/ no side-effect - old = ipr[idx]; - ipr[idx] = val; - if (xc->getKernelStats()) - xc->getKernelStats()->context(old, val, xc); - break; - - case AlphaISA::IPR_DTB_PTE: - // write entire quad w/ no side-effect, tag is forthcoming - ipr[idx] = val; - break; - - case AlphaISA::IPR_EXC_ADDR: - // second least significant bit in PC is always zero - ipr[idx] = val & ~2; - break; - - case AlphaISA::IPR_ASTRR: - case AlphaISA::IPR_ASTER: - // only write least significant four bits - privilege mask - ipr[idx] = val & 0xf; - break; - - case AlphaISA::IPR_IPLR: -#ifdef DEBUG - if (break_ipl != -1 && break_ipl == (val & 0x1f)) - debug_break(); -#endif - - // only write least significant five bits - interrupt level - ipr[idx] = val & 0x1f; - if (xc->getKernelStats()) - xc->getKernelStats()->swpipl(ipr[idx]); - break; - - case AlphaISA::IPR_DTB_CM: - if (val & 0x18) { - if (xc->getKernelStats()) - xc->getKernelStats()->mode(Kernel::user, xc); - } else { - if (xc->getKernelStats()) - xc->getKernelStats()->mode(Kernel::kernel, xc); - } - - case AlphaISA::IPR_ICM: - // only write two mode bits - processor mode - ipr[idx] = val & 0x18; - break; - - case AlphaISA::IPR_ALT_MODE: - // only write two mode bits - processor mode - ipr[idx] = val & 0x18; - break; - - case AlphaISA::IPR_MCSR: - // more here after optimization... - ipr[idx] = val; - break; - - case AlphaISA::IPR_SIRR: - // only write software interrupt mask - ipr[idx] = val & 0x7fff0; - break; - - case AlphaISA::IPR_ICSR: - ipr[idx] = val & ULL(0xffffff0300); - break; - - case AlphaISA::IPR_IVPTBR: - case AlphaISA::IPR_MVPTBR: - ipr[idx] = val & ULL(0xffffffffc0000000); - break; - - case AlphaISA::IPR_DC_TEST_CTL: - ipr[idx] = val & 0x1ffb; - break; - - case AlphaISA::IPR_DC_MODE: - case AlphaISA::IPR_MAF_MODE: - ipr[idx] = val & 0x3f; - break; - - case AlphaISA::IPR_ITB_ASN: - ipr[idx] = val & 0x7f0; - break; - - case AlphaISA::IPR_DTB_ASN: - ipr[idx] = val & ULL(0xfe00000000000000); - break; - - case AlphaISA::IPR_EXC_SUM: - case AlphaISA::IPR_EXC_MASK: - // any write to this register clears it - ipr[idx] = 0; - break; - - case AlphaISA::IPR_INTID: - case AlphaISA::IPR_SL_RCV: - case AlphaISA::IPR_MM_STAT: - case AlphaISA::IPR_ITB_PTE_TEMP: - case AlphaISA::IPR_DTB_PTE_TEMP: - // read-only registers - return new UnimplementedOpcodeFault; - - case AlphaISA::IPR_HWINT_CLR: - case AlphaISA::IPR_SL_XMIT: - case AlphaISA::IPR_DC_FLUSH: - case AlphaISA::IPR_IC_FLUSH: - // the following are write only - ipr[idx] = val; - break; - - case AlphaISA::IPR_DTB_IA: - // really a control write - ipr[idx] = 0; - - xc->getDTBPtr()->flushAll(); - break; - - case AlphaISA::IPR_DTB_IAP: - // really a control write - ipr[idx] = 0; - - xc->getDTBPtr()->flushProcesses(); - break; - - case AlphaISA::IPR_DTB_IS: - // really a control write - ipr[idx] = val; - - xc->getDTBPtr()->flushAddr(val, - DTB_ASN_ASN(ipr[AlphaISA::IPR_DTB_ASN])); - break; - - case AlphaISA::IPR_DTB_TAG: { - struct AlphaISA::PTE pte; - - // FIXME: granularity hints NYI... - if (DTB_PTE_GH(ipr[AlphaISA::IPR_DTB_PTE]) != 0) - panic("PTE GH field != 0"); - - // write entire quad - ipr[idx] = val; - - // construct PTE for new entry - pte.ppn = DTB_PTE_PPN(ipr[AlphaISA::IPR_DTB_PTE]); - pte.xre = DTB_PTE_XRE(ipr[AlphaISA::IPR_DTB_PTE]); - pte.xwe = DTB_PTE_XWE(ipr[AlphaISA::IPR_DTB_PTE]); - pte.fonr = DTB_PTE_FONR(ipr[AlphaISA::IPR_DTB_PTE]); - pte.fonw = DTB_PTE_FONW(ipr[AlphaISA::IPR_DTB_PTE]); - pte.asma = DTB_PTE_ASMA(ipr[AlphaISA::IPR_DTB_PTE]); - pte.asn = DTB_ASN_ASN(ipr[AlphaISA::IPR_DTB_ASN]); - - // insert new TAG/PTE value into data TLB - xc->getDTBPtr()->insert(val, pte); - } - break; - - case AlphaISA::IPR_ITB_PTE: { - struct AlphaISA::PTE pte; - - // FIXME: granularity hints NYI... - if (ITB_PTE_GH(val) != 0) - panic("PTE GH field != 0"); - - // write entire quad - ipr[idx] = val; - - // construct PTE for new entry - pte.ppn = ITB_PTE_PPN(val); - pte.xre = ITB_PTE_XRE(val); - pte.xwe = 0; - pte.fonr = ITB_PTE_FONR(val); - pte.fonw = ITB_PTE_FONW(val); - pte.asma = ITB_PTE_ASMA(val); - pte.asn = ITB_ASN_ASN(ipr[AlphaISA::IPR_ITB_ASN]); - - // insert new TAG/PTE value into data TLB - xc->getITBPtr()->insert(ipr[AlphaISA::IPR_ITB_TAG], pte); - } - break; - - case AlphaISA::IPR_ITB_IA: - // really a control write - ipr[idx] = 0; - - xc->getITBPtr()->flushAll(); - break; - - case AlphaISA::IPR_ITB_IAP: - // really a control write - ipr[idx] = 0; - - xc->getITBPtr()->flushProcesses(); - break; - - case AlphaISA::IPR_ITB_IS: - // really a control write - ipr[idx] = val; - - xc->getITBPtr()->flushAddr(val, - ITB_ASN_ASN(ipr[AlphaISA::IPR_ITB_ASN])); - break; - - default: - // invalid IPR - return new UnimplementedOpcodeFault; - } - - // no error... - return NoFault; -} - -void -AlphaISA::MiscRegFile::copyIprs(ExecContext *xc) -{ - for (int i = IPR_Base_DepTag; i < NumInternalProcRegs; ++i) { - ipr[i] = xc->readMiscReg(i); - } -} - -/** - * Check for special simulator handling of specific PAL calls. - * If return value is false, actual PAL call will be suppressed. - */ -bool -CPUExecContext::simPalCheck(int palFunc) -{ - if (kernelStats) - kernelStats->callpal(palFunc, proxy); - - switch (palFunc) { - case PAL::halt: - halt(); - if (--System::numSystemsRunning == 0) - new SimExitEvent("all cpus halted"); - break; - - case PAL::bpt: - case PAL::bugchk: - if (system->breakpoint()) - return false; - break; - } - - return true; -} - -//Forward instantiation for FastCPU object -template -void AlphaISA::processInterrupts(FastCPU *xc); - -//Forward instantiation for FastCPU object -template -void AlphaISA::zeroRegisters(FastCPU *xc); - -#endif // FULL_SYSTEM diff --git a/arch/alpha/freebsd/system.cc b/arch/alpha/freebsd/system.cc deleted file mode 100644 index e32053afd..000000000 --- a/arch/alpha/freebsd/system.cc +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * Modifications for the FreeBSD kernel. - * Based on kern/linux/linux_system.cc. - * - */ - -#include "arch/alpha/system.hh" -#include "arch/alpha/freebsd/system.hh" -#include "base/loader/symtab.hh" -#include "cpu/exec_context.hh" -#include "mem/functional/memory_control.hh" -#include "mem/functional/physical.hh" -#include "arch/isa_traits.hh" -#include "sim/builder.hh" -#include "sim/byteswap.hh" -#include "arch/vtophys.hh" - -#define TIMER_FREQUENCY 1193180 - -using namespace std; -using namespace AlphaISA; - -FreebsdAlphaSystem::FreebsdAlphaSystem(Params *p) - : AlphaSystem(p) -{ - /** - * Any time DELAY is called just skip the function. - * Shouldn't we actually emulate the delay? - */ - skipDelayEvent = addKernelFuncEvent<SkipFuncEvent>("DELAY"); - skipCalibrateClocks = - addKernelFuncEvent<SkipCalibrateClocksEvent>("calibrate_clocks"); -} - - -FreebsdAlphaSystem::~FreebsdAlphaSystem() -{ - delete skipDelayEvent; - delete skipCalibrateClocks; -} - - -void -FreebsdAlphaSystem::doCalibrateClocks(ExecContext *xc) -{ - Addr ppc_vaddr = 0; - Addr timer_vaddr = 0; - Addr ppc_paddr = 0; - Addr timer_paddr = 0; - - ppc_vaddr = (Addr)xc->readIntReg(ArgumentReg1); - timer_vaddr = (Addr)xc->readIntReg(ArgumentReg2); - - ppc_paddr = vtophys(physmem, ppc_vaddr); - timer_paddr = vtophys(physmem, timer_vaddr); - - uint8_t *ppc = physmem->dma_addr(ppc_paddr, sizeof(uint32_t)); - uint8_t *timer = physmem->dma_addr(timer_paddr, sizeof(uint32_t)); - - *(uint32_t *)ppc = htog((uint32_t)Clock::Frequency); - *(uint32_t *)timer = htog((uint32_t)TIMER_FREQUENCY); -} - - -void -FreebsdAlphaSystem::SkipCalibrateClocksEvent::process(ExecContext *xc) -{ - SkipFuncEvent::process(xc); - ((FreebsdAlphaSystem *)xc->getSystemPtr())->doCalibrateClocks(xc); -} - - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(FreebsdAlphaSystem) - - Param<Tick> boot_cpu_frequency; - SimObjectParam<MemoryController *> memctrl; - SimObjectParam<PhysicalMemory *> physmem; - - Param<string> kernel; - Param<string> console; - Param<string> pal; - - Param<string> boot_osflags; - Param<string> readfile; - Param<unsigned int> init_param; - - Param<uint64_t> system_type; - Param<uint64_t> system_rev; - - Param<bool> bin; - VectorParam<string> binned_fns; - Param<bool> bin_int; - -END_DECLARE_SIM_OBJECT_PARAMS(FreebsdAlphaSystem) - -BEGIN_INIT_SIM_OBJECT_PARAMS(FreebsdAlphaSystem) - - INIT_PARAM(boot_cpu_frequency, "Frequency of the boot CPU"), - INIT_PARAM(memctrl, "memory controller"), - INIT_PARAM(physmem, "phsyical memory"), - INIT_PARAM(kernel, "file that contains the kernel code"), - INIT_PARAM(console, "file that contains the console code"), - INIT_PARAM(pal, "file that contains palcode"), - INIT_PARAM_DFLT(boot_osflags, "flags to pass to the kernel during boot", - "a"), - INIT_PARAM_DFLT(readfile, "file to read startup script from", ""), - INIT_PARAM_DFLT(init_param, "numerical value to pass into simulator", 0), - INIT_PARAM_DFLT(system_type, "Type of system we are emulating", 34), - INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 1<<10), - INIT_PARAM_DFLT(bin, "is this system to be binned", false), - INIT_PARAM(binned_fns, "functions to be broken down and binned"), - INIT_PARAM_DFLT(bin_int, "is interrupt code binned seperately?", true) - -END_INIT_SIM_OBJECT_PARAMS(FreebsdAlphaSystem) - -CREATE_SIM_OBJECT(FreebsdAlphaSystem) -{ - AlphaSystem::Params *p = new AlphaSystem::Params; - p->name = getInstanceName(); - p->boot_cpu_frequency = boot_cpu_frequency; - p->memctrl = memctrl; - p->physmem = physmem; - p->kernel_path = kernel; - p->console_path = console; - p->palcode = pal; - p->boot_osflags = boot_osflags; - p->init_param = init_param; - p->readfile = readfile; - p->system_type = system_type; - p->system_rev = system_rev; - p->bin = bin; - p->binned_fns = binned_fns; - p->bin_int = bin_int; - return new FreebsdAlphaSystem(p); -} - -REGISTER_SIM_OBJECT("FreebsdAlphaSystem", FreebsdAlphaSystem) - diff --git a/arch/alpha/isa/branch.isa b/arch/alpha/isa/branch.isa deleted file mode 100644 index b528df938..000000000 --- a/arch/alpha/isa/branch.isa +++ /dev/null @@ -1,259 +0,0 @@ -// -*- mode:c++ -*- - -// Copyright (c) 2003-2005 The Regents of The University of Michigan -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer; -// redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution; -// neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -output header {{ - - /** - * Base class for instructions whose disassembly is not purely a - * function of the machine instruction (i.e., it depends on the - * PC). This class overrides the disassemble() method to check - * the PC and symbol table values before re-using a cached - * disassembly string. This is necessary for branches and jumps, - * where the disassembly string includes the target address (which - * may depend on the PC and/or symbol table). - */ - class PCDependentDisassembly : public AlphaStaticInst - { - protected: - /// Cached program counter from last disassembly - mutable Addr cachedPC; - /// Cached symbol table pointer from last disassembly - mutable const SymbolTable *cachedSymtab; - - /// Constructor - PCDependentDisassembly(const char *mnem, ExtMachInst _machInst, - OpClass __opClass) - : AlphaStaticInst(mnem, _machInst, __opClass), - cachedPC(0), cachedSymtab(0) - { - } - - const std::string & - disassemble(Addr pc, const SymbolTable *symtab) const; - }; - - /** - * Base class for branches (PC-relative control transfers), - * conditional or unconditional. - */ - class Branch : public PCDependentDisassembly - { - protected: - /// Displacement to target address (signed). - int32_t disp; - - /// Constructor. - Branch(const char *mnem, ExtMachInst _machInst, OpClass __opClass) - : PCDependentDisassembly(mnem, _machInst, __opClass), - disp(BRDISP << 2) - { - } - - Addr branchTarget(Addr branchPC) const; - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; - - /** - * Base class for jumps (register-indirect control transfers). In - * the Alpha ISA, these are always unconditional. - */ - class Jump : public PCDependentDisassembly - { - protected: - - /// Displacement to target address (signed). - int32_t disp; - - public: - /// Constructor - Jump(const char *mnem, ExtMachInst _machInst, OpClass __opClass) - : PCDependentDisassembly(mnem, _machInst, __opClass), - disp(BRDISP) - { - } - - Addr branchTarget(ExecContext *xc) const; - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; -}}; - -output decoder {{ - Addr - Branch::branchTarget(Addr branchPC) const - { - return branchPC + 4 + disp; - } - - Addr - Jump::branchTarget(ExecContext *xc) const - { - Addr NPC = xc->readPC() + 4; - uint64_t Rb = xc->readIntReg(_srcRegIdx[0]); - return (Rb & ~3) | (NPC & 1); - } - - const std::string & - PCDependentDisassembly::disassemble(Addr pc, - const SymbolTable *symtab) const - { - if (!cachedDisassembly || - pc != cachedPC || symtab != cachedSymtab) - { - if (cachedDisassembly) - delete cachedDisassembly; - - cachedDisassembly = - new std::string(generateDisassembly(pc, symtab)); - cachedPC = pc; - cachedSymtab = symtab; - } - - return *cachedDisassembly; - } - - std::string - Branch::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { - std::stringstream ss; - - ccprintf(ss, "%-10s ", mnemonic); - - // There's only one register arg (RA), but it could be - // either a source (the condition for conditional - // branches) or a destination (the link reg for - // unconditional branches) - if (_numSrcRegs > 0) { - printReg(ss, _srcRegIdx[0]); - ss << ","; - } - else if (_numDestRegs > 0) { - printReg(ss, _destRegIdx[0]); - ss << ","; - } - -#ifdef SS_COMPATIBLE_DISASSEMBLY - if (_numSrcRegs == 0 && _numDestRegs == 0) { - printReg(ss, 31); - ss << ","; - } -#endif - - Addr target = pc + 4 + disp; - - std::string str; - if (symtab && symtab->findSymbol(target, str)) - ss << str; - else - ccprintf(ss, "0x%x", target); - - return ss.str(); - } - - std::string - Jump::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { - std::stringstream ss; - - ccprintf(ss, "%-10s ", mnemonic); - -#ifdef SS_COMPATIBLE_DISASSEMBLY - if (_numDestRegs == 0) { - printReg(ss, 31); - ss << ","; - } -#endif - - if (_numDestRegs > 0) { - printReg(ss, _destRegIdx[0]); - ss << ","; - } - - ccprintf(ss, "(r%d)", RB); - - return ss.str(); - } -}}; - -def template JumpOrBranchDecode {{ - return (RA == 31) - ? (StaticInst *)new %(class_name)s(machInst) - : (StaticInst *)new %(class_name)sAndLink(machInst); -}}; - -def format CondBranch(code) {{ - code = 'bool cond;\n' + code + '\nif (cond) NPC = NPC + disp;\n'; - iop = InstObjParams(name, Name, 'Branch', CodeBlock(code), - ('IsDirectControl', 'IsCondControl')) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = BasicDecode.subst(iop) - exec_output = BasicExecute.subst(iop) -}}; - -let {{ -def UncondCtrlBase(name, Name, base_class, npc_expr, flags): - # Declare basic control transfer w/o link (i.e. link reg is R31) - nolink_code = 'NPC = %s;\n' % npc_expr - nolink_iop = InstObjParams(name, Name, base_class, - CodeBlock(nolink_code), flags) - header_output = BasicDeclare.subst(nolink_iop) - decoder_output = BasicConstructor.subst(nolink_iop) - exec_output = BasicExecute.subst(nolink_iop) - - # Generate declaration of '*AndLink' version, append to decls - link_code = 'Ra = NPC & ~3;\n' + nolink_code - link_iop = InstObjParams(name, Name + 'AndLink', base_class, - CodeBlock(link_code), flags) - header_output += BasicDeclare.subst(link_iop) - decoder_output += BasicConstructor.subst(link_iop) - exec_output += BasicExecute.subst(link_iop) - - # need to use link_iop for the decode template since it is expecting - # the shorter version of class_name (w/o "AndLink") - - return (header_output, decoder_output, - JumpOrBranchDecode.subst(nolink_iop), exec_output) -}}; - -def format UncondBranch(*flags) {{ - flags += ('IsUncondControl', 'IsDirectControl') - (header_output, decoder_output, decode_block, exec_output) = \ - UncondCtrlBase(name, Name, 'Branch', 'NPC + disp', flags) -}}; - -def format Jump(*flags) {{ - flags += ('IsUncondControl', 'IsIndirectControl') - (header_output, decoder_output, decode_block, exec_output) = \ - UncondCtrlBase(name, Name, 'Jump', '(Rb & ~3) | (NPC & 1)', flags) -}}; - - diff --git a/arch/alpha/isa/decoder.isa b/arch/alpha/isa/decoder.isa deleted file mode 100644 index b3744a43d..000000000 --- a/arch/alpha/isa/decoder.isa +++ /dev/null @@ -1,819 +0,0 @@ -// -*- mode:c++ -*- - -// Copyright (c) 2003-2006 The Regents of The University of Michigan -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer; -// redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution; -// neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -decode OPCODE default Unknown::unknown() { - - format LoadAddress { - 0x08: lda({{ Ra = Rb + disp; }}); - 0x09: ldah({{ Ra = Rb + (disp << 16); }}); - } - - format LoadOrNop { - 0x0a: ldbu({{ Ra.uq = Mem.ub; }}); - 0x0c: ldwu({{ Ra.uq = Mem.uw; }}); - 0x0b: ldq_u({{ Ra = Mem.uq; }}, ea_code = {{ EA = (Rb + disp) & ~7; }}); - 0x23: ldt({{ Fa = Mem.df; }}); - 0x2a: ldl_l({{ Ra.sl = Mem.sl; }}, mem_flags = LOCKED); - 0x2b: ldq_l({{ Ra.uq = Mem.uq; }}, mem_flags = LOCKED); - 0x20: MiscPrefetch::copy_load({{ EA = Ra; }}, - {{ fault = xc->copySrcTranslate(EA); }}, - inst_flags = [IsMemRef, IsLoad, IsCopy]); - } - - format LoadOrPrefetch { - 0x28: ldl({{ Ra.sl = Mem.sl; }}); - 0x29: ldq({{ Ra.uq = Mem.uq; }}, pf_flags = EVICT_NEXT); - // IsFloating flag on lds gets the prefetch to disassemble - // using f31 instead of r31... funcitonally it's unnecessary - 0x22: lds({{ Fa.uq = s_to_t(Mem.ul); }}, - pf_flags = PF_EXCLUSIVE, inst_flags = IsFloating); - } - - format Store { - 0x0e: stb({{ Mem.ub = Ra<7:0>; }}); - 0x0d: stw({{ Mem.uw = Ra<15:0>; }}); - 0x2c: stl({{ Mem.ul = Ra<31:0>; }}); - 0x2d: stq({{ Mem.uq = Ra.uq; }}); - 0x0f: stq_u({{ Mem.uq = Ra.uq; }}, {{ EA = (Rb + disp) & ~7; }}); - 0x26: sts({{ Mem.ul = t_to_s(Fa.uq); }}); - 0x27: stt({{ Mem.df = Fa; }}); - 0x24: MiscPrefetch::copy_store({{ EA = Rb; }}, - {{ fault = xc->copy(EA); }}, - inst_flags = [IsMemRef, IsStore, IsCopy]); - } - - format StoreCond { - 0x2e: stl_c({{ Mem.ul = Ra<31:0>; }}, - {{ - uint64_t tmp = write_result; - // see stq_c - Ra = (tmp == 0 || tmp == 1) ? tmp : Ra; - }}, mem_flags = LOCKED, inst_flags = IsStoreConditional); - 0x2f: stq_c({{ Mem.uq = Ra; }}, - {{ - uint64_t tmp = write_result; - // If the write operation returns 0 or 1, then - // this was a conventional store conditional, - // and the value indicates the success/failure - // of the operation. If another value is - // returned, then this was a Turbolaser - // mailbox access, and we don't update the - // result register at all. - Ra = (tmp == 0 || tmp == 1) ? tmp : Ra; - }}, mem_flags = LOCKED, inst_flags = IsStoreConditional); - } - - format IntegerOperate { - - 0x10: decode INTFUNC { // integer arithmetic operations - - 0x00: addl({{ Rc.sl = Ra.sl + Rb_or_imm.sl; }}); - 0x40: addlv({{ - uint32_t tmp = Ra.sl + Rb_or_imm.sl; - // signed overflow occurs when operands have same sign - // and sign of result does not match. - if (Ra.sl<31:> == Rb_or_imm.sl<31:> && tmp<31:> != Ra.sl<31:>) - fault = new IntegerOverflowFault; - Rc.sl = tmp; - }}); - 0x02: s4addl({{ Rc.sl = (Ra.sl << 2) + Rb_or_imm.sl; }}); - 0x12: s8addl({{ Rc.sl = (Ra.sl << 3) + Rb_or_imm.sl; }}); - - 0x20: addq({{ Rc = Ra + Rb_or_imm; }}); - 0x60: addqv({{ - uint64_t tmp = Ra + Rb_or_imm; - // signed overflow occurs when operands have same sign - // and sign of result does not match. - if (Ra<63:> == Rb_or_imm<63:> && tmp<63:> != Ra<63:>) - fault = new IntegerOverflowFault; - Rc = tmp; - }}); - 0x22: s4addq({{ Rc = (Ra << 2) + Rb_or_imm; }}); - 0x32: s8addq({{ Rc = (Ra << 3) + Rb_or_imm; }}); - - 0x09: subl({{ Rc.sl = Ra.sl - Rb_or_imm.sl; }}); - 0x49: sublv({{ - uint32_t tmp = Ra.sl - Rb_or_imm.sl; - // signed overflow detection is same as for add, - // except we need to look at the *complemented* - // sign bit of the subtrahend (Rb), i.e., if the initial - // signs are the *same* then no overflow can occur - if (Ra.sl<31:> != Rb_or_imm.sl<31:> && tmp<31:> != Ra.sl<31:>) - fault = new IntegerOverflowFault; - Rc.sl = tmp; - }}); - 0x0b: s4subl({{ Rc.sl = (Ra.sl << 2) - Rb_or_imm.sl; }}); - 0x1b: s8subl({{ Rc.sl = (Ra.sl << 3) - Rb_or_imm.sl; }}); - - 0x29: subq({{ Rc = Ra - Rb_or_imm; }}); - 0x69: subqv({{ - uint64_t tmp = Ra - Rb_or_imm; - // signed overflow detection is same as for add, - // except we need to look at the *complemented* - // sign bit of the subtrahend (Rb), i.e., if the initial - // signs are the *same* then no overflow can occur - if (Ra<63:> != Rb_or_imm<63:> && tmp<63:> != Ra<63:>) - fault = new IntegerOverflowFault; - Rc = tmp; - }}); - 0x2b: s4subq({{ Rc = (Ra << 2) - Rb_or_imm; }}); - 0x3b: s8subq({{ Rc = (Ra << 3) - Rb_or_imm; }}); - - 0x2d: cmpeq({{ Rc = (Ra == Rb_or_imm); }}); - 0x6d: cmple({{ Rc = (Ra.sq <= Rb_or_imm.sq); }}); - 0x4d: cmplt({{ Rc = (Ra.sq < Rb_or_imm.sq); }}); - 0x3d: cmpule({{ Rc = (Ra.uq <= Rb_or_imm.uq); }}); - 0x1d: cmpult({{ Rc = (Ra.uq < Rb_or_imm.uq); }}); - - 0x0f: cmpbge({{ - int hi = 7; - int lo = 0; - uint64_t tmp = 0; - for (int i = 0; i < 8; ++i) { - tmp |= (Ra.uq<hi:lo> >= Rb_or_imm.uq<hi:lo>) << i; - hi += 8; - lo += 8; - } - Rc = tmp; - }}); - } - - 0x11: decode INTFUNC { // integer logical operations - - 0x00: and({{ Rc = Ra & Rb_or_imm; }}); - 0x08: bic({{ Rc = Ra & ~Rb_or_imm; }}); - 0x20: bis({{ Rc = Ra | Rb_or_imm; }}); - 0x28: ornot({{ Rc = Ra | ~Rb_or_imm; }}); - 0x40: xor({{ Rc = Ra ^ Rb_or_imm; }}); - 0x48: eqv({{ Rc = Ra ^ ~Rb_or_imm; }}); - - // conditional moves - 0x14: cmovlbs({{ Rc = ((Ra & 1) == 1) ? Rb_or_imm : Rc; }}); - 0x16: cmovlbc({{ Rc = ((Ra & 1) == 0) ? Rb_or_imm : Rc; }}); - 0x24: cmoveq({{ Rc = (Ra == 0) ? Rb_or_imm : Rc; }}); - 0x26: cmovne({{ Rc = (Ra != 0) ? Rb_or_imm : Rc; }}); - 0x44: cmovlt({{ Rc = (Ra.sq < 0) ? Rb_or_imm : Rc; }}); - 0x46: cmovge({{ Rc = (Ra.sq >= 0) ? Rb_or_imm : Rc; }}); - 0x64: cmovle({{ Rc = (Ra.sq <= 0) ? Rb_or_imm : Rc; }}); - 0x66: cmovgt({{ Rc = (Ra.sq > 0) ? Rb_or_imm : Rc; }}); - - // For AMASK, RA must be R31. - 0x61: decode RA { - 31: amask({{ Rc = Rb_or_imm & ~ULL(0x17); }}); - } - - // For IMPLVER, RA must be R31 and the B operand - // must be the immediate value 1. - 0x6c: decode RA { - 31: decode IMM { - 1: decode INTIMM { - // return EV5 for FULL_SYSTEM and EV6 otherwise - 1: implver({{ -#if FULL_SYSTEM - Rc = 1; -#else - Rc = 2; -#endif - }}); - } - } - } - -#if FULL_SYSTEM - // The mysterious 11.25... - 0x25: WarnUnimpl::eleven25(); -#endif - } - - 0x12: decode INTFUNC { - 0x39: sll({{ Rc = Ra << Rb_or_imm<5:0>; }}); - 0x34: srl({{ Rc = Ra.uq >> Rb_or_imm<5:0>; }}); - 0x3c: sra({{ Rc = Ra.sq >> Rb_or_imm<5:0>; }}); - - 0x02: mskbl({{ Rc = Ra & ~(mask( 8) << (Rb_or_imm<2:0> * 8)); }}); - 0x12: mskwl({{ Rc = Ra & ~(mask(16) << (Rb_or_imm<2:0> * 8)); }}); - 0x22: mskll({{ Rc = Ra & ~(mask(32) << (Rb_or_imm<2:0> * 8)); }}); - 0x32: mskql({{ Rc = Ra & ~(mask(64) << (Rb_or_imm<2:0> * 8)); }}); - - 0x52: mskwh({{ - int bv = Rb_or_imm<2:0>; - Rc = bv ? (Ra & ~(mask(16) >> (64 - 8 * bv))) : Ra; - }}); - 0x62: msklh({{ - int bv = Rb_or_imm<2:0>; - Rc = bv ? (Ra & ~(mask(32) >> (64 - 8 * bv))) : Ra; - }}); - 0x72: mskqh({{ - int bv = Rb_or_imm<2:0>; - Rc = bv ? (Ra & ~(mask(64) >> (64 - 8 * bv))) : Ra; - }}); - - 0x06: extbl({{ Rc = (Ra.uq >> (Rb_or_imm<2:0> * 8))< 7:0>; }}); - 0x16: extwl({{ Rc = (Ra.uq >> (Rb_or_imm<2:0> * 8))<15:0>; }}); - 0x26: extll({{ Rc = (Ra.uq >> (Rb_or_imm<2:0> * 8))<31:0>; }}); - 0x36: extql({{ Rc = (Ra.uq >> (Rb_or_imm<2:0> * 8)); }}); - - 0x5a: extwh({{ - Rc = (Ra << (64 - (Rb_or_imm<2:0> * 8))<5:0>)<15:0>; }}); - 0x6a: extlh({{ - Rc = (Ra << (64 - (Rb_or_imm<2:0> * 8))<5:0>)<31:0>; }}); - 0x7a: extqh({{ - Rc = (Ra << (64 - (Rb_or_imm<2:0> * 8))<5:0>); }}); - - 0x0b: insbl({{ Rc = Ra< 7:0> << (Rb_or_imm<2:0> * 8); }}); - 0x1b: inswl({{ Rc = Ra<15:0> << (Rb_or_imm<2:0> * 8); }}); - 0x2b: insll({{ Rc = Ra<31:0> << (Rb_or_imm<2:0> * 8); }}); - 0x3b: insql({{ Rc = Ra << (Rb_or_imm<2:0> * 8); }}); - - 0x57: inswh({{ - int bv = Rb_or_imm<2:0>; - Rc = bv ? (Ra.uq<15:0> >> (64 - 8 * bv)) : 0; - }}); - 0x67: inslh({{ - int bv = Rb_or_imm<2:0>; - Rc = bv ? (Ra.uq<31:0> >> (64 - 8 * bv)) : 0; - }}); - 0x77: insqh({{ - int bv = Rb_or_imm<2:0>; - Rc = bv ? (Ra.uq >> (64 - 8 * bv)) : 0; - }}); - - 0x30: zap({{ - uint64_t zapmask = 0; - for (int i = 0; i < 8; ++i) { - if (Rb_or_imm<i:>) - zapmask |= (mask(8) << (i * 8)); - } - Rc = Ra & ~zapmask; - }}); - 0x31: zapnot({{ - uint64_t zapmask = 0; - for (int i = 0; i < 8; ++i) { - if (!Rb_or_imm<i:>) - zapmask |= (mask(8) << (i * 8)); - } - Rc = Ra & ~zapmask; - }}); - } - - 0x13: decode INTFUNC { // integer multiplies - 0x00: mull({{ Rc.sl = Ra.sl * Rb_or_imm.sl; }}, IntMultOp); - 0x20: mulq({{ Rc = Ra * Rb_or_imm; }}, IntMultOp); - 0x30: umulh({{ - uint64_t hi, lo; - mul128(Ra, Rb_or_imm, hi, lo); - Rc = hi; - }}, IntMultOp); - 0x40: mullv({{ - // 32-bit multiply with trap on overflow - int64_t Rax = Ra.sl; // sign extended version of Ra.sl - int64_t Rbx = Rb_or_imm.sl; - int64_t tmp = Rax * Rbx; - // To avoid overflow, all the upper 32 bits must match - // the sign bit of the lower 32. We code this as - // checking the upper 33 bits for all 0s or all 1s. - uint64_t sign_bits = tmp<63:31>; - if (sign_bits != 0 && sign_bits != mask(33)) - fault = new IntegerOverflowFault; - Rc.sl = tmp<31:0>; - }}, IntMultOp); - 0x60: mulqv({{ - // 64-bit multiply with trap on overflow - uint64_t hi, lo; - mul128(Ra, Rb_or_imm, hi, lo); - // all the upper 64 bits must match the sign bit of - // the lower 64 - if (!((hi == 0 && lo<63:> == 0) || - (hi == mask(64) && lo<63:> == 1))) - fault = new IntegerOverflowFault; - Rc = lo; - }}, IntMultOp); - } - - 0x1c: decode INTFUNC { - 0x00: decode RA { 31: sextb({{ Rc.sb = Rb_or_imm< 7:0>; }}); } - 0x01: decode RA { 31: sextw({{ Rc.sw = Rb_or_imm<15:0>; }}); } - 0x32: ctlz({{ - uint64_t count = 0; - uint64_t temp = Rb; - if (temp<63:32>) temp >>= 32; else count += 32; - if (temp<31:16>) temp >>= 16; else count += 16; - if (temp<15:8>) temp >>= 8; else count += 8; - if (temp<7:4>) temp >>= 4; else count += 4; - if (temp<3:2>) temp >>= 2; else count += 2; - if (temp<1:1>) temp >>= 1; else count += 1; - if ((temp<0:0>) != 0x1) count += 1; - Rc = count; - }}, IntAluOp); - - 0x33: cttz({{ - uint64_t count = 0; - uint64_t temp = Rb; - if (!(temp<31:0>)) { temp >>= 32; count += 32; } - if (!(temp<15:0>)) { temp >>= 16; count += 16; } - if (!(temp<7:0>)) { temp >>= 8; count += 8; } - if (!(temp<3:0>)) { temp >>= 4; count += 4; } - if (!(temp<1:0>)) { temp >>= 2; count += 2; } - if (!(temp<0:0> & ULL(0x1))) count += 1; - Rc = count; - }}, IntAluOp); - - format FailUnimpl { - 0x30: ctpop(); - 0x31: perr(); - 0x34: unpkbw(); - 0x35: unpkbl(); - 0x36: pkwb(); - 0x37: pklb(); - 0x38: minsb8(); - 0x39: minsw4(); - 0x3a: minub8(); - 0x3b: minuw4(); - 0x3c: maxub8(); - 0x3d: maxuw4(); - 0x3e: maxsb8(); - 0x3f: maxsw4(); - } - - format BasicOperateWithNopCheck { - 0x70: decode RB { - 31: ftoit({{ Rc = Fa.uq; }}, FloatCvtOp); - } - 0x78: decode RB { - 31: ftois({{ Rc.sl = t_to_s(Fa.uq); }}, - FloatCvtOp); - } - } - } - } - - // Conditional branches. - format CondBranch { - 0x39: beq({{ cond = (Ra == 0); }}); - 0x3d: bne({{ cond = (Ra != 0); }}); - 0x3e: bge({{ cond = (Ra.sq >= 0); }}); - 0x3f: bgt({{ cond = (Ra.sq > 0); }}); - 0x3b: ble({{ cond = (Ra.sq <= 0); }}); - 0x3a: blt({{ cond = (Ra.sq < 0); }}); - 0x38: blbc({{ cond = ((Ra & 1) == 0); }}); - 0x3c: blbs({{ cond = ((Ra & 1) == 1); }}); - - 0x31: fbeq({{ cond = (Fa == 0); }}); - 0x35: fbne({{ cond = (Fa != 0); }}); - 0x36: fbge({{ cond = (Fa >= 0); }}); - 0x37: fbgt({{ cond = (Fa > 0); }}); - 0x33: fble({{ cond = (Fa <= 0); }}); - 0x32: fblt({{ cond = (Fa < 0); }}); - } - - // unconditional branches - format UncondBranch { - 0x30: br(); - 0x34: bsr(IsCall); - } - - // indirect branches - 0x1a: decode JMPFUNC { - format Jump { - 0: jmp(); - 1: jsr(IsCall); - 2: ret(IsReturn); - 3: jsr_coroutine(IsCall, IsReturn); - } - } - - // Square root and integer-to-FP moves - 0x14: decode FP_SHORTFUNC { - // Integer to FP register moves must have RB == 31 - 0x4: decode RB { - 31: decode FP_FULLFUNC { - format BasicOperateWithNopCheck { - 0x004: itofs({{ Fc.uq = s_to_t(Ra.ul); }}, FloatCvtOp); - 0x024: itoft({{ Fc.uq = Ra.uq; }}, FloatCvtOp); - 0x014: FailUnimpl::itoff(); // VAX-format conversion - } - } - } - - // Square root instructions must have FA == 31 - 0xb: decode FA { - 31: decode FP_TYPEFUNC { - format FloatingPointOperate { -#if SS_COMPATIBLE_FP - 0x0b: sqrts({{ - if (Fb < 0.0) - fault = new ArithmeticFault; - Fc = sqrt(Fb); - }}, FloatSqrtOp); -#else - 0x0b: sqrts({{ - if (Fb.sf < 0.0) - fault = new ArithmeticFault; - Fc.sf = sqrt(Fb.sf); - }}, FloatSqrtOp); -#endif - 0x2b: sqrtt({{ - if (Fb < 0.0) - fault = new ArithmeticFault; - Fc = sqrt(Fb); - }}, FloatSqrtOp); - } - } - } - - // VAX-format sqrtf and sqrtg are not implemented - 0xa: FailUnimpl::sqrtfg(); - } - - // IEEE floating point - 0x16: decode FP_SHORTFUNC_TOP2 { - // The top two bits of the short function code break this - // space into four groups: binary ops, compares, reserved, and - // conversions. See Table 4-12 of AHB. There are different - // special cases in these different groups, so we decode on - // these top two bits first just to select a decode strategy. - // Most of these instructions may have various trapping and - // rounding mode flags set; these are decoded in the - // FloatingPointDecode template used by the - // FloatingPointOperate format. - - // add/sub/mul/div: just decode on the short function code - // and source type. All valid trapping and rounding modes apply. - 0: decode FP_TRAPMODE { - // check for valid trapping modes here - 0,1,5,7: decode FP_TYPEFUNC { - format FloatingPointOperate { -#if SS_COMPATIBLE_FP - 0x00: adds({{ Fc = Fa + Fb; }}); - 0x01: subs({{ Fc = Fa - Fb; }}); - 0x02: muls({{ Fc = Fa * Fb; }}, FloatMultOp); - 0x03: divs({{ Fc = Fa / Fb; }}, FloatDivOp); -#else - 0x00: adds({{ Fc.sf = Fa.sf + Fb.sf; }}); - 0x01: subs({{ Fc.sf = Fa.sf - Fb.sf; }}); - 0x02: muls({{ Fc.sf = Fa.sf * Fb.sf; }}, FloatMultOp); - 0x03: divs({{ Fc.sf = Fa.sf / Fb.sf; }}, FloatDivOp); -#endif - - 0x20: addt({{ Fc = Fa + Fb; }}); - 0x21: subt({{ Fc = Fa - Fb; }}); - 0x22: mult({{ Fc = Fa * Fb; }}, FloatMultOp); - 0x23: divt({{ Fc = Fa / Fb; }}, FloatDivOp); - } - } - } - - // Floating-point compare instructions must have the default - // rounding mode, and may use the default trapping mode or - // /SU. Both trapping modes are treated the same by M5; the - // only difference on the real hardware (as far a I can tell) - // is that without /SU you'd get an imprecise trap if you - // tried to compare a NaN with something else (instead of an - // "unordered" result). - 1: decode FP_FULLFUNC { - format BasicOperateWithNopCheck { - 0x0a5, 0x5a5: cmpteq({{ Fc = (Fa == Fb) ? 2.0 : 0.0; }}, - FloatCmpOp); - 0x0a7, 0x5a7: cmptle({{ Fc = (Fa <= Fb) ? 2.0 : 0.0; }}, - FloatCmpOp); - 0x0a6, 0x5a6: cmptlt({{ Fc = (Fa < Fb) ? 2.0 : 0.0; }}, - FloatCmpOp); - 0x0a4, 0x5a4: cmptun({{ // unordered - Fc = (!(Fa < Fb) && !(Fa == Fb) && !(Fa > Fb)) ? 2.0 : 0.0; - }}, FloatCmpOp); - } - } - - // The FP-to-integer and integer-to-FP conversion insts - // require that FA be 31. - 3: decode FA { - 31: decode FP_TYPEFUNC { - format FloatingPointOperate { - 0x2f: decode FP_ROUNDMODE { - format FPFixedRounding { - // "chopped" i.e. round toward zero - 0: cvttq({{ Fc.sq = (int64_t)trunc(Fb); }}, - Chopped); - // round to minus infinity - 1: cvttq({{ Fc.sq = (int64_t)floor(Fb); }}, - MinusInfinity); - } - default: cvttq({{ Fc.sq = (int64_t)nearbyint(Fb); }}); - } - - // The cvtts opcode is overloaded to be cvtst if the trap - // mode is 2 or 6 (which are not valid otherwise) - 0x2c: decode FP_FULLFUNC { - format BasicOperateWithNopCheck { - // trap on denorm version "cvtst/s" is - // simulated same as cvtst - 0x2ac, 0x6ac: cvtst({{ Fc = Fb.sf; }}); - } - default: cvtts({{ Fc.sf = Fb; }}); - } - - // The trapping mode for integer-to-FP conversions - // must be /SUI or nothing; /U and /SU are not - // allowed. The full set of rounding modes are - // supported though. - 0x3c: decode FP_TRAPMODE { - 0,7: cvtqs({{ Fc.sf = Fb.sq; }}); - } - 0x3e: decode FP_TRAPMODE { - 0,7: cvtqt({{ Fc = Fb.sq; }}); - } - } - } - } - } - - // misc FP operate - 0x17: decode FP_FULLFUNC { - format BasicOperateWithNopCheck { - 0x010: cvtlq({{ - Fc.sl = (Fb.uq<63:62> << 30) | Fb.uq<58:29>; - }}); - 0x030: cvtql({{ - Fc.uq = (Fb.uq<31:30> << 62) | (Fb.uq<29:0> << 29); - }}); - - // We treat the precise & imprecise trapping versions of - // cvtql identically. - 0x130, 0x530: cvtqlv({{ - // To avoid overflow, all the upper 32 bits must match - // the sign bit of the lower 32. We code this as - // checking the upper 33 bits for all 0s or all 1s. - uint64_t sign_bits = Fb.uq<63:31>; - if (sign_bits != 0 && sign_bits != mask(33)) - fault = new IntegerOverflowFault; - Fc.uq = (Fb.uq<31:30> << 62) | (Fb.uq<29:0> << 29); - }}); - - 0x020: cpys({{ // copy sign - Fc.uq = (Fa.uq<63:> << 63) | Fb.uq<62:0>; - }}); - 0x021: cpysn({{ // copy sign negated - Fc.uq = (~Fa.uq<63:> << 63) | Fb.uq<62:0>; - }}); - 0x022: cpyse({{ // copy sign and exponent - Fc.uq = (Fa.uq<63:52> << 52) | Fb.uq<51:0>; - }}); - - 0x02a: fcmoveq({{ Fc = (Fa == 0) ? Fb : Fc; }}); - 0x02b: fcmovne({{ Fc = (Fa != 0) ? Fb : Fc; }}); - 0x02c: fcmovlt({{ Fc = (Fa < 0) ? Fb : Fc; }}); - 0x02d: fcmovge({{ Fc = (Fa >= 0) ? Fb : Fc; }}); - 0x02e: fcmovle({{ Fc = (Fa <= 0) ? Fb : Fc; }}); - 0x02f: fcmovgt({{ Fc = (Fa > 0) ? Fb : Fc; }}); - - 0x024: mt_fpcr({{ FPCR = Fa.uq; }}, IsIprAccess); - 0x025: mf_fpcr({{ Fa.uq = FPCR; }}, IsIprAccess); - } - } - - // miscellaneous mem-format ops - 0x18: decode MEMFUNC { - format WarnUnimpl { - 0x8000: fetch(); - 0xa000: fetch_m(); - 0xe800: ecb(); - } - - format MiscPrefetch { - 0xf800: wh64({{ EA = Rb & ~ULL(63); }}, - {{ xc->writeHint(EA, 64, memAccessFlags); }}, - mem_flags = NO_FAULT, - inst_flags = [IsMemRef, IsDataPrefetch, - IsStore, MemWriteOp]); - } - - format BasicOperate { - 0xc000: rpcc({{ -#if FULL_SYSTEM - /* Rb is a fake dependency so here is a fun way to get - * the parser to understand that. - */ - Ra = xc->readMiscRegWithEffect(AlphaISA::IPR_CC, fault) + (Rb & 0); - -#else - Ra = curTick; -#endif - }}, IsUnverifiable); - - // All of the barrier instructions below do nothing in - // their execute() methods (hence the empty code blocks). - // All of their functionality is hard-coded in the - // pipeline based on the flags IsSerializing, - // IsMemBarrier, and IsWriteBarrier. In the current - // detailed CPU model, the execute() function only gets - // called at fetch, so there's no way to generate pipeline - // behavior at any other stage. Once we go to an - // exec-in-exec CPU model we should be able to get rid of - // these flags and implement this behavior via the - // execute() methods. - - // trapb is just a barrier on integer traps, where excb is - // a barrier on integer and FP traps. "EXCB is thus a - // superset of TRAPB." (Alpha ARM, Sec 4.11.4) We treat - // them the same though. - 0x0000: trapb({{ }}, IsSerializing, IsSerializeBefore, No_OpClass); - 0x0400: excb({{ }}, IsSerializing, IsSerializeBefore, No_OpClass); - 0x4000: mb({{ }}, IsMemBarrier, MemReadOp); - 0x4400: wmb({{ }}, IsWriteBarrier, MemWriteOp); - } - -#if FULL_SYSTEM - format BasicOperate { - 0xe000: rc({{ - Ra = xc->readIntrFlag(); - xc->setIntrFlag(0); - }}, IsNonSpeculative); - 0xf000: rs({{ - Ra = xc->readIntrFlag(); - xc->setIntrFlag(1); - }}, IsNonSpeculative); - } -#else - format FailUnimpl { - 0xe000: rc(); - 0xf000: rs(); - } -#endif - } - -#if FULL_SYSTEM - 0x00: CallPal::call_pal({{ - if (!palValid || - (palPriv - && xc->readMiscRegWithEffect(AlphaISA::IPR_ICM, fault) != AlphaISA::mode_kernel)) { - // invalid pal function code, or attempt to do privileged - // PAL call in non-kernel mode - fault = new UnimplementedOpcodeFault; - } - else { - // check to see if simulator wants to do something special - // on this PAL call (including maybe suppress it) - bool dopal = xc->simPalCheck(palFunc); - - if (dopal) { - xc->setMiscRegWithEffect(AlphaISA::IPR_EXC_ADDR, NPC); - NPC = xc->readMiscRegWithEffect(AlphaISA::IPR_PAL_BASE, fault) + palOffset; - } - } - }}, IsNonSpeculative); -#else - 0x00: decode PALFUNC { - format EmulatedCallPal { - 0x00: halt ({{ - SimExit(curTick, "halt instruction encountered"); - }}, IsNonSpeculative); - 0x83: callsys({{ - xc->syscall(); - }}, IsNonSpeculative); - // Read uniq reg into ABI return value register (r0) - 0x9e: rduniq({{ R0 = Runiq; }}, IsIprAccess); - // Write uniq reg with value from ABI arg register (r16) - 0x9f: wruniq({{ Runiq = R16; }}, IsIprAccess); - } - } -#endif - -#if FULL_SYSTEM - 0x1b: decode PALMODE { - 0: OpcdecFault::hw_st_quad(); - 1: decode HW_LDST_QUAD { - format HwLoad { - 0: hw_ld({{ EA = (Rb + disp) & ~3; }}, {{ Ra = Mem.ul; }}, L); - 1: hw_ld({{ EA = (Rb + disp) & ~7; }}, {{ Ra = Mem.uq; }}, Q); - } - } - } - - 0x1f: decode PALMODE { - 0: OpcdecFault::hw_st_cond(); - format HwStore { - 1: decode HW_LDST_COND { - 0: decode HW_LDST_QUAD { - 0: hw_st({{ EA = (Rb + disp) & ~3; }}, - {{ Mem.ul = Ra<31:0>; }}, L); - 1: hw_st({{ EA = (Rb + disp) & ~7; }}, - {{ Mem.uq = Ra.uq; }}, Q); - } - - 1: FailUnimpl::hw_st_cond(); - } - } - } - - 0x19: decode PALMODE { - 0: OpcdecFault::hw_mfpr(); - format HwMoveIPR { - 1: hw_mfpr({{ - Ra = xc->readMiscRegWithEffect(ipr_index, fault); - }}, IsIprAccess); - } - } - - 0x1d: decode PALMODE { - 0: OpcdecFault::hw_mtpr(); - format HwMoveIPR { - 1: hw_mtpr({{ - xc->setMiscRegWithEffect(ipr_index, Ra); - if (traceData) { traceData->setData(Ra); } - }}, IsIprAccess); - } - } - - format BasicOperate { - 0x1e: decode PALMODE { - 0: OpcdecFault::hw_rei(); - 1:hw_rei({{ xc->hwrei(); }}, IsSerializing, IsSerializeBefore); - } - - // M5 special opcodes use the reserved 0x01 opcode space - 0x01: decode M5FUNC { - 0x00: arm({{ - AlphaPseudo::arm(xc->xcBase()); - }}, IsNonSpeculative); - 0x01: quiesce({{ - AlphaPseudo::quiesce(xc->xcBase()); - }}, IsNonSpeculative, IsQuiesce); - 0x02: quiesceNs({{ - AlphaPseudo::quiesceNs(xc->xcBase(), R16); - }}, IsNonSpeculative, IsQuiesce); - 0x03: quiesceCycles({{ - AlphaPseudo::quiesceCycles(xc->xcBase(), R16); - }}, IsNonSpeculative, IsQuiesce); - 0x04: quiesceTime({{ - R0 = AlphaPseudo::quiesceTime(xc->xcBase()); - }}, IsNonSpeculative); - 0x10: ivlb({{ - AlphaPseudo::ivlb(xc->xcBase()); - }}, No_OpClass, IsNonSpeculative); - 0x11: ivle({{ - AlphaPseudo::ivle(xc->xcBase()); - }}, No_OpClass, IsNonSpeculative); - 0x20: m5exit_old({{ - AlphaPseudo::m5exit_old(xc->xcBase()); - }}, No_OpClass, IsNonSpeculative); - 0x21: m5exit({{ - AlphaPseudo::m5exit(xc->xcBase(), R16); - }}, No_OpClass, IsNonSpeculative); - 0x30: initparam({{ Ra = xc->xcBase()->getCpuPtr()->system->init_param; }}); - 0x40: resetstats({{ - AlphaPseudo::resetstats(xc->xcBase(), R16, R17); - }}, IsNonSpeculative); - 0x41: dumpstats({{ - AlphaPseudo::dumpstats(xc->xcBase(), R16, R17); - }}, IsNonSpeculative); - 0x42: dumpresetstats({{ - AlphaPseudo::dumpresetstats(xc->xcBase(), R16, R17); - }}, IsNonSpeculative); - 0x43: m5checkpoint({{ - AlphaPseudo::m5checkpoint(xc->xcBase(), R16, R17); - }}, IsNonSpeculative); - 0x50: m5readfile({{ - R0 = AlphaPseudo::readfile(xc->xcBase(), R16, R17, R18); - }}, IsNonSpeculative); - 0x51: m5break({{ - AlphaPseudo::debugbreak(xc->xcBase()); - }}, IsNonSpeculative); - 0x52: m5switchcpu({{ - AlphaPseudo::switchcpu(xc->xcBase()); - }}, IsNonSpeculative); - 0x53: m5addsymbol({{ - AlphaPseudo::addsymbol(xc->xcBase(), R16, R17); - }}, IsNonSpeculative); - 0x54: m5panic({{ - panic("M5 panic instruction called at pc=%#x.", xc->readPC()); - }}, IsNonSpeculative); - - } - } -#endif -} diff --git a/arch/alpha/isa/fp.isa b/arch/alpha/isa/fp.isa deleted file mode 100644 index f34c13c42..000000000 --- a/arch/alpha/isa/fp.isa +++ /dev/null @@ -1,301 +0,0 @@ -// -*- mode:c++ -*- - -// Copyright (c) 2003-2005 The Regents of The University of Michigan -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer; -// redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution; -// neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -output exec {{ - /// Check "FP enabled" machine status bit. Called when executing any FP - /// instruction in full-system mode. - /// @retval Full-system mode: NoFault if FP is enabled, FenFault - /// if not. Non-full-system mode: always returns NoFault. -#if FULL_SYSTEM - inline Fault checkFpEnableFault(%(CPU_exec_context)s *xc) - { - Fault fault = NoFault; // dummy... this ipr access should not fault - if (!EV5::ICSR_FPE(xc->readMiscRegWithEffect(AlphaISA::IPR_ICSR, fault))) { - fault = new FloatEnableFault; - } - return fault; - } -#else - inline Fault checkFpEnableFault(%(CPU_exec_context)s *xc) - { - return NoFault; - } -#endif -}}; - -output header {{ - /** - * Base class for general floating-point instructions. Includes - * support for various Alpha rounding and trapping modes. Only FP - * instructions that require this support are derived from this - * class; the rest derive directly from AlphaStaticInst. - */ - class AlphaFP : public AlphaStaticInst - { - public: - /// Alpha FP rounding modes. - enum RoundingMode { - Chopped = 0, ///< round toward zero - Minus_Infinity = 1, ///< round toward minus infinity - Normal = 2, ///< round to nearest (default) - Dynamic = 3, ///< use FPCR setting (in instruction) - Plus_Infinity = 3 ///< round to plus inifinity (in FPCR) - }; - - /// Alpha FP trapping modes. - /// For instructions that produce integer results, the - /// "Underflow Enable" modes really mean "Overflow Enable", and - /// the assembly modifier is V rather than U. - enum TrappingMode { - /// default: nothing enabled - Imprecise = 0, ///< no modifier - /// underflow/overflow traps enabled, inexact disabled - Underflow_Imprecise = 1, ///< /U or /V - Underflow_Precise = 5, ///< /SU or /SV - /// underflow/overflow and inexact traps enabled - Underflow_Inexact_Precise = 7 ///< /SUI or /SVI - }; - - protected: - /// Map Alpha rounding mode to C99 constants from <fenv.h>. - static const int alphaToC99RoundingMode[]; - - /// Map enum RoundingMode values to disassembly suffixes. - static const char *roundingModeSuffix[]; - /// Map enum TrappingMode values to FP disassembly suffixes. - static const char *fpTrappingModeSuffix[]; - /// Map enum TrappingMode values to integer disassembly suffixes. - static const char *intTrappingModeSuffix[]; - - /// This instruction's rounding mode. - RoundingMode roundingMode; - /// This instruction's trapping mode. - TrappingMode trappingMode; - - /// Have we warned about this instruction's unsupported - /// rounding mode (if applicable)? - mutable bool warnedOnRounding; - - /// Have we warned about this instruction's unsupported - /// trapping mode (if applicable)? - mutable bool warnedOnTrapping; - - /// Constructor - AlphaFP(const char *mnem, ExtMachInst _machInst, OpClass __opClass) - : AlphaStaticInst(mnem, _machInst, __opClass), - roundingMode((enum RoundingMode)FP_ROUNDMODE), - trappingMode((enum TrappingMode)FP_TRAPMODE), - warnedOnRounding(false), - warnedOnTrapping(false) - { - } - - int getC99RoundingMode(uint64_t fpcr_val) const; - - // This differs from the AlphaStaticInst version only in - // printing suffixes for non-default rounding & trapping modes. - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; - -}}; - - -output decoder {{ - int - AlphaFP::getC99RoundingMode(uint64_t fpcr_val) const - { - if (roundingMode == Dynamic) { - return alphaToC99RoundingMode[bits(fpcr_val, 59, 58)]; - } - else { - return alphaToC99RoundingMode[roundingMode]; - } - } - - std::string - AlphaFP::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { - std::string mnem_str(mnemonic); - -#ifndef SS_COMPATIBLE_DISASSEMBLY - std::string suffix(""); - suffix += ((_destRegIdx[0] >= FP_Base_DepTag) - ? fpTrappingModeSuffix[trappingMode] - : intTrappingModeSuffix[trappingMode]); - suffix += roundingModeSuffix[roundingMode]; - - if (suffix != "") { - mnem_str = csprintf("%s/%s", mnemonic, suffix); - } -#endif - - std::stringstream ss; - ccprintf(ss, "%-10s ", mnem_str.c_str()); - - // just print the first two source regs... if there's - // a third one, it's a read-modify-write dest (Rc), - // e.g. for CMOVxx - if (_numSrcRegs > 0) { - printReg(ss, _srcRegIdx[0]); - } - if (_numSrcRegs > 1) { - ss << ","; - printReg(ss, _srcRegIdx[1]); - } - - // just print the first dest... if there's a second one, - // it's generally implicit - if (_numDestRegs > 0) { - if (_numSrcRegs > 0) - ss << ","; - printReg(ss, _destRegIdx[0]); - } - - return ss.str(); - } - - const int AlphaFP::alphaToC99RoundingMode[] = { - FE_TOWARDZERO, // Chopped - FE_DOWNWARD, // Minus_Infinity - FE_TONEAREST, // Normal - FE_UPWARD // Dynamic in inst, Plus_Infinity in FPCR - }; - - const char *AlphaFP::roundingModeSuffix[] = { "c", "m", "", "d" }; - // mark invalid trapping modes, but don't fail on them, because - // you could decode anything on a misspeculated path - const char *AlphaFP::fpTrappingModeSuffix[] = - { "", "u", "INVTM2", "INVTM3", "INVTM4", "su", "INVTM6", "sui" }; - const char *AlphaFP::intTrappingModeSuffix[] = - { "", "v", "INVTM2", "INVTM3", "INVTM4", "sv", "INVTM6", "svi" }; -}}; - -// FP instruction class execute method template. Handles non-standard -// rounding modes. -def template FloatingPointExecute {{ - Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - if (trappingMode != Imprecise && !warnedOnTrapping) { - warn("%s: non-standard trapping mode not supported", - generateDisassembly(0, NULL)); - warnedOnTrapping = true; - } - - Fault fault = NoFault; - - %(fp_enable_check)s; - %(op_decl)s; - %(op_rd)s; -#if USE_FENV - if (roundingMode == Normal) { - %(code)s; - } else { - fesetround(getC99RoundingMode( - xc->readMiscReg(AlphaISA::Fpcr_DepTag))); - %(code)s; - fesetround(FE_TONEAREST); - } -#else - if (roundingMode != Normal && !warnedOnRounding) { - warn("%s: non-standard rounding mode not supported", - generateDisassembly(0, NULL)); - warnedOnRounding = true; - } - %(code)s; -#endif - - if (fault == NoFault) { - %(op_wb)s; - } - - return fault; - } -}}; - -// FP instruction class execute method template where no dynamic -// rounding mode control is needed. Like BasicExecute, but includes -// check & warning for non-standard trapping mode. -def template FPFixedRoundingExecute {{ - Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - if (trappingMode != Imprecise && !warnedOnTrapping) { - warn("%s: non-standard trapping mode not supported", - generateDisassembly(0, NULL)); - warnedOnTrapping = true; - } - - Fault fault = NoFault; - - %(fp_enable_check)s; - %(op_decl)s; - %(op_rd)s; - %(code)s; - - if (fault == NoFault) { - %(op_wb)s; - } - - return fault; - } -}}; - -def template FloatingPointDecode {{ - { - AlphaStaticInst *i = new %(class_name)s(machInst); - if (FC == 31) { - i = makeNop(i); - } - return i; - } -}}; - -// General format for floating-point operate instructions: -// - Checks trapping and rounding mode flags. Trapping modes -// currently unimplemented (will fail). -// - Generates NOP if FC == 31. -def format FloatingPointOperate(code, *opt_args) {{ - iop = InstObjParams(name, Name, 'AlphaFP', CodeBlock(code), opt_args) - decode_block = FloatingPointDecode.subst(iop) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - exec_output = FloatingPointExecute.subst(iop) -}}; - -// Special format for cvttq where rounding mode is pre-decoded -def format FPFixedRounding(code, class_suffix, *opt_args) {{ - Name += class_suffix - iop = InstObjParams(name, Name, 'AlphaFP', CodeBlock(code), opt_args) - decode_block = FloatingPointDecode.subst(iop) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - exec_output = FPFixedRoundingExecute.subst(iop) -}}; - diff --git a/arch/alpha/isa/int.isa b/arch/alpha/isa/int.isa deleted file mode 100644 index 17ecc1a51..000000000 --- a/arch/alpha/isa/int.isa +++ /dev/null @@ -1,128 +0,0 @@ -// -*- mode:c++ -*- - -// Copyright (c) 2003-2005 The Regents of The University of Michigan -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer; -// redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution; -// neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -output header {{ - /** - * Base class for integer immediate instructions. - */ - class IntegerImm : public AlphaStaticInst - { - protected: - /// Immediate operand value (unsigned 8-bit int). - uint8_t imm; - - /// Constructor - IntegerImm(const char *mnem, ExtMachInst _machInst, OpClass __opClass) - : AlphaStaticInst(mnem, _machInst, __opClass), imm(INTIMM) - { - } - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; -}}; - -output decoder {{ - std::string - IntegerImm::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { - std::stringstream ss; - - ccprintf(ss, "%-10s ", mnemonic); - - // just print the first source reg... if there's - // a second one, it's a read-modify-write dest (Rc), - // e.g. for CMOVxx - if (_numSrcRegs > 0) { - printReg(ss, _srcRegIdx[0]); - ss << ","; - } - - ss << (int)imm; - - if (_numDestRegs > 0) { - ss << ","; - printReg(ss, _destRegIdx[0]); - } - - return ss.str(); - } -}}; - - -def template RegOrImmDecode {{ - { - AlphaStaticInst *i = - (IMM) ? (AlphaStaticInst *)new %(class_name)sImm(machInst) - : (AlphaStaticInst *)new %(class_name)s(machInst); - if (RC == 31) { - i = makeNop(i); - } - return i; - } -}}; - -// Primary format for integer operate instructions: -// - Generates both reg-reg and reg-imm versions if Rb_or_imm is used. -// - Generates NOP if RC == 31. -def format IntegerOperate(code, *opt_flags) {{ - # If the code block contains 'Rb_or_imm', we define two instructions, - # one using 'Rb' and one using 'imm', and have the decoder select - # the right one. - uses_imm = (code.find('Rb_or_imm') != -1) - if uses_imm: - orig_code = code - # base code is reg version: - # rewrite by substituting 'Rb' for 'Rb_or_imm' - code = re.sub(r'Rb_or_imm', 'Rb', orig_code) - # generate immediate version by substituting 'imm' - # note that imm takes no extenstion, so we extend - # the regexp to replace any extension as well - imm_code = re.sub(r'Rb_or_imm(\.\w+)?', 'imm', orig_code) - - # generate declaration for register version - cblk = CodeBlock(code) - iop = InstObjParams(name, Name, 'AlphaStaticInst', cblk, opt_flags) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - exec_output = BasicExecute.subst(iop) - - if uses_imm: - # append declaration for imm version - imm_cblk = CodeBlock(imm_code) - imm_iop = InstObjParams(name, Name + 'Imm', 'IntegerImm', imm_cblk, - opt_flags) - header_output += BasicDeclare.subst(imm_iop) - decoder_output += BasicConstructor.subst(imm_iop) - exec_output += BasicExecute.subst(imm_iop) - # decode checks IMM bit to pick correct version - decode_block = RegOrImmDecode.subst(iop) - else: - # no imm version: just check for nop - decode_block = OperateNopCheckDecode.subst(iop) -}}; diff --git a/arch/alpha/isa/main.isa b/arch/alpha/isa/main.isa deleted file mode 100644 index 80a5e9ca1..000000000 --- a/arch/alpha/isa/main.isa +++ /dev/null @@ -1,448 +0,0 @@ -// -*- mode:c++ -*- - -// Copyright (c) 2003-2005 The Regents of The University of Michigan -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer; -// redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution; -// neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -output header {{ -#include <sstream> -#include <iostream> -#include <iomanip> - -#include "config/ss_compatible_fp.hh" -#include "cpu/static_inst.hh" -#include "arch/alpha/faults.hh" -#include "mem/mem_req.hh" // some constructors use MemReq flags -}}; - -output decoder {{ -#include "base/cprintf.hh" -#include "base/fenv.hh" -#include "base/loader/symtab.hh" -#include "config/ss_compatible_fp.hh" -#include "cpu/exec_context.hh" // for Jump::branchTarget() - -#include <math.h> - -using namespace AlphaISA; -}}; - -output exec {{ -#include <math.h> - -#if FULL_SYSTEM -#include "sim/pseudo_inst.hh" -#endif -#include "base/fenv.hh" -#include "config/ss_compatible_fp.hh" -#include "cpu/base.hh" -#include "cpu/exetrace.hh" -#include "sim/sim_exit.hh" - -using namespace AlphaISA; -}}; - -//////////////////////////////////////////////////////////////////// -// -// Namespace statement. Everything below this line will be in the -// AlphaISAInst namespace. -// - - -namespace AlphaISA; - -//////////////////////////////////////////////////////////////////// -// -// Bitfield definitions. -// - -// Universal (format-independent) fields -def bitfield PALMODE <32:32>; -def bitfield OPCODE <31:26>; -def bitfield RA <25:21>; -def bitfield RB <20:16>; - -// Memory format -def signed bitfield MEMDISP <15: 0>; // displacement -def bitfield MEMFUNC <15: 0>; // function code (same field, unsigned) - -// Memory-format jumps -def bitfield JMPFUNC <15:14>; // function code (disp<15:14>) -def bitfield JMPHINT <13: 0>; // tgt Icache idx hint (disp<13:0>) - -// Branch format -def signed bitfield BRDISP <20: 0>; // displacement - -// Integer operate format(s>; -def bitfield INTIMM <20:13>; // integer immediate (literal) -def bitfield IMM <12:12>; // immediate flag -def bitfield INTFUNC <11: 5>; // function code -def bitfield RC < 4: 0>; // dest reg - -// Floating-point operate format -def bitfield FA <25:21>; -def bitfield FB <20:16>; -def bitfield FP_FULLFUNC <15: 5>; // complete function code - def bitfield FP_TRAPMODE <15:13>; // trapping mode - def bitfield FP_ROUNDMODE <12:11>; // rounding mode - def bitfield FP_TYPEFUNC <10: 5>; // type+func: handiest for decoding - def bitfield FP_SRCTYPE <10: 9>; // source reg type - def bitfield FP_SHORTFUNC < 8: 5>; // short function code - def bitfield FP_SHORTFUNC_TOP2 <8:7>; // top 2 bits of short func code -def bitfield FC < 4: 0>; // dest reg - -// PALcode format -def bitfield PALFUNC <25: 0>; // function code - -// EV5 PAL instructions: -// HW_LD/HW_ST -def bitfield HW_LDST_PHYS <15>; // address is physical -def bitfield HW_LDST_ALT <14>; // use ALT_MODE IPR -def bitfield HW_LDST_WRTCK <13>; // HW_LD only: fault if no write acc -def bitfield HW_LDST_QUAD <12>; // size: 0=32b, 1=64b -def bitfield HW_LDST_VPTE <11>; // HW_LD only: is PTE fetch -def bitfield HW_LDST_LOCK <10>; // HW_LD only: is load locked -def bitfield HW_LDST_COND <10>; // HW_ST only: is store conditional -def signed bitfield HW_LDST_DISP <9:0>; // signed displacement - -// HW_REI -def bitfield HW_REI_TYP <15:14>; // type: stalling vs. non-stallingk -def bitfield HW_REI_MBZ <13: 0>; // must be zero - -// HW_MTPR/MW_MFPR -def bitfield HW_IPR_IDX <15:0>; // IPR index - -// M5 instructions -def bitfield M5FUNC <7:0>; - -def operand_types {{ - 'sb' : ('signed int', 8), - 'ub' : ('unsigned int', 8), - 'sw' : ('signed int', 16), - 'uw' : ('unsigned int', 16), - 'sl' : ('signed int', 32), - 'ul' : ('unsigned int', 32), - 'sq' : ('signed int', 64), - 'uq' : ('unsigned int', 64), - 'sf' : ('float', 32), - 'df' : ('float', 64) -}}; - -def operands {{ - # Int regs default to unsigned, but code should not count on this. - # For clarity, descriptions that depend on unsigned behavior should - # explicitly specify '.uq'. - 'Ra': ('IntReg', 'uq', 'PALMODE ? AlphaISA::reg_redir[RA] : RA', - 'IsInteger', 1), - 'Rb': ('IntReg', 'uq', 'PALMODE ? AlphaISA::reg_redir[RB] : RB', - 'IsInteger', 2), - 'Rc': ('IntReg', 'uq', 'PALMODE ? AlphaISA::reg_redir[RC] : RC', - 'IsInteger', 3), - 'Fa': ('FloatReg', 'df', 'FA', 'IsFloating', 1), - 'Fb': ('FloatReg', 'df', 'FB', 'IsFloating', 2), - 'Fc': ('FloatReg', 'df', 'FC', 'IsFloating', 3), - 'Mem': ('Mem', 'uq', None, ('IsMemRef', 'IsLoad', 'IsStore'), 4), - 'NPC': ('NPC', 'uq', None, ( None, None, 'IsControl' ), 4), - 'Runiq': ('ControlReg', 'uq', 'TheISA::Uniq_DepTag', None, 1), - 'FPCR': (' ControlReg', 'uq', 'TheISA::Fpcr_DepTag', None, 1), - # The next two are hacks for non-full-system call-pal emulation - 'R0': ('IntReg', 'uq', '0', None, 1), - 'R16': ('IntReg', 'uq', '16', None, 1), - 'R17': ('IntReg', 'uq', '17', None, 1), - 'R18': ('IntReg', 'uq', '18', None, 1) -}}; - -//////////////////////////////////////////////////////////////////// -// -// Basic instruction classes/templates/formats etc. -// - -output header {{ -// uncomment the following to get SimpleScalar-compatible disassembly -// (useful for diffing output traces). -// #define SS_COMPATIBLE_DISASSEMBLY - - /** - * Base class for all Alpha static instructions. - */ - class AlphaStaticInst : public StaticInst - { - protected: - - /// Make AlphaISA register dependence tags directly visible in - /// this class and derived classes. Maybe these should really - /// live here and not in the AlphaISA namespace. - enum DependenceTags { - FP_Base_DepTag = AlphaISA::FP_Base_DepTag, - Fpcr_DepTag = AlphaISA::Fpcr_DepTag, - Uniq_DepTag = AlphaISA::Uniq_DepTag, - Lock_Flag_DepTag = AlphaISA::Lock_Flag_DepTag, - Lock_Addr_DepTag = AlphaISA::Lock_Addr_DepTag, - IPR_Base_DepTag = AlphaISA::IPR_Base_DepTag - }; - - /// Constructor. - AlphaStaticInst(const char *mnem, ExtMachInst _machInst, - OpClass __opClass) - : StaticInst(mnem, _machInst, __opClass) - { - } - - /// Print a register name for disassembly given the unique - /// dependence tag number (FP or int). - void printReg(std::ostream &os, int reg) const; - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; -}}; - -output decoder {{ - void - AlphaStaticInst::printReg(std::ostream &os, int reg) const - { - if (reg < FP_Base_DepTag) { - ccprintf(os, "r%d", reg); - } - else { - ccprintf(os, "f%d", reg - FP_Base_DepTag); - } - } - - std::string - AlphaStaticInst::generateDisassembly(Addr pc, - const SymbolTable *symtab) const - { - std::stringstream ss; - - ccprintf(ss, "%-10s ", mnemonic); - - // just print the first two source regs... if there's - // a third one, it's a read-modify-write dest (Rc), - // e.g. for CMOVxx - if (_numSrcRegs > 0) { - printReg(ss, _srcRegIdx[0]); - } - if (_numSrcRegs > 1) { - ss << ","; - printReg(ss, _srcRegIdx[1]); - } - - // just print the first dest... if there's a second one, - // it's generally implicit - if (_numDestRegs > 0) { - if (_numSrcRegs > 0) - ss << ","; - printReg(ss, _destRegIdx[0]); - } - - return ss.str(); - } -}}; - -// Declarations for execute() methods. -def template BasicExecDeclare {{ - Fault execute(%(CPU_exec_context)s *, Trace::InstRecord *) const; -}}; - -// Basic instruction class declaration template. -def template BasicDeclare {{ - /** - * Static instruction class for "%(mnemonic)s". - */ - class %(class_name)s : public %(base_class)s - { - public: - /// Constructor. - %(class_name)s(ExtMachInst machInst); - - %(BasicExecDeclare)s - }; -}}; - -// Basic instruction class constructor template. -def template BasicConstructor {{ - inline %(class_name)s::%(class_name)s(ExtMachInst machInst) - : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s) - { - %(constructor)s; - } -}}; - -// Basic instruction class execute method template. -def template BasicExecute {{ - Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Fault fault = NoFault; - - %(fp_enable_check)s; - %(op_decl)s; - %(op_rd)s; - %(code)s; - - if (fault == NoFault) { - %(op_wb)s; - } - - return fault; - } -}}; - -// Basic decode template. -def template BasicDecode {{ - return new %(class_name)s(machInst); -}}; - -// Basic decode template, passing mnemonic in as string arg to constructor. -def template BasicDecodeWithMnemonic {{ - return new %(class_name)s("%(mnemonic)s", machInst); -}}; - -// The most basic instruction format... used only for a few misc. insts -def format BasicOperate(code, *flags) {{ - iop = InstObjParams(name, Name, 'AlphaStaticInst', CodeBlock(code), flags) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = BasicDecode.subst(iop) - exec_output = BasicExecute.subst(iop) -}}; - - - -//////////////////////////////////////////////////////////////////// -// -// Nop -// - -output header {{ - /** - * Static instruction class for no-ops. This is a leaf class. - */ - class Nop : public AlphaStaticInst - { - /// Disassembly of original instruction. - const std::string originalDisassembly; - - public: - /// Constructor - Nop(const std::string _originalDisassembly, ExtMachInst _machInst) - : AlphaStaticInst("nop", _machInst, No_OpClass), - originalDisassembly(_originalDisassembly) - { - flags[IsNop] = true; - } - - ~Nop() { } - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - - %(BasicExecDeclare)s - }; - - /// Helper function for decoding nops. Substitute Nop object - /// for original inst passed in as arg (and delete latter). - static inline - AlphaStaticInst * - makeNop(AlphaStaticInst *inst) - { - AlphaStaticInst *nop = new Nop(inst->disassemble(0), inst->machInst); - delete inst; - return nop; - } -}}; - -output decoder {{ - std::string Nop::generateDisassembly(Addr pc, - const SymbolTable *symtab) const - { -#ifdef SS_COMPATIBLE_DISASSEMBLY - return originalDisassembly; -#else - return csprintf("%-10s (%s)", "nop", originalDisassembly); -#endif - } -}}; - -output exec {{ - Fault - Nop::execute(%(CPU_exec_context)s *, Trace::InstRecord *) const - { - return NoFault; - } -}}; - -// integer & FP operate instructions use Rc as dest, so check for -// Rc == 31 to detect nops -def template OperateNopCheckDecode {{ - { - AlphaStaticInst *i = new %(class_name)s(machInst); - if (RC == 31) { - i = makeNop(i); - } - return i; - } -}}; - -// Like BasicOperate format, but generates NOP if RC/FC == 31 -def format BasicOperateWithNopCheck(code, *opt_args) {{ - iop = InstObjParams(name, Name, 'AlphaStaticInst', CodeBlock(code), - opt_args) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = OperateNopCheckDecode.subst(iop) - exec_output = BasicExecute.subst(iop) -}}; - -// Integer instruction templates, formats, etc. -##include "int.isa" - -// Floating-point instruction templates, formats, etc. -##include "fp.isa" - -// Memory instruction templates, formats, etc. -##include "mem.isa" - -// Branch/jump instruction templates, formats, etc. -##include "branch.isa" - -// PAL instruction templates, formats, etc. -##include "pal.isa" - -// Opcdec fault instruction templates, formats, etc. -##include "opcdec.isa" - -// Unimplemented instruction templates, formats, etc. -##include "unimp.isa" - -// Unknown instruction templates, formats, etc. -##include "unknown.isa" - -// Execution utility functions -##include "util.isa" - -// The actual decoder -##include "decoder.isa" diff --git a/arch/alpha/isa/mem.isa b/arch/alpha/isa/mem.isa deleted file mode 100644 index 3c8b4f755..000000000 --- a/arch/alpha/isa/mem.isa +++ /dev/null @@ -1,702 +0,0 @@ -// -*- mode:c++ -*- - -// Copyright (c) 2003-2005 The Regents of The University of Michigan -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer; -// redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution; -// neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -output header {{ - /** - * Base class for general Alpha memory-format instructions. - */ - class Memory : public AlphaStaticInst - { - protected: - - /// Memory request flags. See mem_req_base.hh. - unsigned memAccessFlags; - /// Pointer to EAComp object. - const StaticInstPtr eaCompPtr; - /// Pointer to MemAcc object. - const StaticInstPtr memAccPtr; - - /// Constructor - Memory(const char *mnem, ExtMachInst _machInst, OpClass __opClass, - StaticInstPtr _eaCompPtr = nullStaticInstPtr, - StaticInstPtr _memAccPtr = nullStaticInstPtr) - : AlphaStaticInst(mnem, _machInst, __opClass), - memAccessFlags(0), eaCompPtr(_eaCompPtr), memAccPtr(_memAccPtr) - { - } - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - - public: - - const StaticInstPtr &eaCompInst() const { return eaCompPtr; } - const StaticInstPtr &memAccInst() const { return memAccPtr; } - }; - - /** - * Base class for memory-format instructions using a 32-bit - * displacement (i.e. most of them). - */ - class MemoryDisp32 : public Memory - { - protected: - /// Displacement for EA calculation (signed). - int32_t disp; - - /// Constructor. - MemoryDisp32(const char *mnem, ExtMachInst _machInst, OpClass __opClass, - StaticInstPtr _eaCompPtr = nullStaticInstPtr, - StaticInstPtr _memAccPtr = nullStaticInstPtr) - : Memory(mnem, _machInst, __opClass, _eaCompPtr, _memAccPtr), - disp(MEMDISP) - { - } - }; - - - /** - * Base class for a few miscellaneous memory-format insts - * that don't interpret the disp field: wh64, fetch, fetch_m, ecb. - * None of these instructions has a destination register either. - */ - class MemoryNoDisp : public Memory - { - protected: - /// Constructor - MemoryNoDisp(const char *mnem, ExtMachInst _machInst, OpClass __opClass, - StaticInstPtr _eaCompPtr = nullStaticInstPtr, - StaticInstPtr _memAccPtr = nullStaticInstPtr) - : Memory(mnem, _machInst, __opClass, _eaCompPtr, _memAccPtr) - { - } - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; -}}; - - -output decoder {{ - std::string - Memory::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { - return csprintf("%-10s %c%d,%d(r%d)", mnemonic, - flags[IsFloating] ? 'f' : 'r', RA, MEMDISP, RB); - } - - std::string - MemoryNoDisp::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { - return csprintf("%-10s (r%d)", mnemonic, RB); - } -}}; - -def format LoadAddress(code) {{ - iop = InstObjParams(name, Name, 'MemoryDisp32', CodeBlock(code)) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = BasicDecode.subst(iop) - exec_output = BasicExecute.subst(iop) -}}; - - -def template LoadStoreDeclare {{ - /** - * Static instruction class for "%(mnemonic)s". - */ - class %(class_name)s : public %(base_class)s - { - protected: - - /** - * "Fake" effective address computation class for "%(mnemonic)s". - */ - class EAComp : public %(base_class)s - { - public: - /// Constructor - EAComp(ExtMachInst machInst); - - %(BasicExecDeclare)s - }; - - /** - * "Fake" memory access instruction class for "%(mnemonic)s". - */ - class MemAcc : public %(base_class)s - { - public: - /// Constructor - MemAcc(ExtMachInst machInst); - - %(BasicExecDeclare)s - }; - - public: - - /// Constructor. - %(class_name)s(ExtMachInst machInst); - - %(BasicExecDeclare)s - - %(InitiateAccDeclare)s - - %(CompleteAccDeclare)s - }; -}}; - - -def template InitiateAccDeclare {{ - Fault initiateAcc(%(CPU_exec_context)s *, Trace::InstRecord *) const; -}}; - - -def template CompleteAccDeclare {{ - Fault completeAcc(uint8_t *, %(CPU_exec_context)s *, Trace::InstRecord *) const; -}}; - - -def template LoadStoreConstructor {{ - /** TODO: change op_class to AddrGenOp or something (requires - * creating new member of OpClass enum in op_class.hh, updating - * config files, etc.). */ - inline %(class_name)s::EAComp::EAComp(ExtMachInst machInst) - : %(base_class)s("%(mnemonic)s (EAComp)", machInst, IntAluOp) - { - %(ea_constructor)s; - } - - inline %(class_name)s::MemAcc::MemAcc(ExtMachInst machInst) - : %(base_class)s("%(mnemonic)s (MemAcc)", machInst, %(op_class)s) - { - %(memacc_constructor)s; - } - - inline %(class_name)s::%(class_name)s(ExtMachInst machInst) - : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, - new EAComp(machInst), new MemAcc(machInst)) - { - %(constructor)s; - } -}}; - - -def template EACompExecute {{ - Fault - %(class_name)s::EAComp::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Addr EA; - Fault fault = NoFault; - - %(fp_enable_check)s; - %(op_decl)s; - %(op_rd)s; - %(code)s; - - if (fault == NoFault) { - %(op_wb)s; - xc->setEA(EA); - } - - return fault; - } -}}; - -def template LoadMemAccExecute {{ - Fault - %(class_name)s::MemAcc::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Addr EA; - Fault fault = NoFault; - - %(fp_enable_check)s; - %(op_decl)s; - %(op_rd)s; - EA = xc->getEA(); - - if (fault == NoFault) { - fault = xc->read(EA, (uint%(mem_acc_size)d_t&)Mem, memAccessFlags); - %(code)s; - } - - if (fault == NoFault) { - %(op_wb)s; - } - - return fault; - } -}}; - - -def template LoadExecute {{ - Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Addr EA; - Fault fault = NoFault; - - %(fp_enable_check)s; - %(op_decl)s; - %(op_rd)s; - %(ea_code)s; - - if (fault == NoFault) { - fault = xc->read(EA, (uint%(mem_acc_size)d_t&)Mem, memAccessFlags); - %(memacc_code)s; - } - - if (fault == NoFault) { - %(op_wb)s; - } - - return fault; - } -}}; - - -def template LoadInitiateAcc {{ - Fault %(class_name)s::initiateAcc(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Addr EA; - Fault fault = NoFault; - - %(fp_enable_check)s; - %(op_src_decl)s; - %(op_rd)s; - %(ea_code)s; - - if (fault == NoFault) { - fault = xc->read(EA, (uint%(mem_acc_size)d_t &)Mem, memAccessFlags); - } - - return fault; - } -}}; - - -def template LoadCompleteAcc {{ - Fault %(class_name)s::completeAcc(uint8_t *data, - %(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Fault fault = NoFault; - - %(fp_enable_check)s; - %(op_src_decl)s; - %(op_dest_decl)s; - - memcpy(&Mem, data, sizeof(Mem)); - - if (fault == NoFault) { - %(memacc_code)s; - } - - if (fault == NoFault) { - %(op_wb)s; - } - - return fault; - } -}}; - - -def template StoreMemAccExecute {{ - Fault - %(class_name)s::MemAcc::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Addr EA; - Fault fault = NoFault; - uint64_t write_result = 0; - - %(fp_enable_check)s; - %(op_decl)s; - %(op_rd)s; - EA = xc->getEA(); - - if (fault == NoFault) { - %(code)s; - } - - if (fault == NoFault) { - fault = xc->write((uint%(mem_acc_size)d_t&)Mem, EA, - memAccessFlags, &write_result); - if (traceData) { traceData->setData(Mem); } - } - - if (fault == NoFault) { - %(postacc_code)s; - } - - if (fault == NoFault) { - %(op_wb)s; - } - - return fault; - } -}}; - - -def template StoreExecute {{ - Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Addr EA; - Fault fault = NoFault; - uint64_t write_result = 0; - - %(fp_enable_check)s; - %(op_decl)s; - %(op_rd)s; - %(ea_code)s; - - if (fault == NoFault) { - %(memacc_code)s; - } - - if (fault == NoFault) { - fault = xc->write((uint%(mem_acc_size)d_t&)Mem, EA, - memAccessFlags, &write_result); - if (traceData) { traceData->setData(Mem); } - } - - if (fault == NoFault) { - %(postacc_code)s; - } - - if (fault == NoFault) { - %(op_wb)s; - } - - return fault; - } -}}; - -def template StoreInitiateAcc {{ - Fault %(class_name)s::initiateAcc(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Addr EA; - Fault fault = NoFault; - uint64_t write_result = 0; - - %(fp_enable_check)s; - %(op_src_decl)s; - %(op_dest_decl)s; - %(op_rd)s; - %(ea_code)s; - - if (fault == NoFault) { - %(memacc_code)s; - } - - if (fault == NoFault) { - fault = xc->write((uint%(mem_acc_size)d_t&)Mem, EA, - memAccessFlags, &write_result); - if (traceData) { traceData->setData(Mem); } - } - - return fault; - } -}}; - - -def template StoreCompleteAcc {{ - Fault %(class_name)s::completeAcc(uint8_t *data, - %(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Fault fault = NoFault; - uint64_t write_result = 0; - - %(fp_enable_check)s; - %(op_dest_decl)s; - - memcpy(&write_result, data, sizeof(write_result)); - - if (fault == NoFault) { - %(postacc_code)s; - } - - if (fault == NoFault) { - %(op_wb)s; - } - - return fault; - } -}}; - - -def template MiscMemAccExecute {{ - Fault %(class_name)s::MemAcc::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Addr EA; - Fault fault = NoFault; - - %(fp_enable_check)s; - %(op_decl)s; - %(op_rd)s; - EA = xc->getEA(); - - if (fault == NoFault) { - %(code)s; - } - - return NoFault; - } -}}; - -def template MiscExecute {{ - Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Addr EA; - Fault fault = NoFault; - - %(fp_enable_check)s; - %(op_decl)s; - %(op_rd)s; - %(ea_code)s; - - if (fault == NoFault) { - %(memacc_code)s; - } - - return NoFault; - } -}}; - -def template MiscInitiateAcc {{ - Fault %(class_name)s::initiateAcc(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - panic("Misc instruction does not support split access method!"); - return NoFault; - } -}}; - - -def template MiscCompleteAcc {{ - Fault %(class_name)s::completeAcc(uint8_t *data, - %(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - panic("Misc instruction does not support split access method!"); - - return NoFault; - } -}}; - -// load instructions use Ra as dest, so check for -// Ra == 31 to detect nops -def template LoadNopCheckDecode {{ - { - AlphaStaticInst *i = new %(class_name)s(machInst); - if (RA == 31) { - i = makeNop(i); - } - return i; - } -}}; - - -// for some load instructions, Ra == 31 indicates a prefetch (not a nop) -def template LoadPrefetchCheckDecode {{ - { - if (RA != 31) { - return new %(class_name)s(machInst); - } - else { - return new %(class_name)sPrefetch(machInst); - } - } -}}; - - -let {{ -def LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, - postacc_code = '', base_class = 'MemoryDisp32', - decode_template = BasicDecode, exec_template_base = ''): - # Make sure flags are in lists (convert to lists if not). - mem_flags = makeList(mem_flags) - inst_flags = makeList(inst_flags) - - # add hook to get effective addresses into execution trace output. - ea_code += '\nif (traceData) { traceData->setAddr(EA); }\n' - - # generate code block objects - ea_cblk = CodeBlock(ea_code) - memacc_cblk = CodeBlock(memacc_code) - postacc_cblk = CodeBlock(postacc_code) - - # Some CPU models execute the memory operation as an atomic unit, - # while others want to separate them into an effective address - # computation and a memory access operation. As a result, we need - # to generate three StaticInst objects. Note that the latter two - # are nested inside the larger "atomic" one. - - # generate InstObjParams for EAComp object - ea_iop = InstObjParams(name, Name, base_class, ea_cblk, inst_flags) - - # generate InstObjParams for MemAcc object - memacc_iop = InstObjParams(name, Name, base_class, memacc_cblk, inst_flags) - # in the split execution model, the MemAcc portion is responsible - # for the post-access code. - memacc_iop.postacc_code = postacc_cblk.code - - # generate InstObjParams for InitiateAcc, CompleteAcc object - # The code used depends on the template being used - if (exec_template_base == 'Load'): - initiateacc_cblk = CodeBlock(ea_code + memacc_code) - completeacc_cblk = CodeBlock(memacc_code + postacc_code) - elif (exec_template_base == 'Store'): - initiateacc_cblk = CodeBlock(ea_code + memacc_code) - completeacc_cblk = CodeBlock(postacc_code) - else: - initiateacc_cblk = '' - completeacc_cblk = '' - - initiateacc_iop = InstObjParams(name, Name, base_class, initiateacc_cblk, - inst_flags) - - completeacc_iop = InstObjParams(name, Name, base_class, completeacc_cblk, - inst_flags) - - if (exec_template_base == 'Load'): - initiateacc_iop.ea_code = ea_cblk.code - initiateacc_iop.memacc_code = memacc_cblk.code - completeacc_iop.memacc_code = memacc_cblk.code - completeacc_iop.postacc_code = postacc_cblk.code - elif (exec_template_base == 'Store'): - initiateacc_iop.ea_code = ea_cblk.code - initiateacc_iop.memacc_code = memacc_cblk.code - completeacc_iop.postacc_code = postacc_cblk.code - - # generate InstObjParams for unified execution - cblk = CodeBlock(ea_code + memacc_code + postacc_code) - iop = InstObjParams(name, Name, base_class, cblk, inst_flags) - - iop.ea_constructor = ea_cblk.constructor - iop.ea_code = ea_cblk.code - iop.memacc_constructor = memacc_cblk.constructor - iop.memacc_code = memacc_cblk.code - iop.postacc_code = postacc_cblk.code - - if mem_flags: - s = '\n\tmemAccessFlags = ' + string.join(mem_flags, '|') + ';' - iop.constructor += s - memacc_iop.constructor += s - - # select templates - memAccExecTemplate = eval(exec_template_base + 'MemAccExecute') - fullExecTemplate = eval(exec_template_base + 'Execute') - initiateAccTemplate = eval(exec_template_base + 'InitiateAcc') - completeAccTemplate = eval(exec_template_base + 'CompleteAcc') - - # (header_output, decoder_output, decode_block, exec_output) - return (LoadStoreDeclare.subst(iop), LoadStoreConstructor.subst(iop), - decode_template.subst(iop), - EACompExecute.subst(ea_iop) - + memAccExecTemplate.subst(memacc_iop) - + fullExecTemplate.subst(iop) - + initiateAccTemplate.subst(initiateacc_iop) - + completeAccTemplate.subst(completeacc_iop)) -}}; - - -def format LoadOrNop(memacc_code, ea_code = {{ EA = Rb + disp; }}, - mem_flags = [], inst_flags = []) {{ - (header_output, decoder_output, decode_block, exec_output) = \ - LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, - decode_template = LoadNopCheckDecode, - exec_template_base = 'Load') -}}; - - -// Note that the flags passed in apply only to the prefetch version -def format LoadOrPrefetch(memacc_code, ea_code = {{ EA = Rb + disp; }}, - mem_flags = [], pf_flags = [], inst_flags = []) {{ - # declare the load instruction object and generate the decode block - (header_output, decoder_output, decode_block, exec_output) = \ - LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, - decode_template = LoadPrefetchCheckDecode, - exec_template_base = 'Load') - - # Declare the prefetch instruction object. - - # Make sure flag args are lists so we can mess with them. - mem_flags = makeList(mem_flags) - pf_flags = makeList(pf_flags) - inst_flags = makeList(inst_flags) - - pf_mem_flags = mem_flags + pf_flags + ['NO_FAULT'] - pf_inst_flags = inst_flags + ['IsMemRef', 'IsLoad', - 'IsDataPrefetch', 'MemReadOp'] - - (pf_header_output, pf_decoder_output, _, pf_exec_output) = \ - LoadStoreBase(name, Name + 'Prefetch', ea_code, - 'xc->prefetch(EA, memAccessFlags);', - pf_mem_flags, pf_inst_flags, exec_template_base = 'Misc') - - header_output += pf_header_output - decoder_output += pf_decoder_output - exec_output += pf_exec_output -}}; - - -def format Store(memacc_code, ea_code = {{ EA = Rb + disp; }}, - mem_flags = [], inst_flags = []) {{ - (header_output, decoder_output, decode_block, exec_output) = \ - LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, - exec_template_base = 'Store') -}}; - - -def format StoreCond(memacc_code, postacc_code, - ea_code = {{ EA = Rb + disp; }}, - mem_flags = [], inst_flags = []) {{ - (header_output, decoder_output, decode_block, exec_output) = \ - LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, - postacc_code, exec_template_base = 'Store') -}}; - - -// Use 'MemoryNoDisp' as base: for wh64, fetch, ecb -def format MiscPrefetch(ea_code, memacc_code, - mem_flags = [], inst_flags = []) {{ - (header_output, decoder_output, decode_block, exec_output) = \ - LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, - base_class = 'MemoryNoDisp', exec_template_base = 'Misc') -}}; - - diff --git a/arch/alpha/isa/opcdec.isa b/arch/alpha/isa/opcdec.isa deleted file mode 100644 index bb2f91e5c..000000000 --- a/arch/alpha/isa/opcdec.isa +++ /dev/null @@ -1,72 +0,0 @@ -// -*- mode:c++ -*- - -// Copyright (c) 2003-2005 The Regents of The University of Michigan -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer; -// redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution; -// neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -output header {{ - /** - * Static instruction class for instructions that cause an OPCDEC fault - * when executed. This is currently only for PAL mode instructions - * executed in non-PAL mode. - */ - class OpcdecFault : public AlphaStaticInst - { - public: - /// Constructor - OpcdecFault(ExtMachInst _machInst) - : AlphaStaticInst("opcdec fault", _machInst, No_OpClass) - { - } - - %(BasicExecDeclare)s - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; -}}; - -output decoder {{ - std::string - OpcdecFault::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { - return csprintf("%-10s (inst 0x%x, opcode 0x%x)", - " OPCDEC fault", machInst, OPCODE); - } -}}; - -output exec {{ - Fault - OpcdecFault::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - return new UnimplementedOpcodeFault; - } -}}; - -def format OpcdecFault() {{ - decode_block = 'return new OpcdecFault(machInst);\n' -}}; - diff --git a/arch/alpha/isa/pal.isa b/arch/alpha/isa/pal.isa deleted file mode 100644 index 63af56359..000000000 --- a/arch/alpha/isa/pal.isa +++ /dev/null @@ -1,273 +0,0 @@ -// -*- mode:c++ -*- - -// Copyright (c) 2003-2005 The Regents of The University of Michigan -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer; -// redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution; -// neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -output header {{ - /** - * Base class for emulated call_pal calls (used only in - * non-full-system mode). - */ - class EmulatedCallPal : public AlphaStaticInst - { - protected: - - /// Constructor. - EmulatedCallPal(const char *mnem, ExtMachInst _machInst, - OpClass __opClass) - : AlphaStaticInst(mnem, _machInst, __opClass) - { - } - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; -}}; - -output decoder {{ - std::string - EmulatedCallPal::generateDisassembly(Addr pc, - const SymbolTable *symtab) const - { -#ifdef SS_COMPATIBLE_DISASSEMBLY - return csprintf("%s %s", "call_pal", mnemonic); -#else - return csprintf("%-10s %s", "call_pal", mnemonic); -#endif - } -}}; - -def format EmulatedCallPal(code, *flags) {{ - iop = InstObjParams(name, Name, 'EmulatedCallPal', CodeBlock(code), flags) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = BasicDecode.subst(iop) - exec_output = BasicExecute.subst(iop) -}}; - -output header {{ - /** - * Base class for full-system-mode call_pal instructions. - * Probably could turn this into a leaf class and get rid of the - * parser template. - */ - class CallPalBase : public AlphaStaticInst - { - protected: - int palFunc; ///< Function code part of instruction - int palOffset; ///< Target PC, offset from IPR_PAL_BASE - bool palValid; ///< is the function code valid? - bool palPriv; ///< is this call privileged? - - /// Constructor. - CallPalBase(const char *mnem, ExtMachInst _machInst, - OpClass __opClass); - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; -}}; - -output decoder {{ - inline - CallPalBase::CallPalBase(const char *mnem, ExtMachInst _machInst, - OpClass __opClass) - : AlphaStaticInst(mnem, _machInst, __opClass), - palFunc(PALFUNC) - { - // From the 21164 HRM (paraphrased): - // Bit 7 of the function code (mask 0x80) indicates - // whether the call is privileged (bit 7 == 0) or - // unprivileged (bit 7 == 1). The privileged call table - // starts at 0x2000, the unprivielged call table starts at - // 0x3000. Bits 5-0 (mask 0x3f) are used to calculate the - // offset. - const int palPrivMask = 0x80; - const int palOffsetMask = 0x3f; - - // Pal call is invalid unless all other bits are 0 - palValid = ((machInst & ~(palPrivMask | palOffsetMask)) == 0); - palPriv = ((machInst & palPrivMask) == 0); - int shortPalFunc = (machInst & palOffsetMask); - // Add 1 to base to set pal-mode bit - palOffset = (palPriv ? 0x2001 : 0x3001) + (shortPalFunc << 6); - } - - std::string - CallPalBase::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { - return csprintf("%-10s %#x", "call_pal", palFunc); - } -}}; - -def format CallPal(code, *flags) {{ - iop = InstObjParams(name, Name, 'CallPalBase', CodeBlock(code), flags) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = BasicDecode.subst(iop) - exec_output = BasicExecute.subst(iop) -}}; - -//////////////////////////////////////////////////////////////////// -// -// hw_ld, hw_st -// - -output header {{ - /** - * Base class for hw_ld and hw_st. - */ - class HwLoadStore : public Memory - { - protected: - - /// Displacement for EA calculation (signed). - int16_t disp; - - /// Constructor - HwLoadStore(const char *mnem, ExtMachInst _machInst, OpClass __opClass, - StaticInstPtr _eaCompPtr = nullStaticInstPtr, - StaticInstPtr _memAccPtr = nullStaticInstPtr); - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; -}}; - - -output decoder {{ - inline - HwLoadStore::HwLoadStore(const char *mnem, ExtMachInst _machInst, - OpClass __opClass, - StaticInstPtr _eaCompPtr, - StaticInstPtr _memAccPtr) - : Memory(mnem, _machInst, __opClass, _eaCompPtr, _memAccPtr), - disp(HW_LDST_DISP) - { - memAccessFlags = 0; - if (HW_LDST_PHYS) memAccessFlags |= PHYSICAL; - if (HW_LDST_ALT) memAccessFlags |= ALTMODE; - if (HW_LDST_VPTE) memAccessFlags |= VPTE; - if (HW_LDST_LOCK) memAccessFlags |= LOCKED; - } - - std::string - HwLoadStore::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { -#ifdef SS_COMPATIBLE_DISASSEMBLY - return csprintf("%-10s r%d,%d(r%d)", mnemonic, RA, disp, RB); -#else - // HW_LDST_LOCK and HW_LDST_COND are the same bit. - const char *lock_str = - (HW_LDST_LOCK) ? (flags[IsLoad] ? ",LOCK" : ",COND") : ""; - - return csprintf("%-10s r%d,%d(r%d)%s%s%s%s%s", - mnemonic, RA, disp, RB, - HW_LDST_PHYS ? ",PHYS" : "", - HW_LDST_ALT ? ",ALT" : "", - HW_LDST_QUAD ? ",QUAD" : "", - HW_LDST_VPTE ? ",VPTE" : "", - lock_str); -#endif - } -}}; - -def format HwLoad(ea_code, memacc_code, class_ext, *flags) {{ - (header_output, decoder_output, decode_block, exec_output) = \ - LoadStoreBase(name, Name + class_ext, ea_code, memacc_code, - mem_flags = [], inst_flags = flags, - base_class = 'HwLoadStore', exec_template_base = 'Load') -}}; - - -def format HwStore(ea_code, memacc_code, class_ext, *flags) {{ - (header_output, decoder_output, decode_block, exec_output) = \ - LoadStoreBase(name, Name + class_ext, ea_code, memacc_code, - mem_flags = [], inst_flags = flags, - base_class = 'HwLoadStore', exec_template_base = 'Store') -}}; - - -def format HwStoreCond(ea_code, memacc_code, postacc_code, class_ext, - *flags) {{ - (header_output, decoder_output, decode_block, exec_output) = \ - LoadStoreBase(name, Name + class_ext, ea_code, memacc_code, - postacc_code, mem_flags = [], inst_flags = flags, - base_class = 'HwLoadStore') -}}; - - -output header {{ - /** - * Base class for hw_mfpr and hw_mtpr. - */ - class HwMoveIPR : public AlphaStaticInst - { - protected: - /// Index of internal processor register. - int ipr_index; - - /// Constructor - HwMoveIPR(const char *mnem, ExtMachInst _machInst, OpClass __opClass) - : AlphaStaticInst(mnem, _machInst, __opClass), - ipr_index(HW_IPR_IDX) - { - } - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; -}}; - -output decoder {{ - std::string - HwMoveIPR::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { - if (_numSrcRegs > 0) { - // must be mtpr - return csprintf("%-10s r%d,IPR(%#x)", - mnemonic, RA, ipr_index); - } - else { - // must be mfpr - return csprintf("%-10s IPR(%#x),r%d", - mnemonic, ipr_index, RA); - } - } -}}; - -def format HwMoveIPR(code, *flags) {{ - all_flags = ['IprAccessOp'] - all_flags += flags - iop = InstObjParams(name, Name, 'HwMoveIPR', CodeBlock(code), - all_flags) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = BasicDecode.subst(iop) - exec_output = BasicExecute.subst(iop) -}}; - - diff --git a/arch/alpha/isa/unimp.isa b/arch/alpha/isa/unimp.isa deleted file mode 100644 index 392522801..000000000 --- a/arch/alpha/isa/unimp.isa +++ /dev/null @@ -1,165 +0,0 @@ -// -*- mode:c++ -*- - -// Copyright (c) 2003-2005 The Regents of The University of Michigan -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer; -// redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution; -// neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -output header {{ - /** - * Static instruction class for unimplemented instructions that - * cause simulator termination. Note that these are recognized - * (legal) instructions that the simulator does not support; the - * 'Unknown' class is used for unrecognized/illegal instructions. - * This is a leaf class. - */ - class FailUnimplemented : public AlphaStaticInst - { - public: - /// Constructor - FailUnimplemented(const char *_mnemonic, ExtMachInst _machInst) - : AlphaStaticInst(_mnemonic, _machInst, No_OpClass) - { - // don't call execute() (which panics) if we're on a - // speculative path - flags[IsNonSpeculative] = true; - } - - %(BasicExecDeclare)s - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; - - /** - * Base class for unimplemented instructions that cause a warning - * to be printed (but do not terminate simulation). This - * implementation is a little screwy in that it will print a - * warning for each instance of a particular unimplemented machine - * instruction, not just for each unimplemented opcode. Should - * probably make the 'warned' flag a static member of the derived - * class. - */ - class WarnUnimplemented : public AlphaStaticInst - { - private: - /// Have we warned on this instruction yet? - mutable bool warned; - - public: - /// Constructor - WarnUnimplemented(const char *_mnemonic, ExtMachInst _machInst) - : AlphaStaticInst(_mnemonic, _machInst, No_OpClass), warned(false) - { - // don't call execute() (which panics) if we're on a - // speculative path - flags[IsNonSpeculative] = true; - } - - %(BasicExecDeclare)s - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; -}}; - -output decoder {{ - std::string - FailUnimplemented::generateDisassembly(Addr pc, - const SymbolTable *symtab) const - { - return csprintf("%-10s (unimplemented)", mnemonic); - } - - std::string - WarnUnimplemented::generateDisassembly(Addr pc, - const SymbolTable *symtab) const - { -#ifdef SS_COMPATIBLE_DISASSEMBLY - return csprintf("%-10s", mnemonic); -#else - return csprintf("%-10s (unimplemented)", mnemonic); -#endif - } -}}; - -output exec {{ - Fault - FailUnimplemented::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - panic("attempt to execute unimplemented instruction '%s' " - "(inst 0x%08x, opcode 0x%x)", mnemonic, machInst, OPCODE); - return new UnimplementedOpcodeFault; - } - - Fault - WarnUnimplemented::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - if (!warned) { - warn("instruction '%s' unimplemented\n", mnemonic); - warned = true; - } - - return NoFault; - } -}}; - - -def format FailUnimpl() {{ - iop = InstObjParams(name, 'FailUnimplemented') - decode_block = BasicDecodeWithMnemonic.subst(iop) -}}; - -def format WarnUnimpl() {{ - iop = InstObjParams(name, 'WarnUnimplemented') - decode_block = BasicDecodeWithMnemonic.subst(iop) -}}; - -output header {{ - /** - * Static instruction class for unknown (illegal) instructions. - * These cause simulator termination if they are executed in a - * non-speculative mode. This is a leaf class. - */ - class Unknown : public AlphaStaticInst - { - public: - /// Constructor - Unknown(ExtMachInst _machInst) - : AlphaStaticInst("unknown", _machInst, No_OpClass) - { - // don't call execute() (which panics) if we're on a - // speculative path - flags[IsNonSpeculative] = true; - } - - %(BasicExecDeclare)s - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; -}}; - diff --git a/arch/alpha/isa/unknown.isa b/arch/alpha/isa/unknown.isa deleted file mode 100644 index 47d166255..000000000 --- a/arch/alpha/isa/unknown.isa +++ /dev/null @@ -1,52 +0,0 @@ -// -*- mode:c++ -*- - -// Copyright (c) 2003-2005 The Regents of The University of Michigan -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer; -// redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution; -// neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -output decoder {{ - std::string - Unknown::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { - return csprintf("%-10s (inst 0x%x, opcode 0x%x)", - "unknown", machInst, OPCODE); - } -}}; - -output exec {{ - Fault - Unknown::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - panic("attempt to execute unknown instruction " - "(inst 0x%08x, opcode 0x%x)", machInst, OPCODE); - return new UnimplementedOpcodeFault; - } -}}; - -def format Unknown() {{ - decode_block = 'return new Unknown(machInst);\n' -}}; - diff --git a/arch/alpha/isa/util.isa b/arch/alpha/isa/util.isa deleted file mode 100644 index 9fbbf6636..000000000 --- a/arch/alpha/isa/util.isa +++ /dev/null @@ -1,112 +0,0 @@ -// -*- mode:c++ -*- - -// Copyright (c) 2003-2005 The Regents of The University of Michigan -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer; -// redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution; -// neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -output exec {{ - - /// Return opa + opb, summing carry into third arg. - inline uint64_t - addc(uint64_t opa, uint64_t opb, int &carry) - { - uint64_t res = opa + opb; - if (res < opa || res < opb) - ++carry; - return res; - } - - /// Multiply two 64-bit values (opa * opb), returning the 128-bit - /// product in res_hi and res_lo. - inline void - mul128(uint64_t opa, uint64_t opb, uint64_t &res_hi, uint64_t &res_lo) - { - // do a 64x64 --> 128 multiply using four 32x32 --> 64 multiplies - uint64_t opa_hi = opa<63:32>; - uint64_t opa_lo = opa<31:0>; - uint64_t opb_hi = opb<63:32>; - uint64_t opb_lo = opb<31:0>; - - res_lo = opa_lo * opb_lo; - - // The middle partial products logically belong in bit - // positions 95 to 32. Thus the lower 32 bits of each product - // sum into the upper 32 bits of the low result, while the - // upper 32 sum into the low 32 bits of the upper result. - uint64_t partial1 = opa_hi * opb_lo; - uint64_t partial2 = opa_lo * opb_hi; - - uint64_t partial1_lo = partial1<31:0> << 32; - uint64_t partial1_hi = partial1<63:32>; - uint64_t partial2_lo = partial2<31:0> << 32; - uint64_t partial2_hi = partial2<63:32>; - - // Add partial1_lo and partial2_lo to res_lo, keeping track - // of any carries out - int carry_out = 0; - res_lo = addc(partial1_lo, res_lo, carry_out); - res_lo = addc(partial2_lo, res_lo, carry_out); - - // Now calculate the high 64 bits... - res_hi = (opa_hi * opb_hi) + partial1_hi + partial2_hi + carry_out; - } - - /// Map 8-bit S-floating exponent to 11-bit T-floating exponent. - /// See Table 2-2 of Alpha AHB. - inline int - map_s(int old_exp) - { - int hibit = old_exp<7:>; - int lobits = old_exp<6:0>; - - if (hibit == 1) { - return (lobits == 0x7f) ? 0x7ff : (0x400 | lobits); - } - else { - return (lobits == 0) ? 0 : (0x380 | lobits); - } - } - - /// Convert a 32-bit S-floating value to the equivalent 64-bit - /// representation to be stored in an FP reg. - inline uint64_t - s_to_t(uint32_t s_val) - { - uint64_t tmp = s_val; - return (tmp<31:> << 63 // sign bit - | (uint64_t)map_s(tmp<30:23>) << 52 // exponent - | tmp<22:0> << 29); // fraction - } - - /// Convert a 64-bit T-floating value to the equivalent 32-bit - /// S-floating representation to be stored in memory. - inline int32_t - t_to_s(uint64_t t_val) - { - return (t_val<63:62> << 30 // sign bit & hi exp bit - | t_val<58:29>); // rest of exp & fraction - } -}}; - diff --git a/arch/alpha/isa_traits.hh b/arch/alpha/isa_traits.hh deleted file mode 100644 index 878193881..000000000 --- a/arch/alpha/isa_traits.hh +++ /dev/null @@ -1,384 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __ARCH_ALPHA_ISA_TRAITS_HH__ -#define __ARCH_ALPHA_ISA_TRAITS_HH__ - -namespace LittleEndianGuest {} -using namespace LittleEndianGuest; - -//#include "arch/alpha/faults.hh" -#include "base/misc.hh" -#include "config/full_system.hh" -#include "sim/host.hh" -#include "sim/faults.hh" - -class ExecContext; -class FastCPU; -class FullCPU; -class Checkpoint; - -#define TARGET_ALPHA - -class StaticInst; -class StaticInstPtr; - -namespace EV5 { -int DTB_ASN_ASN(uint64_t reg); -int ITB_ASN_ASN(uint64_t reg); -} - -#if !FULL_SYSTEM -class SyscallReturn { - public: - template <class T> - SyscallReturn(T v, bool s) - { - retval = (uint64_t)v; - success = s; - } - - template <class T> - SyscallReturn(T v) - { - success = (v >= 0); - retval = (uint64_t)v; - } - - ~SyscallReturn() {} - - SyscallReturn& operator=(const SyscallReturn& s) { - retval = s.retval; - success = s.success; - return *this; - } - - bool successful() { return success; } - uint64_t value() { return retval; } - - - private: - uint64_t retval; - bool success; -}; - -#endif - - - -namespace AlphaISA -{ - - typedef uint32_t MachInst; - typedef uint64_t ExtMachInst; - typedef uint8_t RegIndex; - - const int NumIntArchRegs = 32; - const int NumPALShadowRegs = 8; - const int NumFloatArchRegs = 32; - // @todo: Figure out what this number really should be. - const int NumMiscArchRegs = 32; - - // Static instruction parameters - const int MaxInstSrcRegs = 3; - const int MaxInstDestRegs = 2; - - // semantically meaningful register indices - const int ZeroReg = 31; // architecturally meaningful - // the rest of these depend on the ABI - const int StackPointerReg = 30; - const int GlobalPointerReg = 29; - const int ProcedureValueReg = 27; - const int ReturnAddressReg = 26; - const int ReturnValueReg = 0; - const int FramePointerReg = 15; - const int ArgumentReg0 = 16; - const int ArgumentReg1 = 17; - const int ArgumentReg2 = 18; - const int ArgumentReg3 = 19; - const int ArgumentReg4 = 20; - const int ArgumentReg5 = 21; - const int SyscallNumReg = ReturnValueReg; - const int SyscallPseudoReturnReg = ArgumentReg4; - const int SyscallSuccessReg = 19; - - - - const int LogVMPageSize = 13; // 8K bytes - const int VMPageSize = (1 << LogVMPageSize); - - const int BranchPredAddrShiftAmt = 2; // instructions are 4-byte aligned - - const int WordBytes = 4; - const int HalfwordBytes = 2; - const int ByteBytes = 1; - - - const int NumIntRegs = NumIntArchRegs + NumPALShadowRegs; - const int NumFloatRegs = NumFloatArchRegs; - const int NumMiscRegs = NumMiscArchRegs; - - // These enumerate all the registers for dependence tracking. - enum DependenceTags { - // 0..31 are the integer regs 0..31 - // 32..63 are the FP regs 0..31, i.e. use (reg + FP_Base_DepTag) - FP_Base_DepTag = 40, - Ctrl_Base_DepTag = 72, - Fpcr_DepTag = 72, // floating point control register - Uniq_DepTag = 73, - Lock_Flag_DepTag = 74, - Lock_Addr_DepTag = 75, - IPR_Base_DepTag = 76 - }; - - typedef uint64_t IntReg; - typedef IntReg IntRegFile[NumIntRegs]; - - // floating point register file entry type - typedef union { - uint64_t q; - double d; - } FloatReg; - - typedef union { - uint64_t q[NumFloatRegs]; // integer qword view - double d[NumFloatRegs]; // double-precision floating point view - } FloatRegFile; - -extern const Addr PageShift; -extern const Addr PageBytes; -extern const Addr PageMask; -extern const Addr PageOffset; - -// redirected register map, really only used for the full system case. -extern const int reg_redir[NumIntRegs]; - -#if FULL_SYSTEM - - typedef uint64_t InternalProcReg; - -#include "arch/alpha/isa_fullsys_traits.hh" - -#else - const int NumInternalProcRegs = 0; -#endif - - // control register file contents - typedef uint64_t MiscReg; - class MiscRegFile { - protected: - uint64_t fpcr; // floating point condition codes - uint64_t uniq; // process-unique register - bool lock_flag; // lock flag for LL/SC - Addr lock_addr; // lock address for LL/SC - - public: - MiscReg readReg(int misc_reg); - - //These functions should be removed once the simplescalar cpu model - //has been replaced. - int getInstAsid(); - int getDataAsid(); - - MiscReg readRegWithEffect(int misc_reg, Fault &fault, ExecContext *xc); - - Fault setReg(int misc_reg, const MiscReg &val); - - Fault setRegWithEffect(int misc_reg, const MiscReg &val, - ExecContext *xc); - - void copyMiscRegs(ExecContext *xc); - -#if FULL_SYSTEM - protected: - InternalProcReg ipr[NumInternalProcRegs]; // Internal processor regs - - private: - MiscReg readIpr(int idx, Fault &fault, ExecContext *xc); - - Fault setIpr(int idx, uint64_t val, ExecContext *xc); - - void copyIprs(ExecContext *xc); -#endif - friend class RegFile; - }; - - const int TotalNumRegs = NumIntRegs + NumFloatRegs + - NumMiscRegs + NumInternalProcRegs; - - const int TotalDataRegs = NumIntRegs + NumFloatRegs; - - typedef union { - IntReg intreg; - FloatReg fpreg; - MiscReg ctrlreg; - } AnyReg; - - struct RegFile { - IntRegFile intRegFile; // (signed) integer register file - FloatRegFile floatRegFile; // floating point register file - MiscRegFile miscRegs; // control register file - Addr pc; // program counter - Addr npc; // next-cycle program counter - Addr nnpc; - -#if FULL_SYSTEM - int intrflag; // interrupt flag - inline int instAsid() - { return EV5::ITB_ASN_ASN(miscRegs.ipr[IPR_ITB_ASN]); } - inline int dataAsid() - { return EV5::DTB_ASN_ASN(miscRegs.ipr[IPR_DTB_ASN]); } -#endif // FULL_SYSTEM - - void serialize(std::ostream &os); - void unserialize(Checkpoint *cp, const std::string §ion); - }; - - static inline ExtMachInst makeExtMI(MachInst inst, const uint64_t &pc); - - StaticInstPtr decodeInst(ExtMachInst); - - // return a no-op instruction... used for instruction fetch faults - extern const ExtMachInst NoopMachInst; - - enum annotes { - ANNOTE_NONE = 0, - // An impossible number for instruction annotations - ITOUCH_ANNOTE = 0xffffffff, - }; - - static inline bool isCallerSaveIntegerRegister(unsigned int reg) { - panic("register classification not implemented"); - return (reg >= 1 && reg <= 8 || reg >= 22 && reg <= 25 || reg == 27); - } - - static inline bool isCalleeSaveIntegerRegister(unsigned int reg) { - panic("register classification not implemented"); - return (reg >= 9 && reg <= 15); - } - - static inline bool isCallerSaveFloatRegister(unsigned int reg) { - panic("register classification not implemented"); - return false; - } - - static inline bool isCalleeSaveFloatRegister(unsigned int reg) { - panic("register classification not implemented"); - return false; - } - - static inline Addr alignAddress(const Addr &addr, - unsigned int nbytes) { - return (addr & ~(nbytes - 1)); - } - - // Instruction address compression hooks - static inline Addr realPCToFetchPC(const Addr &addr) { - return addr; - } - - static inline Addr fetchPCToRealPC(const Addr &addr) { - return addr; - } - - // the size of "fetched" instructions (not necessarily the size - // of real instructions for PISA) - static inline size_t fetchInstSize() { - return sizeof(MachInst); - } - - static inline MachInst makeRegisterCopy(int dest, int src) { - panic("makeRegisterCopy not implemented"); - return 0; - } - - // Machine operations - - void saveMachineReg(AnyReg &savereg, const RegFile ®_file, - int regnum); - - void restoreMachineReg(RegFile ®s, const AnyReg ®, - int regnum); - -#if 0 - static void serializeSpecialRegs(const Serializable::Proxy &proxy, - const RegFile ®s); - - static void unserializeSpecialRegs(const IniFile *db, - const std::string &category, - ConfigNode *node, - RegFile ®s); -#endif - - /** - * Function to insure ISA semantics about 0 registers. - * @param xc The execution context. - */ - template <class XC> - void zeroRegisters(XC *xc); - - const Addr MaxAddr = (Addr)-1; - -#if !FULL_SYSTEM - static inline void setSyscallReturn(SyscallReturn return_value, RegFile *regs) - { - // check for error condition. Alpha syscall convention is to - // indicate success/failure in reg a3 (r19) and put the - // return value itself in the standard return value reg (v0). - if (return_value.successful()) { - // no error - regs->intRegFile[SyscallSuccessReg] = 0; - regs->intRegFile[ReturnValueReg] = return_value.value(); - } else { - // got an error, return details - regs->intRegFile[SyscallSuccessReg] = (IntReg) -1; - regs->intRegFile[ReturnValueReg] = -return_value.value(); - } - } -#endif -}; - -static inline AlphaISA::ExtMachInst -AlphaISA::makeExtMI(AlphaISA::MachInst inst, const uint64_t &pc) { -#if FULL_SYSTEM - AlphaISA::ExtMachInst ext_inst = inst; - if (pc && 0x1) - return ext_inst|=(static_cast<AlphaISA::ExtMachInst>(pc & 0x1) << 32); - else - return ext_inst; -#else - return AlphaISA::ExtMachInst(inst); -#endif -} - -#if FULL_SYSTEM - -#include "arch/alpha/ev5.hh" -#endif - -#endif // __ARCH_ALPHA_ISA_TRAITS_HH__ diff --git a/arch/alpha/linux/process.cc b/arch/alpha/linux/process.cc deleted file mode 100644 index 1c911bc50..000000000 --- a/arch/alpha/linux/process.cc +++ /dev/null @@ -1,589 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "arch/alpha/linux/process.hh" -#include "arch/alpha/isa_traits.hh" - -#include "base/trace.hh" -#include "cpu/exec_context.hh" -#include "kern/linux/linux.hh" -#include "mem/functional/functional.hh" - -#include "sim/process.hh" -#include "sim/syscall_emul.hh" - -using namespace std; -using namespace AlphaISA; - - - -/// Target uname() handler. -static SyscallReturn -unameFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - TypedBufferArg<Linux::utsname> name(xc->getSyscallArg(0)); - - strcpy(name->sysname, "Linux"); - strcpy(name->nodename, "m5.eecs.umich.edu"); - strcpy(name->release, "2.4.20"); - strcpy(name->version, "#1 Mon Aug 18 11:32:15 EDT 2003"); - strcpy(name->machine, "alpha"); - - name.copyOut(xc->getMemPtr()); - return 0; -} - -/// Target osf_getsysyinfo() handler. Even though this call is -/// borrowed from Tru64, the subcases that get used appear to be -/// different in practice from those used by Tru64 processes. -static SyscallReturn -osf_getsysinfoFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - unsigned op = xc->getSyscallArg(0); - // unsigned nbytes = xc->getSyscallArg(2); - - switch (op) { - - case 45: { // GSI_IEEE_FP_CONTROL - TypedBufferArg<uint64_t> fpcr(xc->getSyscallArg(1)); - // I don't think this exactly matches the HW FPCR - *fpcr = 0; - fpcr.copyOut(xc->getMemPtr()); - return 0; - } - - default: - cerr << "osf_getsysinfo: unknown op " << op << endl; - abort(); - break; - } - - return 1; -} - -/// Target osf_setsysinfo() handler. -static SyscallReturn -osf_setsysinfoFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - unsigned op = xc->getSyscallArg(0); - // unsigned nbytes = xc->getSyscallArg(2); - - switch (op) { - - case 14: { // SSI_IEEE_FP_CONTROL - TypedBufferArg<uint64_t> fpcr(xc->getSyscallArg(1)); - // I don't think this exactly matches the HW FPCR - fpcr.copyIn(xc->getMemPtr()); - DPRINTFR(SyscallVerbose, "osf_setsysinfo(SSI_IEEE_FP_CONTROL): " - " setting FPCR to 0x%x\n", gtoh(*(uint64_t*)fpcr)); - return 0; - } - - default: - cerr << "osf_setsysinfo: unknown op " << op << endl; - abort(); - break; - } - - return 1; -} - - -SyscallDesc AlphaLinuxProcess::syscallDescs[] = { - /* 0 */ SyscallDesc("osf_syscall", unimplementedFunc), - /* 1 */ SyscallDesc("exit", exitFunc), - /* 2 */ SyscallDesc("fork", unimplementedFunc), - /* 3 */ SyscallDesc("read", readFunc), - /* 4 */ SyscallDesc("write", writeFunc), - /* 5 */ SyscallDesc("osf_old_open", unimplementedFunc), - /* 6 */ SyscallDesc("close", closeFunc), - /* 7 */ SyscallDesc("osf_wait4", unimplementedFunc), - /* 8 */ SyscallDesc("osf_old_creat", unimplementedFunc), - /* 9 */ SyscallDesc("link", unimplementedFunc), - /* 10 */ SyscallDesc("unlink", unlinkFunc), - /* 11 */ SyscallDesc("osf_execve", unimplementedFunc), - /* 12 */ SyscallDesc("chdir", unimplementedFunc), - /* 13 */ SyscallDesc("fchdir", unimplementedFunc), - /* 14 */ SyscallDesc("mknod", unimplementedFunc), - /* 15 */ SyscallDesc("chmod", chmodFunc<Linux>), - /* 16 */ SyscallDesc("chown", chownFunc), - /* 17 */ SyscallDesc("brk", obreakFunc), - /* 18 */ SyscallDesc("osf_getfsstat", unimplementedFunc), - /* 19 */ SyscallDesc("lseek", lseekFunc), - /* 20 */ SyscallDesc("getxpid", getpidPseudoFunc), - /* 21 */ SyscallDesc("osf_mount", unimplementedFunc), - /* 22 */ SyscallDesc("umount", unimplementedFunc), - /* 23 */ SyscallDesc("setuid", setuidFunc), - /* 24 */ SyscallDesc("getxuid", getuidPseudoFunc), - /* 25 */ SyscallDesc("exec_with_loader", unimplementedFunc), - /* 26 */ SyscallDesc("osf_ptrace", unimplementedFunc), - /* 27 */ SyscallDesc("osf_nrecvmsg", unimplementedFunc), - /* 28 */ SyscallDesc("osf_nsendmsg", unimplementedFunc), - /* 29 */ SyscallDesc("osf_nrecvfrom", unimplementedFunc), - /* 30 */ SyscallDesc("osf_naccept", unimplementedFunc), - /* 31 */ SyscallDesc("osf_ngetpeername", unimplementedFunc), - /* 32 */ SyscallDesc("osf_ngetsockname", unimplementedFunc), - /* 33 */ SyscallDesc("access", unimplementedFunc), - /* 34 */ SyscallDesc("osf_chflags", unimplementedFunc), - /* 35 */ SyscallDesc("osf_fchflags", unimplementedFunc), - /* 36 */ SyscallDesc("sync", unimplementedFunc), - /* 37 */ SyscallDesc("kill", unimplementedFunc), - /* 38 */ SyscallDesc("osf_old_stat", unimplementedFunc), - /* 39 */ SyscallDesc("setpgid", unimplementedFunc), - /* 40 */ SyscallDesc("osf_old_lstat", unimplementedFunc), - /* 41 */ SyscallDesc("dup", unimplementedFunc), - /* 42 */ SyscallDesc("pipe", pipePseudoFunc), - /* 43 */ SyscallDesc("osf_set_program_attributes", unimplementedFunc), - /* 44 */ SyscallDesc("osf_profil", unimplementedFunc), - /* 45 */ SyscallDesc("open", openFunc<Linux>), - /* 46 */ SyscallDesc("osf_old_sigaction", unimplementedFunc), - /* 47 */ SyscallDesc("getxgid", getgidPseudoFunc), - /* 48 */ SyscallDesc("osf_sigprocmask", ignoreFunc), - /* 49 */ SyscallDesc("osf_getlogin", unimplementedFunc), - /* 50 */ SyscallDesc("osf_setlogin", unimplementedFunc), - /* 51 */ SyscallDesc("acct", unimplementedFunc), - /* 52 */ SyscallDesc("sigpending", unimplementedFunc), - /* 53 */ SyscallDesc("osf_classcntl", unimplementedFunc), - /* 54 */ SyscallDesc("ioctl", ioctlFunc<Linux>), - /* 55 */ SyscallDesc("osf_reboot", unimplementedFunc), - /* 56 */ SyscallDesc("osf_revoke", unimplementedFunc), - /* 57 */ SyscallDesc("symlink", unimplementedFunc), - /* 58 */ SyscallDesc("readlink", unimplementedFunc), - /* 59 */ SyscallDesc("execve", unimplementedFunc), - /* 60 */ SyscallDesc("umask", unimplementedFunc), - /* 61 */ SyscallDesc("chroot", unimplementedFunc), - /* 62 */ SyscallDesc("osf_old_fstat", unimplementedFunc), - /* 63 */ SyscallDesc("getpgrp", unimplementedFunc), - /* 64 */ SyscallDesc("getpagesize", getpagesizeFunc), - /* 65 */ SyscallDesc("osf_mremap", unimplementedFunc), - /* 66 */ SyscallDesc("vfork", unimplementedFunc), - /* 67 */ SyscallDesc("stat", statFunc<Linux>), - /* 68 */ SyscallDesc("lstat", lstatFunc<Linux>), - /* 69 */ SyscallDesc("osf_sbrk", unimplementedFunc), - /* 70 */ SyscallDesc("osf_sstk", unimplementedFunc), - /* 71 */ SyscallDesc("mmap", mmapFunc<Linux>), - /* 72 */ SyscallDesc("osf_old_vadvise", unimplementedFunc), - /* 73 */ SyscallDesc("munmap", munmapFunc), - /* 74 */ SyscallDesc("mprotect", ignoreFunc), - /* 75 */ SyscallDesc("madvise", unimplementedFunc), - /* 76 */ SyscallDesc("vhangup", unimplementedFunc), - /* 77 */ SyscallDesc("osf_kmodcall", unimplementedFunc), - /* 78 */ SyscallDesc("osf_mincore", unimplementedFunc), - /* 79 */ SyscallDesc("getgroups", unimplementedFunc), - /* 80 */ SyscallDesc("setgroups", unimplementedFunc), - /* 81 */ SyscallDesc("osf_old_getpgrp", unimplementedFunc), - /* 82 */ SyscallDesc("setpgrp", unimplementedFunc), - /* 83 */ SyscallDesc("osf_setitimer", unimplementedFunc), - /* 84 */ SyscallDesc("osf_old_wait", unimplementedFunc), - /* 85 */ SyscallDesc("osf_table", unimplementedFunc), - /* 86 */ SyscallDesc("osf_getitimer", unimplementedFunc), - /* 87 */ SyscallDesc("gethostname", gethostnameFunc), - /* 88 */ SyscallDesc("sethostname", unimplementedFunc), - /* 89 */ SyscallDesc("getdtablesize", unimplementedFunc), - /* 90 */ SyscallDesc("dup2", unimplementedFunc), - /* 91 */ SyscallDesc("fstat", fstatFunc<Linux>), - /* 92 */ SyscallDesc("fcntl", fcntlFunc), - /* 93 */ SyscallDesc("osf_select", unimplementedFunc), - /* 94 */ SyscallDesc("poll", unimplementedFunc), - /* 95 */ SyscallDesc("fsync", unimplementedFunc), - /* 96 */ SyscallDesc("setpriority", unimplementedFunc), - /* 97 */ SyscallDesc("socket", unimplementedFunc), - /* 98 */ SyscallDesc("connect", unimplementedFunc), - /* 99 */ SyscallDesc("accept", unimplementedFunc), - /* 100 */ SyscallDesc("getpriority", unimplementedFunc), - /* 101 */ SyscallDesc("send", unimplementedFunc), - /* 102 */ SyscallDesc("recv", unimplementedFunc), - /* 103 */ SyscallDesc("sigreturn", unimplementedFunc), - /* 104 */ SyscallDesc("bind", unimplementedFunc), - /* 105 */ SyscallDesc("setsockopt", unimplementedFunc), - /* 106 */ SyscallDesc("listen", unimplementedFunc), - /* 107 */ SyscallDesc("osf_plock", unimplementedFunc), - /* 108 */ SyscallDesc("osf_old_sigvec", unimplementedFunc), - /* 109 */ SyscallDesc("osf_old_sigblock", unimplementedFunc), - /* 110 */ SyscallDesc("osf_old_sigsetmask", unimplementedFunc), - /* 111 */ SyscallDesc("sigsuspend", unimplementedFunc), - /* 112 */ SyscallDesc("osf_sigstack", ignoreFunc), - /* 113 */ SyscallDesc("recvmsg", unimplementedFunc), - /* 114 */ SyscallDesc("sendmsg", unimplementedFunc), - /* 115 */ SyscallDesc("osf_old_vtrace", unimplementedFunc), - /* 116 */ SyscallDesc("osf_gettimeofday", unimplementedFunc), - /* 117 */ SyscallDesc("osf_getrusage", unimplementedFunc), - /* 118 */ SyscallDesc("getsockopt", unimplementedFunc), - /* 119 */ SyscallDesc("numa_syscalls", unimplementedFunc), - /* 120 */ SyscallDesc("readv", unimplementedFunc), - /* 121 */ SyscallDesc("writev", writevFunc<Linux>), - /* 122 */ SyscallDesc("osf_settimeofday", unimplementedFunc), - /* 123 */ SyscallDesc("fchown", fchownFunc), - /* 124 */ SyscallDesc("fchmod", fchmodFunc<Linux>), - /* 125 */ SyscallDesc("recvfrom", unimplementedFunc), - /* 126 */ SyscallDesc("setreuid", unimplementedFunc), - /* 127 */ SyscallDesc("setregid", unimplementedFunc), - /* 128 */ SyscallDesc("rename", renameFunc), - /* 129 */ SyscallDesc("truncate", unimplementedFunc), - /* 130 */ SyscallDesc("ftruncate", unimplementedFunc), - /* 131 */ SyscallDesc("flock", unimplementedFunc), - /* 132 */ SyscallDesc("setgid", unimplementedFunc), - /* 133 */ SyscallDesc("sendto", unimplementedFunc), - /* 134 */ SyscallDesc("shutdown", unimplementedFunc), - /* 135 */ SyscallDesc("socketpair", unimplementedFunc), - /* 136 */ SyscallDesc("mkdir", unimplementedFunc), - /* 137 */ SyscallDesc("rmdir", unimplementedFunc), - /* 138 */ SyscallDesc("osf_utimes", unimplementedFunc), - /* 139 */ SyscallDesc("osf_old_sigreturn", unimplementedFunc), - /* 140 */ SyscallDesc("osf_adjtime", unimplementedFunc), - /* 141 */ SyscallDesc("getpeername", unimplementedFunc), - /* 142 */ SyscallDesc("osf_gethostid", unimplementedFunc), - /* 143 */ SyscallDesc("osf_sethostid", unimplementedFunc), - /* 144 */ SyscallDesc("getrlimit", getrlimitFunc<Linux>), - /* 145 */ SyscallDesc("setrlimit", ignoreFunc), - /* 146 */ SyscallDesc("osf_old_killpg", unimplementedFunc), - /* 147 */ SyscallDesc("setsid", unimplementedFunc), - /* 148 */ SyscallDesc("quotactl", unimplementedFunc), - /* 149 */ SyscallDesc("osf_oldquota", unimplementedFunc), - /* 150 */ SyscallDesc("getsockname", unimplementedFunc), - /* 151 */ SyscallDesc("osf_pread", unimplementedFunc), - /* 152 */ SyscallDesc("osf_pwrite", unimplementedFunc), - /* 153 */ SyscallDesc("osf_pid_block", unimplementedFunc), - /* 154 */ SyscallDesc("osf_pid_unblock", unimplementedFunc), - /* 155 */ SyscallDesc("osf_signal_urti", unimplementedFunc), - /* 156 */ SyscallDesc("sigaction", ignoreFunc), - /* 157 */ SyscallDesc("osf_sigwaitprim", unimplementedFunc), - /* 158 */ SyscallDesc("osf_nfssvc", unimplementedFunc), - /* 159 */ SyscallDesc("osf_getdirentries", unimplementedFunc), - /* 160 */ SyscallDesc("osf_statfs", unimplementedFunc), - /* 161 */ SyscallDesc("osf_fstatfs", unimplementedFunc), - /* 162 */ SyscallDesc("unknown #162", unimplementedFunc), - /* 163 */ SyscallDesc("osf_async_daemon", unimplementedFunc), - /* 164 */ SyscallDesc("osf_getfh", unimplementedFunc), - /* 165 */ SyscallDesc("osf_getdomainname", unimplementedFunc), - /* 166 */ SyscallDesc("setdomainname", unimplementedFunc), - /* 167 */ SyscallDesc("unknown #167", unimplementedFunc), - /* 168 */ SyscallDesc("unknown #168", unimplementedFunc), - /* 169 */ SyscallDesc("osf_exportfs", unimplementedFunc), - /* 170 */ SyscallDesc("unknown #170", unimplementedFunc), - /* 171 */ SyscallDesc("unknown #171", unimplementedFunc), - /* 172 */ SyscallDesc("unknown #172", unimplementedFunc), - /* 173 */ SyscallDesc("unknown #173", unimplementedFunc), - /* 174 */ SyscallDesc("unknown #174", unimplementedFunc), - /* 175 */ SyscallDesc("unknown #175", unimplementedFunc), - /* 176 */ SyscallDesc("unknown #176", unimplementedFunc), - /* 177 */ SyscallDesc("unknown #177", unimplementedFunc), - /* 178 */ SyscallDesc("unknown #178", unimplementedFunc), - /* 179 */ SyscallDesc("unknown #179", unimplementedFunc), - /* 180 */ SyscallDesc("unknown #180", unimplementedFunc), - /* 181 */ SyscallDesc("osf_alt_plock", unimplementedFunc), - /* 182 */ SyscallDesc("unknown #182", unimplementedFunc), - /* 183 */ SyscallDesc("unknown #183", unimplementedFunc), - /* 184 */ SyscallDesc("osf_getmnt", unimplementedFunc), - /* 185 */ SyscallDesc("unknown #185", unimplementedFunc), - /* 186 */ SyscallDesc("unknown #186", unimplementedFunc), - /* 187 */ SyscallDesc("osf_alt_sigpending", unimplementedFunc), - /* 188 */ SyscallDesc("osf_alt_setsid", unimplementedFunc), - /* 189 */ SyscallDesc("unknown #189", unimplementedFunc), - /* 190 */ SyscallDesc("unknown #190", unimplementedFunc), - /* 191 */ SyscallDesc("unknown #191", unimplementedFunc), - /* 192 */ SyscallDesc("unknown #192", unimplementedFunc), - /* 193 */ SyscallDesc("unknown #193", unimplementedFunc), - /* 194 */ SyscallDesc("unknown #194", unimplementedFunc), - /* 195 */ SyscallDesc("unknown #195", unimplementedFunc), - /* 196 */ SyscallDesc("unknown #196", unimplementedFunc), - /* 197 */ SyscallDesc("unknown #197", unimplementedFunc), - /* 198 */ SyscallDesc("unknown #198", unimplementedFunc), - /* 199 */ SyscallDesc("osf_swapon", unimplementedFunc), - /* 200 */ SyscallDesc("msgctl", unimplementedFunc), - /* 201 */ SyscallDesc("msgget", unimplementedFunc), - /* 202 */ SyscallDesc("msgrcv", unimplementedFunc), - /* 203 */ SyscallDesc("msgsnd", unimplementedFunc), - /* 204 */ SyscallDesc("semctl", unimplementedFunc), - /* 205 */ SyscallDesc("semget", unimplementedFunc), - /* 206 */ SyscallDesc("semop", unimplementedFunc), - /* 207 */ SyscallDesc("osf_utsname", unimplementedFunc), - /* 208 */ SyscallDesc("lchown", unimplementedFunc), - /* 209 */ SyscallDesc("osf_shmat", unimplementedFunc), - /* 210 */ SyscallDesc("shmctl", unimplementedFunc), - /* 211 */ SyscallDesc("shmdt", unimplementedFunc), - /* 212 */ SyscallDesc("shmget", unimplementedFunc), - /* 213 */ SyscallDesc("osf_mvalid", unimplementedFunc), - /* 214 */ SyscallDesc("osf_getaddressconf", unimplementedFunc), - /* 215 */ SyscallDesc("osf_msleep", unimplementedFunc), - /* 216 */ SyscallDesc("osf_mwakeup", unimplementedFunc), - /* 217 */ SyscallDesc("msync", unimplementedFunc), - /* 218 */ SyscallDesc("osf_signal", unimplementedFunc), - /* 219 */ SyscallDesc("osf_utc_gettime", unimplementedFunc), - /* 220 */ SyscallDesc("osf_utc_adjtime", unimplementedFunc), - /* 221 */ SyscallDesc("unknown #221", unimplementedFunc), - /* 222 */ SyscallDesc("osf_security", unimplementedFunc), - /* 223 */ SyscallDesc("osf_kloadcall", unimplementedFunc), - /* 224 */ SyscallDesc("unknown #224", unimplementedFunc), - /* 225 */ SyscallDesc("unknown #225", unimplementedFunc), - /* 226 */ SyscallDesc("unknown #226", unimplementedFunc), - /* 227 */ SyscallDesc("unknown #227", unimplementedFunc), - /* 228 */ SyscallDesc("unknown #228", unimplementedFunc), - /* 229 */ SyscallDesc("unknown #229", unimplementedFunc), - /* 230 */ SyscallDesc("unknown #230", unimplementedFunc), - /* 231 */ SyscallDesc("unknown #231", unimplementedFunc), - /* 232 */ SyscallDesc("unknown #232", unimplementedFunc), - /* 233 */ SyscallDesc("getpgid", unimplementedFunc), - /* 234 */ SyscallDesc("getsid", unimplementedFunc), - /* 235 */ SyscallDesc("sigaltstack", ignoreFunc), - /* 236 */ SyscallDesc("osf_waitid", unimplementedFunc), - /* 237 */ SyscallDesc("osf_priocntlset", unimplementedFunc), - /* 238 */ SyscallDesc("osf_sigsendset", unimplementedFunc), - /* 239 */ SyscallDesc("osf_set_speculative", unimplementedFunc), - /* 240 */ SyscallDesc("osf_msfs_syscall", unimplementedFunc), - /* 241 */ SyscallDesc("osf_sysinfo", unimplementedFunc), - /* 242 */ SyscallDesc("osf_uadmin", unimplementedFunc), - /* 243 */ SyscallDesc("osf_fuser", unimplementedFunc), - /* 244 */ SyscallDesc("osf_proplist_syscall", unimplementedFunc), - /* 245 */ SyscallDesc("osf_ntp_adjtime", unimplementedFunc), - /* 246 */ SyscallDesc("osf_ntp_gettime", unimplementedFunc), - /* 247 */ SyscallDesc("osf_pathconf", unimplementedFunc), - /* 248 */ SyscallDesc("osf_fpathconf", unimplementedFunc), - /* 249 */ SyscallDesc("unknown #249", unimplementedFunc), - /* 250 */ SyscallDesc("osf_uswitch", unimplementedFunc), - /* 251 */ SyscallDesc("osf_usleep_thread", unimplementedFunc), - /* 252 */ SyscallDesc("osf_audcntl", unimplementedFunc), - /* 253 */ SyscallDesc("osf_audgen", unimplementedFunc), - /* 254 */ SyscallDesc("sysfs", unimplementedFunc), - /* 255 */ SyscallDesc("osf_subsys_info", unimplementedFunc), - /* 256 */ SyscallDesc("osf_getsysinfo", osf_getsysinfoFunc), - /* 257 */ SyscallDesc("osf_setsysinfo", osf_setsysinfoFunc), - /* 258 */ SyscallDesc("osf_afs_syscall", unimplementedFunc), - /* 259 */ SyscallDesc("osf_swapctl", unimplementedFunc), - /* 260 */ SyscallDesc("osf_memcntl", unimplementedFunc), - /* 261 */ SyscallDesc("osf_fdatasync", unimplementedFunc), - /* 262 */ SyscallDesc("unknown #262", unimplementedFunc), - /* 263 */ SyscallDesc("unknown #263", unimplementedFunc), - /* 264 */ SyscallDesc("unknown #264", unimplementedFunc), - /* 265 */ SyscallDesc("unknown #265", unimplementedFunc), - /* 266 */ SyscallDesc("unknown #266", unimplementedFunc), - /* 267 */ SyscallDesc("unknown #267", unimplementedFunc), - /* 268 */ SyscallDesc("unknown #268", unimplementedFunc), - /* 269 */ SyscallDesc("unknown #269", unimplementedFunc), - /* 270 */ SyscallDesc("unknown #270", unimplementedFunc), - /* 271 */ SyscallDesc("unknown #271", unimplementedFunc), - /* 272 */ SyscallDesc("unknown #272", unimplementedFunc), - /* 273 */ SyscallDesc("unknown #273", unimplementedFunc), - /* 274 */ SyscallDesc("unknown #274", unimplementedFunc), - /* 275 */ SyscallDesc("unknown #275", unimplementedFunc), - /* 276 */ SyscallDesc("unknown #276", unimplementedFunc), - /* 277 */ SyscallDesc("unknown #277", unimplementedFunc), - /* 278 */ SyscallDesc("unknown #278", unimplementedFunc), - /* 279 */ SyscallDesc("unknown #279", unimplementedFunc), - /* 280 */ SyscallDesc("unknown #280", unimplementedFunc), - /* 281 */ SyscallDesc("unknown #281", unimplementedFunc), - /* 282 */ SyscallDesc("unknown #282", unimplementedFunc), - /* 283 */ SyscallDesc("unknown #283", unimplementedFunc), - /* 284 */ SyscallDesc("unknown #284", unimplementedFunc), - /* 285 */ SyscallDesc("unknown #285", unimplementedFunc), - /* 286 */ SyscallDesc("unknown #286", unimplementedFunc), - /* 287 */ SyscallDesc("unknown #287", unimplementedFunc), - /* 288 */ SyscallDesc("unknown #288", unimplementedFunc), - /* 289 */ SyscallDesc("unknown #289", unimplementedFunc), - /* 290 */ SyscallDesc("unknown #290", unimplementedFunc), - /* 291 */ SyscallDesc("unknown #291", unimplementedFunc), - /* 292 */ SyscallDesc("unknown #292", unimplementedFunc), - /* 293 */ SyscallDesc("unknown #293", unimplementedFunc), - /* 294 */ SyscallDesc("unknown #294", unimplementedFunc), - /* 295 */ SyscallDesc("unknown #295", unimplementedFunc), - /* 296 */ SyscallDesc("unknown #296", unimplementedFunc), - /* 297 */ SyscallDesc("unknown #297", unimplementedFunc), - /* 298 */ SyscallDesc("unknown #298", unimplementedFunc), - /* 299 */ SyscallDesc("unknown #299", unimplementedFunc), -/* - * Linux-specific system calls begin at 300 - */ - /* 300 */ SyscallDesc("bdflush", unimplementedFunc), - /* 301 */ SyscallDesc("sethae", unimplementedFunc), - /* 302 */ SyscallDesc("mount", unimplementedFunc), - /* 303 */ SyscallDesc("old_adjtimex", unimplementedFunc), - /* 304 */ SyscallDesc("swapoff", unimplementedFunc), - /* 305 */ SyscallDesc("getdents", unimplementedFunc), - /* 306 */ SyscallDesc("create_module", unimplementedFunc), - /* 307 */ SyscallDesc("init_module", unimplementedFunc), - /* 308 */ SyscallDesc("delete_module", unimplementedFunc), - /* 309 */ SyscallDesc("get_kernel_syms", unimplementedFunc), - /* 310 */ SyscallDesc("syslog", unimplementedFunc), - /* 311 */ SyscallDesc("reboot", unimplementedFunc), - /* 312 */ SyscallDesc("clone", unimplementedFunc), - /* 313 */ SyscallDesc("uselib", unimplementedFunc), - /* 314 */ SyscallDesc("mlock", unimplementedFunc), - /* 315 */ SyscallDesc("munlock", unimplementedFunc), - /* 316 */ SyscallDesc("mlockall", unimplementedFunc), - /* 317 */ SyscallDesc("munlockall", unimplementedFunc), - /* 318 */ SyscallDesc("sysinfo", unimplementedFunc), - /* 319 */ SyscallDesc("_sysctl", unimplementedFunc), - /* 320 */ SyscallDesc("was sys_idle", unimplementedFunc), - /* 321 */ SyscallDesc("oldumount", unimplementedFunc), - /* 322 */ SyscallDesc("swapon", unimplementedFunc), - /* 323 */ SyscallDesc("times", ignoreFunc), - /* 324 */ SyscallDesc("personality", unimplementedFunc), - /* 325 */ SyscallDesc("setfsuid", unimplementedFunc), - /* 326 */ SyscallDesc("setfsgid", unimplementedFunc), - /* 327 */ SyscallDesc("ustat", unimplementedFunc), - /* 328 */ SyscallDesc("statfs", unimplementedFunc), - /* 329 */ SyscallDesc("fstatfs", unimplementedFunc), - /* 330 */ SyscallDesc("sched_setparam", unimplementedFunc), - /* 331 */ SyscallDesc("sched_getparam", unimplementedFunc), - /* 332 */ SyscallDesc("sched_setscheduler", unimplementedFunc), - /* 333 */ SyscallDesc("sched_getscheduler", unimplementedFunc), - /* 334 */ SyscallDesc("sched_yield", unimplementedFunc), - /* 335 */ SyscallDesc("sched_get_priority_max", unimplementedFunc), - /* 336 */ SyscallDesc("sched_get_priority_min", unimplementedFunc), - /* 337 */ SyscallDesc("sched_rr_get_interval", unimplementedFunc), - /* 338 */ SyscallDesc("afs_syscall", unimplementedFunc), - /* 339 */ SyscallDesc("uname", unameFunc), - /* 340 */ SyscallDesc("nanosleep", unimplementedFunc), - /* 341 */ SyscallDesc("mremap", unimplementedFunc), - /* 342 */ SyscallDesc("nfsservctl", unimplementedFunc), - /* 343 */ SyscallDesc("setresuid", unimplementedFunc), - /* 344 */ SyscallDesc("getresuid", unimplementedFunc), - /* 345 */ SyscallDesc("pciconfig_read", unimplementedFunc), - /* 346 */ SyscallDesc("pciconfig_write", unimplementedFunc), - /* 347 */ SyscallDesc("query_module", unimplementedFunc), - /* 348 */ SyscallDesc("prctl", unimplementedFunc), - /* 349 */ SyscallDesc("pread", unimplementedFunc), - /* 350 */ SyscallDesc("pwrite", unimplementedFunc), - /* 351 */ SyscallDesc("rt_sigreturn", unimplementedFunc), - /* 352 */ SyscallDesc("rt_sigaction", ignoreFunc), - /* 353 */ SyscallDesc("rt_sigprocmask", unimplementedFunc), - /* 354 */ SyscallDesc("rt_sigpending", unimplementedFunc), - /* 355 */ SyscallDesc("rt_sigtimedwait", unimplementedFunc), - /* 356 */ SyscallDesc("rt_sigqueueinfo", unimplementedFunc), - /* 357 */ SyscallDesc("rt_sigsuspend", unimplementedFunc), - /* 358 */ SyscallDesc("select", unimplementedFunc), - /* 359 */ SyscallDesc("gettimeofday", gettimeofdayFunc<Linux>), - /* 360 */ SyscallDesc("settimeofday", unimplementedFunc), - /* 361 */ SyscallDesc("getitimer", unimplementedFunc), - /* 362 */ SyscallDesc("setitimer", unimplementedFunc), - /* 363 */ SyscallDesc("utimes", utimesFunc<Linux>), - /* 364 */ SyscallDesc("getrusage", getrusageFunc<Linux>), - /* 365 */ SyscallDesc("wait4", unimplementedFunc), - /* 366 */ SyscallDesc("adjtimex", unimplementedFunc), - /* 367 */ SyscallDesc("getcwd", unimplementedFunc), - /* 368 */ SyscallDesc("capget", unimplementedFunc), - /* 369 */ SyscallDesc("capset", unimplementedFunc), - /* 370 */ SyscallDesc("sendfile", unimplementedFunc), - /* 371 */ SyscallDesc("setresgid", unimplementedFunc), - /* 372 */ SyscallDesc("getresgid", unimplementedFunc), - /* 373 */ SyscallDesc("dipc", unimplementedFunc), - /* 374 */ SyscallDesc("pivot_root", unimplementedFunc), - /* 375 */ SyscallDesc("mincore", unimplementedFunc), - /* 376 */ SyscallDesc("pciconfig_iobase", unimplementedFunc), - /* 377 */ SyscallDesc("getdents64", unimplementedFunc), - /* 378 */ SyscallDesc("gettid", unimplementedFunc), - /* 379 */ SyscallDesc("readahead", unimplementedFunc), - /* 380 */ SyscallDesc("security", unimplementedFunc), - /* 381 */ SyscallDesc("tkill", unimplementedFunc), - /* 382 */ SyscallDesc("setxattr", unimplementedFunc), - /* 383 */ SyscallDesc("lsetxattr", unimplementedFunc), - /* 384 */ SyscallDesc("fsetxattr", unimplementedFunc), - /* 385 */ SyscallDesc("getxattr", unimplementedFunc), - /* 386 */ SyscallDesc("lgetxattr", unimplementedFunc), - /* 387 */ SyscallDesc("fgetxattr", unimplementedFunc), - /* 388 */ SyscallDesc("listxattr", unimplementedFunc), - /* 389 */ SyscallDesc("llistxattr", unimplementedFunc), - /* 390 */ SyscallDesc("flistxattr", unimplementedFunc), - /* 391 */ SyscallDesc("removexattr", unimplementedFunc), - /* 392 */ SyscallDesc("lremovexattr", unimplementedFunc), - /* 393 */ SyscallDesc("fremovexattr", unimplementedFunc), - /* 394 */ SyscallDesc("futex", unimplementedFunc), - /* 395 */ SyscallDesc("sched_setaffinity", unimplementedFunc), - /* 396 */ SyscallDesc("sched_getaffinity", unimplementedFunc), - /* 397 */ SyscallDesc("tuxcall", unimplementedFunc), - /* 398 */ SyscallDesc("io_setup", unimplementedFunc), - /* 399 */ SyscallDesc("io_destroy", unimplementedFunc), - /* 400 */ SyscallDesc("io_getevents", unimplementedFunc), - /* 401 */ SyscallDesc("io_submit", unimplementedFunc), - /* 402 */ SyscallDesc("io_cancel", unimplementedFunc), - /* 403 */ SyscallDesc("unknown #403", unimplementedFunc), - /* 404 */ SyscallDesc("unknown #404", unimplementedFunc), - /* 405 */ SyscallDesc("exit_group", exitFunc), // exit all threads... - /* 406 */ SyscallDesc("lookup_dcookie", unimplementedFunc), - /* 407 */ SyscallDesc("sys_epoll_create", unimplementedFunc), - /* 408 */ SyscallDesc("sys_epoll_ctl", unimplementedFunc), - /* 409 */ SyscallDesc("sys_epoll_wait", unimplementedFunc), - /* 410 */ SyscallDesc("remap_file_pages", unimplementedFunc), - /* 411 */ SyscallDesc("set_tid_address", unimplementedFunc), - /* 412 */ SyscallDesc("restart_syscall", unimplementedFunc), - /* 413 */ SyscallDesc("fadvise64", unimplementedFunc), - /* 414 */ SyscallDesc("timer_create", unimplementedFunc), - /* 415 */ SyscallDesc("timer_settime", unimplementedFunc), - /* 416 */ SyscallDesc("timer_gettime", unimplementedFunc), - /* 417 */ SyscallDesc("timer_getoverrun", unimplementedFunc), - /* 418 */ SyscallDesc("timer_delete", unimplementedFunc), - /* 419 */ SyscallDesc("clock_settime", unimplementedFunc), - /* 420 */ SyscallDesc("clock_gettime", unimplementedFunc), - /* 421 */ SyscallDesc("clock_getres", unimplementedFunc), - /* 422 */ SyscallDesc("clock_nanosleep", unimplementedFunc), - /* 423 */ SyscallDesc("semtimedop", unimplementedFunc), - /* 424 */ SyscallDesc("tgkill", unimplementedFunc), - /* 425 */ SyscallDesc("stat64", unimplementedFunc), - /* 426 */ SyscallDesc("lstat64", lstat64Func<Linux>), - /* 427 */ SyscallDesc("fstat64", fstat64Func<Linux>), - /* 428 */ SyscallDesc("vserver", unimplementedFunc), - /* 429 */ SyscallDesc("mbind", unimplementedFunc), - /* 430 */ SyscallDesc("get_mempolicy", unimplementedFunc), - /* 431 */ SyscallDesc("set_mempolicy", unimplementedFunc), - /* 432 */ SyscallDesc("mq_open", unimplementedFunc), - /* 433 */ SyscallDesc("mq_unlink", unimplementedFunc), - /* 434 */ SyscallDesc("mq_timedsend", unimplementedFunc), - /* 435 */ SyscallDesc("mq_timedreceive", unimplementedFunc), - /* 436 */ SyscallDesc("mq_notify", unimplementedFunc), - /* 437 */ SyscallDesc("mq_getsetattr", unimplementedFunc), - /* 438 */ SyscallDesc("waitid", unimplementedFunc), - /* 439 */ SyscallDesc("add_key", unimplementedFunc), - /* 440 */ SyscallDesc("request_key", unimplementedFunc), - /* 441 */ SyscallDesc("keyctl", unimplementedFunc) -}; - -AlphaLinuxProcess::AlphaLinuxProcess(const std::string &name, - ObjectFile *objFile, - int stdin_fd, - int stdout_fd, - int stderr_fd, - std::vector<std::string> &argv, - std::vector<std::string> &envp) - : LiveProcess(name, objFile, stdin_fd, stdout_fd, stderr_fd, argv, envp), - Num_Syscall_Descs(sizeof(syscallDescs) / sizeof(SyscallDesc)) -{ - init_regs->intRegFile[0] = 0; -} - - - -SyscallDesc* -AlphaLinuxProcess::getDesc(int callnum) -{ - if (callnum < 0 || callnum > Num_Syscall_Descs) - return NULL; - return &syscallDescs[callnum]; -} diff --git a/arch/alpha/linux/process.hh b/arch/alpha/linux/process.hh deleted file mode 100644 index 7de1b1ac1..000000000 --- a/arch/alpha/linux/process.hh +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2003-2004 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __ALPHA_LINUX_PROCESS_HH__ -#define __ALPHA_LINUX_PROCESS_HH__ - -#include "sim/process.hh" - - -/// A process with emulated Alpha/Linux syscalls. -class AlphaLinuxProcess : public LiveProcess -{ - public: - /// Constructor. - AlphaLinuxProcess(const std::string &name, - ObjectFile *objFile, - int stdin_fd, int stdout_fd, int stderr_fd, - std::vector<std::string> &argv, - std::vector<std::string> &envp); - - virtual SyscallDesc* getDesc(int callnum); - - /// The target system's hostname. - static const char *hostname; - - /// Array of syscall descriptors, indexed by call number. - static SyscallDesc syscallDescs[]; - - const int Num_Syscall_Descs; -}; - - -#endif // __ALPHA_LINUX_PROCESS_HH__ diff --git a/arch/alpha/linux/system.cc b/arch/alpha/linux/system.cc deleted file mode 100644 index f9275d15e..000000000 --- a/arch/alpha/linux/system.cc +++ /dev/null @@ -1,289 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * This code loads the linux kernel, console, pal and patches certain - * functions. The symbol tables are loaded so that traces can show - * the executing function and we can skip functions. Various delay - * loops are skipped and their final values manually computed to speed - * up boot time. - */ - -#include "arch/arguments.hh" -#include "arch/vtophys.hh" -#include "arch/alpha/linux/system.hh" -#include "arch/alpha/linux/threadinfo.hh" -#include "arch/alpha/system.hh" -#include "base/loader/symtab.hh" -#include "cpu/exec_context.hh" -#include "cpu/base.hh" -#include "dev/platform.hh" -#include "kern/linux/printk.hh" -#include "kern/linux/events.hh" -#include "mem/functional/memory_control.hh" -#include "mem/functional/physical.hh" -#include "sim/builder.hh" -#include "sim/byteswap.hh" - -using namespace std; -using namespace AlphaISA; -using namespace Linux; - -LinuxAlphaSystem::LinuxAlphaSystem(Params *p) - : AlphaSystem(p) -{ - Addr addr = 0; - Addr paddr = 0; - - /** - * The symbol swapper_pg_dir marks the beginning of the kernel and - * the location of bootloader passed arguments - */ - if (!kernelSymtab->findAddress("swapper_pg_dir", KernelStart)) { - panic("Could not determine start location of kernel"); - } - - /** - * Since we aren't using a bootloader, we have to copy the - * kernel arguments directly into the kernel's memory. - */ - paddr = vtophys(physmem, CommandLine()); - char *commandline = (char *)physmem->dma_addr(paddr, sizeof(uint64_t)); - if (commandline) - strncpy(commandline, params()->boot_osflags.c_str(), CommandLineSize); - - /** - * find the address of the est_cycle_freq variable and insert it - * so we don't through the lengthly process of trying to - * calculated it by using the PIT, RTC, etc. - */ - if (kernelSymtab->findAddress("est_cycle_freq", addr)) { - paddr = vtophys(physmem, addr); - uint8_t *est_cycle_frequency = - physmem->dma_addr(paddr, sizeof(uint64_t)); - - if (est_cycle_frequency) - *(uint64_t *)est_cycle_frequency = - Clock::Frequency / p->boot_cpu_frequency; - } - - - /** - * EV5 only supports 127 ASNs so we are going to tell the kernel that the - * paritiuclar EV6 we have only supports 127 asns. - * @todo At some point we should change ev5.hh and the palcode to support - * 255 ASNs. - */ - if (kernelSymtab->findAddress("dp264_mv", addr)) { - paddr = vtophys(physmem, addr); - char *dp264_mv = (char *)physmem->dma_addr(paddr, sizeof(uint64_t)); - - if (dp264_mv) { - *(uint32_t*)(dp264_mv+0x18) = LittleEndianGuest::htog((uint32_t)127); - } else - panic("could not translate dp264_mv addr\n"); - - } else - panic("could not find dp264_mv\n"); - -#ifndef NDEBUG - kernelPanicEvent = addKernelFuncEvent<BreakPCEvent>("panic"); - if (!kernelPanicEvent) - panic("could not find kernel symbol \'panic\'"); - -#if 0 - kernelDieEvent = addKernelFuncEvent<BreakPCEvent>("die_if_kernel"); - if (!kernelDieEvent) - panic("could not find kernel symbol \'die_if_kernel\'"); -#endif - -#endif - - /** - * Any time ide_delay_50ms, calibarte_delay or - * determine_cpu_caches is called just skip the - * function. Currently determine_cpu_caches only is used put - * information in proc, however if that changes in the future we - * will have to fill in the cache size variables appropriately. - */ - - skipIdeDelay50msEvent = - addKernelFuncEvent<SkipFuncEvent>("ide_delay_50ms"); - skipDelayLoopEvent = - addKernelFuncEvent<SkipDelayLoopEvent>("calibrate_delay"); - skipCacheProbeEvent = - addKernelFuncEvent<SkipFuncEvent>("determine_cpu_caches"); - debugPrintkEvent = addKernelFuncEvent<DebugPrintkEvent>("dprintk"); - idleStartEvent = addKernelFuncEvent<IdleStartEvent>("cpu_idle"); - - if (kernelSymtab->findAddress("alpha_switch_to", addr) && DTRACE(Thread)) { - printThreadEvent = new PrintThreadInfo(&pcEventQueue, "threadinfo", - addr + sizeof(MachInst) * 6); - } else { - printThreadEvent = NULL; - } - - if (params()->bin_int) { - intStartEvent = addPalFuncEvent<InterruptStartEvent>("sys_int_21"); - if (!intStartEvent) - panic("could not find symbol: sys_int_21\n"); - - intEndEvent = addPalFuncEvent<InterruptEndEvent>("rti_to_kern"); - if (!intEndEvent) - panic("could not find symbol: rti_to_kern\n"); - - intEndEvent2 = addPalFuncEvent<InterruptEndEvent>("rti_to_user"); - if (!intEndEvent2) - panic("could not find symbol: rti_to_user\n"); - - intEndEvent3 = addKernelFuncEvent<InterruptEndEvent>("do_softirq"); - if (!intEndEvent3) - panic("could not find symbol: do_softirq\n"); - } -} - -LinuxAlphaSystem::~LinuxAlphaSystem() -{ -#ifndef NDEBUG - delete kernelPanicEvent; -#endif - delete skipIdeDelay50msEvent; - delete skipDelayLoopEvent; - delete skipCacheProbeEvent; - delete debugPrintkEvent; - delete idleStartEvent; - delete printThreadEvent; - delete intStartEvent; - delete intEndEvent; - delete intEndEvent2; -} - - -void -LinuxAlphaSystem::setDelayLoop(ExecContext *xc) -{ - Addr addr = 0; - if (kernelSymtab->findAddress("loops_per_jiffy", addr)) { - Addr paddr = vtophys(physmem, addr); - - uint8_t *loops_per_jiffy = - physmem->dma_addr(paddr, sizeof(uint32_t)); - - Tick cpuFreq = xc->getCpuPtr()->frequency(); - Tick intrFreq = platform->intrFrequency(); - *(uint32_t *)loops_per_jiffy = - (uint32_t)((cpuFreq / intrFreq) * 0.9988); - } -} - - -void -LinuxAlphaSystem::SkipDelayLoopEvent::process(ExecContext *xc) -{ - SkipFuncEvent::process(xc); - // calculate and set loops_per_jiffy - ((LinuxAlphaSystem *)xc->getSystemPtr())->setDelayLoop(xc); -} - -void -LinuxAlphaSystem::PrintThreadInfo::process(ExecContext *xc) -{ - Linux::ThreadInfo ti(xc); - - DPRINTF(Thread, "Currently Executing Thread %s, pid %d, started at: %d\n", - ti.curTaskName(), ti.curTaskPID(), ti.curTaskStart()); -} - - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(LinuxAlphaSystem) - - Param<Tick> boot_cpu_frequency; - SimObjectParam<MemoryController *> memctrl; - SimObjectParam<PhysicalMemory *> physmem; - - Param<string> kernel; - Param<string> console; - Param<string> pal; - - Param<string> boot_osflags; - Param<string> readfile; - Param<unsigned int> init_param; - - Param<uint64_t> system_type; - Param<uint64_t> system_rev; - - Param<bool> bin; - VectorParam<string> binned_fns; - Param<bool> bin_int; - -END_DECLARE_SIM_OBJECT_PARAMS(LinuxAlphaSystem) - -BEGIN_INIT_SIM_OBJECT_PARAMS(LinuxAlphaSystem) - - INIT_PARAM(boot_cpu_frequency, "Frequency of the boot CPU"), - INIT_PARAM(memctrl, "memory controller"), - INIT_PARAM(physmem, "phsyical memory"), - INIT_PARAM(kernel, "file that contains the kernel code"), - INIT_PARAM(console, "file that contains the console code"), - INIT_PARAM(pal, "file that contains palcode"), - INIT_PARAM_DFLT(boot_osflags, "flags to pass to the kernel during boot", - "a"), - INIT_PARAM_DFLT(readfile, "file to read startup script from", ""), - INIT_PARAM_DFLT(init_param, "numerical value to pass into simulator", 0), - INIT_PARAM_DFLT(system_type, "Type of system we are emulating", 34), - INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 1<<10), - INIT_PARAM_DFLT(bin, "is this system to be binned", false), - INIT_PARAM(binned_fns, "functions to be broken down and binned"), - INIT_PARAM_DFLT(bin_int, "is interrupt code binned seperately?", true) - -END_INIT_SIM_OBJECT_PARAMS(LinuxAlphaSystem) - -CREATE_SIM_OBJECT(LinuxAlphaSystem) -{ - AlphaSystem::Params *p = new AlphaSystem::Params; - p->name = getInstanceName(); - p->boot_cpu_frequency = boot_cpu_frequency; - p->memctrl = memctrl; - p->physmem = physmem; - p->kernel_path = kernel; - p->console_path = console; - p->palcode = pal; - p->boot_osflags = boot_osflags; - p->init_param = init_param; - p->readfile = readfile; - p->system_type = system_type; - p->system_rev = system_rev; - p->bin = bin; - p->binned_fns = binned_fns; - p->bin_int = bin_int; - return new LinuxAlphaSystem(p); -} - -REGISTER_SIM_OBJECT("LinuxAlphaSystem", LinuxAlphaSystem) - diff --git a/arch/alpha/linux/system.hh b/arch/alpha/linux/system.hh deleted file mode 100644 index 035e2a427..000000000 --- a/arch/alpha/linux/system.hh +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __ARCH_ALPHA_LINUX_SYSTEM_HH__ -#define __ARCH_ALPHA_LINUX_SYSTEM_HH__ - -class ExecContext; - -class BreakPCEvent; -class IdleStartEvent; - -#include "arch/alpha/system.hh" -#include "kern/linux/events.hh" - -using namespace AlphaISA; -using namespace Linux; -using namespace std; - -/** - * This class contains linux specific system code (Loading, Events, Binning). - * It points to objects that are the system binaries to load and patches them - * appropriately to work in simulator. - */ -class LinuxAlphaSystem : public AlphaSystem -{ - private: - class SkipDelayLoopEvent : public SkipFuncEvent - { - public: - SkipDelayLoopEvent(PCEventQueue *q, const std::string &desc, Addr addr) - : SkipFuncEvent(q, desc, addr) {} - virtual void process(ExecContext *xc); - }; - - class PrintThreadInfo : public PCEvent - { - public: - PrintThreadInfo(PCEventQueue *q, const std::string &desc, Addr addr) - : PCEvent(q, desc, addr) {} - virtual void process(ExecContext *xc); - }; - - - /** - * Addresses defining where the kernel bootloader places various - * elements. Details found in include/asm-alpha/system.h - */ - Addr KernelStart; // Lookup the symbol swapper_pg_dir - - public: - Addr InitStack() const { return KernelStart + 0x02000; } - Addr EmptyPGT() const { return KernelStart + 0x04000; } - Addr EmptyPGE() const { return KernelStart + 0x08000; } - Addr ZeroPGE() const { return KernelStart + 0x0A000; } - Addr StartAddr() const { return KernelStart + 0x10000; } - - Addr Param() const { return ZeroPGE() + 0x0; } - Addr CommandLine() const { return Param() + 0x0; } - Addr InitrdStart() const { return Param() + 0x100; } - Addr InitrdSize() const { return Param() + 0x108; } - static const int CommandLineSize = 256; - - private: -#ifndef NDEBUG - /** Event to halt the simulator if the kernel calls panic() */ - BreakPCEvent *kernelPanicEvent; - - /** Event to halt the simulator if the kernel calls die_if_kernel */ - BreakPCEvent *kernelDieEvent; -#endif - - /** - * Event to skip determine_cpu_caches() because we don't support - * the IPRs that the code can access to figure out cache sizes - */ - SkipFuncEvent *skipCacheProbeEvent; - - /** PC based event to skip the ide_delay_50ms() call */ - SkipFuncEvent *skipIdeDelay50msEvent; - - /** - * PC based event to skip the dprink() call and emulate its - * functionality - */ - DebugPrintkEvent *debugPrintkEvent; - - /** - * Skip calculate_delay_loop() rather than waiting for this to be - * calculated - */ - SkipDelayLoopEvent *skipDelayLoopEvent; - - /** - * Event to print information about thread switches if the trace flag - * Thread is set - */ - PrintThreadInfo *printThreadEvent; - - /** - * Event to bin Interrupts seperately from kernel code - */ - InterruptStartEvent *intStartEvent; - - /** - * Event to bin Interrupts seperately from kernel code - */ - InterruptEndEvent *intEndEvent; - InterruptEndEvent *intEndEvent2; - InterruptEndEvent *intEndEvent3; - - /** Grab the PCBB of the idle process when it starts */ - IdleStartEvent *idleStartEvent; - - public: - LinuxAlphaSystem(Params *p); - ~LinuxAlphaSystem(); - - void setDelayLoop(ExecContext *xc); -}; - -#endif // __ARCH_ALPHA_LINUX_SYSTEM_HH__ diff --git a/arch/alpha/process.cc b/arch/alpha/process.cc deleted file mode 100644 index b2dbe7ad1..000000000 --- a/arch/alpha/process.cc +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2003-2004 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "arch/alpha/process.hh" - -namespace AlphaISA -{ - -LiveProcess * -createProcess(const std::string &nm, ObjectFile * objFile, - int stdin_fd, int stdout_fd, int stderr_fd, - std::vector<std::string> &argv, std::vector<std::string> &envp) -{ - LiveProcess * process = NULL; - if (objFile->getArch() != ObjectFile::Alpha) - fatal("Object file does not match architecture."); - switch (objFile->getOpSys()) { - case ObjectFile::Tru64: - process = new AlphaTru64Process(nm, objFile, - stdin_fd, stdout_fd, stderr_fd, - argv, envp); - break; - - case ObjectFile::Linux: - process = new AlphaLinuxProcess(nm, objFile, - stdin_fd, stdout_fd, stderr_fd, - argv, envp); - break; - - default: - fatal("Unknown/unsupported operating system."); - } - return process; -} - -} // namespace AlphaISA diff --git a/arch/alpha/process.hh b/arch/alpha/process.hh deleted file mode 100644 index 4a2a4212e..000000000 --- a/arch/alpha/process.hh +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2003-2004 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __ALPHA_PROCESS_HH__ -#define __ALPHA_PROCESS_HH__ - -#include <string> - -#include "arch/alpha/linux/process.hh" -#include "arch/alpha/tru64/process.hh" -#include "base/loader/object_file.hh" - -namespace AlphaISA -{ - -LiveProcess * -createProcess(const std::string &nm, ObjectFile * objFile, - int stdin_fd, int stdout_fd, int stderr_fd, - std::vector<std::string> &argv, std::vector<std::string> &envp); - -} // namespace AlphaISA - -#endif // __ALPHA_PROCESS_HH__ diff --git a/arch/alpha/stacktrace.cc b/arch/alpha/stacktrace.cc deleted file mode 100644 index 26656ab5c..000000000 --- a/arch/alpha/stacktrace.cc +++ /dev/null @@ -1,348 +0,0 @@ -/* - * Copyright (c) 2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <string> - -#include "arch/alpha/isa_traits.hh" -#include "arch/alpha/stacktrace.hh" -#include "arch/alpha/vtophys.hh" -#include "base/bitfield.hh" -#include "base/trace.hh" -#include "cpu/base.hh" -#include "cpu/exec_context.hh" -#include "sim/system.hh" - -using namespace std; -using namespace AlphaISA; - -ProcessInfo::ProcessInfo(ExecContext *_xc) - : xc(_xc) -{ - Addr addr = 0; - - if (!xc->getSystemPtr()->kernelSymtab->findAddress("thread_info_size", addr)) - panic("thread info not compiled into kernel\n"); - thread_info_size = *(int32_t *)vtomem(xc, addr, sizeof(int32_t)); - - if (!xc->getSystemPtr()->kernelSymtab->findAddress("task_struct_size", addr)) - panic("thread info not compiled into kernel\n"); - task_struct_size = *(int32_t *)vtomem(xc, addr, sizeof(int32_t)); - - if (!xc->getSystemPtr()->kernelSymtab->findAddress("thread_info_task", addr)) - panic("thread info not compiled into kernel\n"); - task_off = *(int32_t *)vtomem(xc, addr, sizeof(int32_t)); - - if (!xc->getSystemPtr()->kernelSymtab->findAddress("task_struct_pid", addr)) - panic("thread info not compiled into kernel\n"); - pid_off = *(int32_t *)vtomem(xc, addr, sizeof(int32_t)); - - if (!xc->getSystemPtr()->kernelSymtab->findAddress("task_struct_comm", addr)) - panic("thread info not compiled into kernel\n"); - name_off = *(int32_t *)vtomem(xc, addr, sizeof(int32_t)); -} - -Addr -ProcessInfo::task(Addr ksp) const -{ - Addr base = ksp & ~0x3fff; - if (base == ULL(0xfffffc0000000000)) - return 0; - - Addr task; - CopyOut(xc, &task, base + task_off, sizeof(task)); - return task; -} - -int -ProcessInfo::pid(Addr ksp) const -{ - Addr task = this->task(ksp); - if (!task) - return -1; - - uint16_t pid; - CopyOut(xc, &pid, task + pid_off, sizeof(pid)); - return pid; -} - -string -ProcessInfo::name(Addr ksp) const -{ - Addr task = this->task(ksp); - if (!task) - return "console"; - - char comm[256]; - CopyString(xc, comm, task + name_off, sizeof(comm)); - if (!comm[0]) - return "startup"; - - return comm; -} - -StackTrace::StackTrace() - : xc(0), stack(64) -{ -} - -StackTrace::StackTrace(ExecContext *_xc, StaticInstPtr inst) - : xc(0), stack(64) -{ - trace(_xc, inst); -} - -StackTrace::~StackTrace() -{ -} - -void -StackTrace::trace(ExecContext *_xc, bool is_call) -{ - xc = _xc; - - bool usermode = (xc->readMiscReg(AlphaISA::IPR_DTB_CM) & 0x18) != 0; - - Addr pc = xc->readNextPC(); - bool kernel = xc->getSystemPtr()->kernelStart <= pc && - pc <= xc->getSystemPtr()->kernelEnd; - - if (usermode) { - stack.push_back(user); - return; - } - - if (!kernel) { - stack.push_back(console); - return; - } - - SymbolTable *symtab = xc->getSystemPtr()->kernelSymtab; - Addr ksp = xc->readIntReg(TheISA::StackPointerReg); - Addr bottom = ksp & ~0x3fff; - Addr addr; - - if (is_call) { - if (!symtab->findNearestAddr(pc, addr)) - panic("could not find address %#x", pc); - - stack.push_back(addr); - pc = xc->readPC(); - } - - Addr ra; - int size; - - while (ksp > bottom) { - if (!symtab->findNearestAddr(pc, addr)) - panic("could not find symbol for pc=%#x", pc); - assert(pc >= addr && "symbol botch: callpc < func"); - - stack.push_back(addr); - - if (isEntry(addr)) - return; - - if (decodePrologue(ksp, pc, addr, size, ra)) { - if (!ra) - return; - - if (size <= 0) { - stack.push_back(unknown); - return; - } - - pc = ra; - ksp += size; - } else { - stack.push_back(unknown); - return; - } - - bool kernel = xc->getSystemPtr()->kernelStart <= pc && - pc <= xc->getSystemPtr()->kernelEnd; - if (!kernel) - return; - - if (stack.size() >= 1000) - panic("unwinding too far"); - } - - panic("unwinding too far"); -} - -bool -StackTrace::isEntry(Addr addr) -{ - if (addr == xc->readMiscReg(AlphaISA::IPR_PALtemp12)) - return true; - - if (addr == xc->readMiscReg(AlphaISA::IPR_PALtemp7)) - return true; - - if (addr == xc->readMiscReg(AlphaISA::IPR_PALtemp11)) - return true; - - if (addr == xc->readMiscReg(AlphaISA::IPR_PALtemp21)) - return true; - - if (addr == xc->readMiscReg(AlphaISA::IPR_PALtemp9)) - return true; - - if (addr == xc->readMiscReg(AlphaISA::IPR_PALtemp2)) - return true; - - return false; -} - -bool -StackTrace::decodeStack(MachInst inst, int &disp) -{ - // lda $sp, -disp($sp) - // - // Opcode<31:26> == 0x08 - // RA<25:21> == 30 - // RB<20:16> == 30 - // Disp<15:0> - const MachInst mem_mask = 0xffff0000; - const MachInst lda_pattern = 0x23de0000; - const MachInst lda_disp_mask = 0x0000ffff; - - // subq $sp, disp, $sp - // addq $sp, disp, $sp - // - // Opcode<31:26> == 0x10 - // RA<25:21> == 30 - // Lit<20:13> - // One<12> = 1 - // Func<11:5> == 0x20 (addq) - // Func<11:5> == 0x29 (subq) - // RC<4:0> == 30 - const MachInst intop_mask = 0xffe01fff; - const MachInst addq_pattern = 0x43c0141e; - const MachInst subq_pattern = 0x43c0153e; - const MachInst intop_disp_mask = 0x001fe000; - const int intop_disp_shift = 13; - - if ((inst & mem_mask) == lda_pattern) - disp = -sext<16>(inst & lda_disp_mask); - else if ((inst & intop_mask) == addq_pattern) - disp = -int((inst & intop_disp_mask) >> intop_disp_shift); - else if ((inst & intop_mask) == subq_pattern) - disp = int((inst & intop_disp_mask) >> intop_disp_shift); - else - return false; - - return true; -} - -bool -StackTrace::decodeSave(MachInst inst, int ®, int &disp) -{ - // lda $stq, disp($sp) - // - // Opcode<31:26> == 0x08 - // RA<25:21> == ? - // RB<20:16> == 30 - // Disp<15:0> - const MachInst stq_mask = 0xfc1f0000; - const MachInst stq_pattern = 0xb41e0000; - const MachInst stq_disp_mask = 0x0000ffff; - const MachInst reg_mask = 0x03e00000; - const int reg_shift = 21; - - if ((inst & stq_mask) == stq_pattern) { - reg = (inst & reg_mask) >> reg_shift; - disp = sext<16>(inst & stq_disp_mask); - } else { - return false; - } - - return true; -} - -/* - * Decode the function prologue for the function we're in, and note - * which registers are stored where, and how large the stack frame is. - */ -bool -StackTrace::decodePrologue(Addr sp, Addr callpc, Addr func, - int &size, Addr &ra) -{ - size = 0; - ra = 0; - - for (Addr pc = func; pc < callpc; pc += sizeof(MachInst)) { - MachInst inst; - CopyOut(xc, (uint8_t *)&inst, pc, sizeof(MachInst)); - - int reg, disp; - if (decodeStack(inst, disp)) { - if (size) { - // panic("decoding frame size again"); - return true; - } - size += disp; - } else if (decodeSave(inst, reg, disp)) { - if (!ra && reg == ReturnAddressReg) { - CopyOut(xc, (uint8_t *)&ra, sp + disp, sizeof(Addr)); - if (!ra) { - // panic("no return address value pc=%#x\n", pc); - return false; - } - } - } - } - - return true; -} - -#if TRACING_ON -void -StackTrace::dump() -{ - StringWrap name(xc->getCpuPtr()->name()); - SymbolTable *symtab = xc->getSystemPtr()->kernelSymtab; - - DPRINTFN("------ Stack ------\n"); - - string symbol; - for (int i = 0, size = stack.size(); i < size; ++i) { - Addr addr = stack[size - i - 1]; - if (addr == user) - symbol = "user"; - else if (addr == console) - symbol = "console"; - else if (addr == unknown) - symbol = "unknown"; - else - symtab->findSymbol(addr, symbol); - - DPRINTFN("%#x: %s\n", addr, symbol); - } -} -#endif diff --git a/arch/alpha/system.cc b/arch/alpha/system.cc deleted file mode 100644 index 25543da57..000000000 --- a/arch/alpha/system.cc +++ /dev/null @@ -1,299 +0,0 @@ -/* - * Copyright (c) 2002-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "arch/alpha/system.hh" -#include "arch/vtophys.hh" -#include "base/remote_gdb.hh" -#include "base/loader/object_file.hh" -#include "base/loader/symtab.hh" -#include "base/trace.hh" -#include "mem/functional/memory_control.hh" -#include "mem/functional/physical.hh" -#include "sim/byteswap.hh" -#include "sim/builder.hh" - - -using namespace LittleEndianGuest; - -AlphaSystem::AlphaSystem(Params *p) - : System(p) -{ - consoleSymtab = new SymbolTable; - palSymtab = new SymbolTable; - - - /** - * Load the pal, and console code into memory - */ - // Load Console Code - console = createObjectFile(params()->console_path); - if (console == NULL) - fatal("Could not load console file %s", params()->console_path); - - // Load pal file - pal = createObjectFile(params()->palcode); - if (pal == NULL) - fatal("Could not load PALcode file %s", params()->palcode); - - - // Load program sections into memory - pal->loadSections(physmem, true); - console->loadSections(physmem, true); - - // load symbols - if (!console->loadGlobalSymbols(consoleSymtab)) - panic("could not load console symbols\n"); - - if (!pal->loadGlobalSymbols(palSymtab)) - panic("could not load pal symbols\n"); - - if (!pal->loadLocalSymbols(palSymtab)) - panic("could not load pal symbols\n"); - - if (!console->loadGlobalSymbols(debugSymbolTable)) - panic("could not load console symbols\n"); - - if (!pal->loadGlobalSymbols(debugSymbolTable)) - panic("could not load pal symbols\n"); - - if (!pal->loadLocalSymbols(debugSymbolTable)) - panic("could not load pal symbols\n"); - - Addr addr = 0; -#ifndef NDEBUG - consolePanicEvent = addConsoleFuncEvent<BreakPCEvent>("panic"); -#endif - - /** - * Copy the osflags (kernel arguments) into the consoles - * memory. (Presently Linux does not use the console service - * routine to get these command line arguments, but Tru64 and - * others do.) - */ - if (consoleSymtab->findAddress("env_booted_osflags", addr)) { - Addr paddr = vtophys(physmem, addr); - char *osflags = (char *)physmem->dma_addr(paddr, sizeof(uint32_t)); - - if (osflags) - strcpy(osflags, params()->boot_osflags.c_str()); - } - - /** - * Set the hardware reset parameter block system type and revision - * information to Tsunami. - */ - if (consoleSymtab->findAddress("m5_rpb", addr)) { - Addr paddr = vtophys(physmem, addr); - char *hwrpb = (char *)physmem->dma_addr(paddr, sizeof(uint64_t)); - - if (!hwrpb) - panic("could not translate hwrpb addr\n"); - - *(uint64_t*)(hwrpb+0x50) = htog(params()->system_type); - *(uint64_t*)(hwrpb+0x58) = htog(params()->system_rev); - } else - panic("could not find hwrpb\n"); - -} - -AlphaSystem::~AlphaSystem() -{ - delete consoleSymtab; - delete console; - delete pal; -#ifdef DEBUG - delete consolePanicEvent; -#endif -} - -/** - * This function fixes up addresses that are used to match PCs for - * hooking simulator events on to target function executions. - * - * Alpha binaries may have multiple global offset table (GOT) - * sections. A function that uses the GOT starts with a - * two-instruction prolog which sets the global pointer (gp == r29) to - * the appropriate GOT section. The proper gp value is calculated - * based on the function address, which must be passed by the caller - * in the procedure value register (pv aka t12 == r27). This sequence - * looks like the following: - * - * opcode Ra Rb offset - * ldah gp,X(pv) 09 29 27 X - * lda gp,Y(gp) 08 29 29 Y - * - * for some constant offsets X and Y. The catch is that the linker - * (or maybe even the compiler, I'm not sure) may recognize that the - * caller and callee are using the same GOT section, making this - * prolog redundant, and modify the call target to skip these - * instructions. If we check for execution of the first instruction - * of a function (the one the symbol points to) to detect when to skip - * it, we'll miss all these modified calls. It might work to - * unconditionally check for the third instruction, but not all - * functions have this prolog, and there's some chance that those - * first two instructions could have undesired consequences. So we do - * the Right Thing and pattern-match the first two instructions of the - * function to decide where to patch. - * - * Eventually this code should be moved into an ISA-specific file. - */ -Addr -AlphaSystem::fixFuncEventAddr(Addr addr) -{ - // mask for just the opcode, Ra, and Rb fields (not the offset) - const uint32_t inst_mask = 0xffff0000; - // ldah gp,X(pv): opcode 9, Ra = 29, Rb = 27 - const uint32_t gp_ldah_pattern = (9 << 26) | (29 << 21) | (27 << 16); - // lda gp,Y(gp): opcode 8, Ra = 29, rb = 29 - const uint32_t gp_lda_pattern = (8 << 26) | (29 << 21) | (29 << 16); - // instruction size - const int sz = sizeof(uint32_t); - - Addr paddr = vtophys(physmem, addr); - uint32_t i1 = *(uint32_t *)physmem->dma_addr(paddr, sz); - uint32_t i2 = *(uint32_t *)physmem->dma_addr(paddr+sz, sz); - - if ((i1 & inst_mask) == gp_ldah_pattern && - (i2 & inst_mask) == gp_lda_pattern) { - Addr new_addr = addr + 2*sz; - DPRINTF(Loader, "fixFuncEventAddr: %p -> %p", addr, new_addr); - return new_addr; - } else { - return addr; - } -} - - -void -AlphaSystem::setAlphaAccess(Addr access) -{ - Addr addr = 0; - if (consoleSymtab->findAddress("m5AlphaAccess", addr)) { - Addr paddr = vtophys(physmem, addr); - uint64_t *m5AlphaAccess = - (uint64_t *)physmem->dma_addr(paddr, sizeof(uint64_t)); - - if (!m5AlphaAccess) - panic("could not translate m5AlphaAccess addr\n"); - - *m5AlphaAccess = htog(EV5::Phys2K0Seg(access)); - } else - panic("could not find m5AlphaAccess\n"); -} - -bool -AlphaSystem::breakpoint() -{ - return remoteGDB[0]->trap(ALPHA_KENTRY_INT); -} - -void -AlphaSystem::serialize(std::ostream &os) -{ - System::serialize(os); - consoleSymtab->serialize("console_symtab", os); - palSymtab->serialize("pal_symtab", os); -} - - -void -AlphaSystem::unserialize(Checkpoint *cp, const std::string §ion) -{ - System::unserialize(cp,section); - consoleSymtab->unserialize("console_symtab", cp, section); - palSymtab->unserialize("pal_symtab", cp, section); -} - - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaSystem) - - Param<Tick> boot_cpu_frequency; - SimObjectParam<MemoryController *> memctrl; - SimObjectParam<PhysicalMemory *> physmem; - - Param<std::string> kernel; - Param<std::string> console; - Param<std::string> pal; - - Param<std::string> boot_osflags; - Param<std::string> readfile; - Param<unsigned int> init_param; - - Param<uint64_t> system_type; - Param<uint64_t> system_rev; - - Param<bool> bin; - VectorParam<std::string> binned_fns; - Param<bool> bin_int; - -END_DECLARE_SIM_OBJECT_PARAMS(AlphaSystem) - -BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaSystem) - - INIT_PARAM(boot_cpu_frequency, "Frequency of the boot CPU"), - INIT_PARAM(memctrl, "memory controller"), - INIT_PARAM(physmem, "phsyical memory"), - INIT_PARAM(kernel, "file that contains the kernel code"), - INIT_PARAM(console, "file that contains the console code"), - INIT_PARAM(pal, "file that contains palcode"), - INIT_PARAM_DFLT(boot_osflags, "flags to pass to the kernel during boot", - "a"), - INIT_PARAM_DFLT(readfile, "file to read startup script from", ""), - INIT_PARAM_DFLT(init_param, "numerical value to pass into simulator", 0), - INIT_PARAM_DFLT(system_type, "Type of system we are emulating", 34), - INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 1<<10), - INIT_PARAM_DFLT(bin, "is this system to be binned", false), - INIT_PARAM(binned_fns, "functions to be broken down and binned"), - INIT_PARAM_DFLT(bin_int, "is interrupt code binned seperately?", true) - -END_INIT_SIM_OBJECT_PARAMS(AlphaSystem) - -CREATE_SIM_OBJECT(AlphaSystem) -{ - AlphaSystem::Params *p = new AlphaSystem::Params; - p->name = getInstanceName(); - p->boot_cpu_frequency = boot_cpu_frequency; - p->memctrl = memctrl; - p->physmem = physmem; - p->kernel_path = kernel; - p->console_path = console; - p->palcode = pal; - p->boot_osflags = boot_osflags; - p->init_param = init_param; - p->readfile = readfile; - p->system_type = system_type; - p->system_rev = system_rev; - p->bin = bin; - p->binned_fns = binned_fns; - p->bin_int = bin_int; - return new AlphaSystem(p); -} - -REGISTER_SIM_OBJECT("AlphaSystem", AlphaSystem) - - diff --git a/arch/alpha/system.hh b/arch/alpha/system.hh deleted file mode 100644 index fe1307ac3..000000000 --- a/arch/alpha/system.hh +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2002-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __ARCH_ALPHA_SYSTEM_HH__ -#define __ARCH_ALPHA_SYSTEM_HH__ - -#include <string> -#include <vector> - -#include "sim/system.hh" -#include "base/loader/symtab.hh" -#include "cpu/pc_event.hh" -#include "kern/system_events.hh" -#include "sim/sim_object.hh" - -class AlphaSystem : public System -{ - public: - struct Params : public System::Params - { - std::string console_path; - std::string palcode; - std::string boot_osflags; - uint64_t system_type; - uint64_t system_rev; - }; - - AlphaSystem(Params *p); - - ~AlphaSystem(); - - virtual bool breakpoint(); - -/** - * Serialization stuff - */ - public: - virtual void serialize(std::ostream &os); - virtual void unserialize(Checkpoint *cp, const std::string §ion); - - /** - * Set the m5AlphaAccess pointer in the console - */ - void setAlphaAccess(Addr access); - - /** console symbol table */ - SymbolTable *consoleSymtab; - - /** pal symbol table */ - SymbolTable *palSymtab; - - /** Object pointer for the console code */ - ObjectFile *console; - - /** Object pointer for the PAL code */ - ObjectFile *pal; - -#ifndef NDEBUG - /** Event to halt the simulator if the console calls panic() */ - BreakPCEvent *consolePanicEvent; -#endif - protected: - const Params *params() const { return (const Params *)_params; } - - /** Add a function-based event to PALcode. */ - template <class T> - T *AlphaSystem::addPalFuncEvent(const char *lbl) - { - return addFuncEvent<T>(palSymtab, lbl); - } - - /** Add a function-based event to the console code. */ - template <class T> - T *AlphaSystem::addConsoleFuncEvent(const char *lbl) - { - return addFuncEvent<T>(consoleSymtab, lbl); - } - - virtual Addr fixFuncEventAddr(Addr addr); - -}; - -#endif - diff --git a/arch/alpha/tlb.cc b/arch/alpha/tlb.cc deleted file mode 100644 index 562235ef8..000000000 --- a/arch/alpha/tlb.cc +++ /dev/null @@ -1,643 +0,0 @@ -/* - * Copyright (c) 2001-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <sstream> -#include <string> -#include <vector> - -#include "arch/alpha/tlb.hh" -#include "base/inifile.hh" -#include "base/str.hh" -#include "base/trace.hh" -#include "config/alpha_tlaser.hh" -#include "cpu/exec_context.hh" -#include "sim/builder.hh" - -using namespace std; -using namespace EV5; - -/////////////////////////////////////////////////////////////////////// -// -// Alpha TLB -// -#ifdef DEBUG -bool uncacheBit39 = false; -bool uncacheBit40 = false; -#endif - -#define MODE2MASK(X) (1 << (X)) - -AlphaTLB::AlphaTLB(const string &name, int s) - : SimObject(name), size(s), nlu(0) -{ - table = new AlphaISA::PTE[size]; - memset(table, 0, sizeof(AlphaISA::PTE[size])); -} - -AlphaTLB::~AlphaTLB() -{ - if (table) - delete [] table; -} - -// look up an entry in the TLB -AlphaISA::PTE * -AlphaTLB::lookup(Addr vpn, uint8_t asn) const -{ - // assume not found... - AlphaISA::PTE *retval = NULL; - - PageTable::const_iterator i = lookupTable.find(vpn); - if (i != lookupTable.end()) { - while (i->first == vpn) { - int index = i->second; - AlphaISA::PTE *pte = &table[index]; - assert(pte->valid); - if (vpn == pte->tag && (pte->asma || pte->asn == asn)) { - retval = pte; - break; - } - - ++i; - } - } - - DPRINTF(TLB, "lookup %#x, asn %#x -> %s ppn %#x\n", vpn, (int)asn, - retval ? "hit" : "miss", retval ? retval->ppn : 0); - return retval; -} - - -void -AlphaTLB::checkCacheability(MemReqPtr &req) -{ - // in Alpha, cacheability is controlled by upper-level bits of the - // physical address - - /* - * We support having the uncacheable bit in either bit 39 or bit 40. - * The Turbolaser platform (and EV5) support having the bit in 39, but - * Tsunami (which Linux assumes uses an EV6) generates accesses with - * the bit in 40. So we must check for both, but we have debug flags - * to catch a weird case where both are used, which shouldn't happen. - */ - - -#if ALPHA_TLASER - if (req->paddr & PAddrUncachedBit39) { -#else - if (req->paddr & PAddrUncachedBit43) { -#endif - // IPR memory space not implemented - if (PAddrIprSpace(req->paddr)) { - if (!req->xc->misspeculating()) { - switch (req->paddr) { - case ULL(0xFFFFF00188): - req->data = 0; - break; - - default: - panic("IPR memory space not implemented! PA=%x\n", - req->paddr); - } - } - } else { - // mark request as uncacheable - req->flags |= UNCACHEABLE; - -#if !ALPHA_TLASER - // Clear bits 42:35 of the physical address (10-2 in Tsunami manual) - req->paddr &= PAddrUncachedMask; -#endif - } - } -} - - -// insert a new TLB entry -void -AlphaTLB::insert(Addr addr, AlphaISA::PTE &pte) -{ - AlphaISA::VAddr vaddr = addr; - if (table[nlu].valid) { - Addr oldvpn = table[nlu].tag; - PageTable::iterator i = lookupTable.find(oldvpn); - - if (i == lookupTable.end()) - panic("TLB entry not found in lookupTable"); - - int index; - while ((index = i->second) != nlu) { - if (table[index].tag != oldvpn) - panic("TLB entry not found in lookupTable"); - - ++i; - } - - DPRINTF(TLB, "remove @%d: %#x -> %#x\n", nlu, oldvpn, table[nlu].ppn); - - lookupTable.erase(i); - } - - DPRINTF(TLB, "insert @%d: %#x -> %#x\n", nlu, vaddr.vpn(), pte.ppn); - - table[nlu] = pte; - table[nlu].tag = vaddr.vpn(); - table[nlu].valid = true; - - lookupTable.insert(make_pair(vaddr.vpn(), nlu)); - nextnlu(); -} - -void -AlphaTLB::flushAll() -{ - DPRINTF(TLB, "flushAll\n"); - memset(table, 0, sizeof(AlphaISA::PTE[size])); - lookupTable.clear(); - nlu = 0; -} - -void -AlphaTLB::flushProcesses() -{ - PageTable::iterator i = lookupTable.begin(); - PageTable::iterator end = lookupTable.end(); - while (i != end) { - int index = i->second; - AlphaISA::PTE *pte = &table[index]; - assert(pte->valid); - - // we can't increment i after we erase it, so save a copy and - // increment it to get the next entry now - PageTable::iterator cur = i; - ++i; - - if (!pte->asma) { - DPRINTF(TLB, "flush @%d: %#x -> %#x\n", index, pte->tag, pte->ppn); - pte->valid = false; - lookupTable.erase(cur); - } - } -} - -void -AlphaTLB::flushAddr(Addr addr, uint8_t asn) -{ - AlphaISA::VAddr vaddr = addr; - - PageTable::iterator i = lookupTable.find(vaddr.vpn()); - if (i == lookupTable.end()) - return; - - while (i->first == vaddr.vpn()) { - int index = i->second; - AlphaISA::PTE *pte = &table[index]; - assert(pte->valid); - - if (vaddr.vpn() == pte->tag && (pte->asma || pte->asn == asn)) { - DPRINTF(TLB, "flushaddr @%d: %#x -> %#x\n", index, vaddr.vpn(), - pte->ppn); - - // invalidate this entry - pte->valid = false; - - lookupTable.erase(i); - } - - ++i; - } -} - - -void -AlphaTLB::serialize(ostream &os) -{ - SERIALIZE_SCALAR(size); - SERIALIZE_SCALAR(nlu); - - for (int i = 0; i < size; i++) { - nameOut(os, csprintf("%s.PTE%d", name(), i)); - table[i].serialize(os); - } -} - -void -AlphaTLB::unserialize(Checkpoint *cp, const string §ion) -{ - UNSERIALIZE_SCALAR(size); - UNSERIALIZE_SCALAR(nlu); - - for (int i = 0; i < size; i++) { - table[i].unserialize(cp, csprintf("%s.PTE%d", section, i)); - if (table[i].valid) { - lookupTable.insert(make_pair(table[i].tag, i)); - } - } -} - - -/////////////////////////////////////////////////////////////////////// -// -// Alpha ITB -// -AlphaITB::AlphaITB(const std::string &name, int size) - : AlphaTLB(name, size) -{} - - -void -AlphaITB::regStats() -{ - hits - .name(name() + ".hits") - .desc("ITB hits"); - misses - .name(name() + ".misses") - .desc("ITB misses"); - acv - .name(name() + ".acv") - .desc("ITB acv"); - accesses - .name(name() + ".accesses") - .desc("ITB accesses"); - - accesses = hits + misses; -} - - -Fault -AlphaITB::translate(MemReqPtr &req) const -{ - ExecContext *xc = req->xc; - - if (AlphaISA::PcPAL(req->vaddr)) { - // strip off PAL PC marker (lsb is 1) - req->paddr = (req->vaddr & ~3) & PAddrImplMask; - hits++; - return NoFault; - } - - if (req->flags & PHYSICAL) { - req->paddr = req->vaddr; - } else { - // verify that this is a good virtual address - if (!validVirtualAddress(req->vaddr)) { - acv++; - return new ItbAcvFault(req->vaddr); - } - - - // VA<42:41> == 2, VA<39:13> maps directly to PA<39:13> for EV5 - // VA<47:41> == 0x7e, VA<40:13> maps directly to PA<40:13> for EV6 -#if ALPHA_TLASER - if ((MCSR_SP(xc->readMiscReg(AlphaISA::IPR_MCSR)) & 2) && - VAddrSpaceEV5(req->vaddr) == 2) { -#else - if (VAddrSpaceEV6(req->vaddr) == 0x7e) { -#endif - // only valid in kernel mode - if (ICM_CM(xc->readMiscReg(AlphaISA::IPR_ICM)) != - AlphaISA::mode_kernel) { - acv++; - return new ItbAcvFault(req->vaddr); - } - - req->paddr = req->vaddr & PAddrImplMask; - -#if !ALPHA_TLASER - // sign extend the physical address properly - if (req->paddr & PAddrUncachedBit40) - req->paddr |= ULL(0xf0000000000); - else - req->paddr &= ULL(0xffffffffff); -#endif - - } else { - // not a physical address: need to look up pte - int asn = DTB_ASN_ASN(xc->readMiscReg(AlphaISA::IPR_DTB_ASN)); - AlphaISA::PTE *pte = lookup(AlphaISA::VAddr(req->vaddr).vpn(), - asn); - - if (!pte) { - misses++; - return new ItbPageFault(req->vaddr); - } - - req->paddr = (pte->ppn << AlphaISA::PageShift) + - (AlphaISA::VAddr(req->vaddr).offset() & ~3); - - // check permissions for this access - if (!(pte->xre & - (1 << ICM_CM(xc->readMiscReg(AlphaISA::IPR_ICM))))) { - // instruction access fault - acv++; - return new ItbAcvFault(req->vaddr); - } - - hits++; - } - } - - // check that the physical address is ok (catch bad physical addresses) - if (req->paddr & ~PAddrImplMask) - return genMachineCheckFault(); - - checkCacheability(req); - - return NoFault; -} - -/////////////////////////////////////////////////////////////////////// -// -// Alpha DTB -// -AlphaDTB::AlphaDTB(const std::string &name, int size) - : AlphaTLB(name, size) -{} - -void -AlphaDTB::regStats() -{ - read_hits - .name(name() + ".read_hits") - .desc("DTB read hits") - ; - - read_misses - .name(name() + ".read_misses") - .desc("DTB read misses") - ; - - read_acv - .name(name() + ".read_acv") - .desc("DTB read access violations") - ; - - read_accesses - .name(name() + ".read_accesses") - .desc("DTB read accesses") - ; - - write_hits - .name(name() + ".write_hits") - .desc("DTB write hits") - ; - - write_misses - .name(name() + ".write_misses") - .desc("DTB write misses") - ; - - write_acv - .name(name() + ".write_acv") - .desc("DTB write access violations") - ; - - write_accesses - .name(name() + ".write_accesses") - .desc("DTB write accesses") - ; - - hits - .name(name() + ".hits") - .desc("DTB hits") - ; - - misses - .name(name() + ".misses") - .desc("DTB misses") - ; - - acv - .name(name() + ".acv") - .desc("DTB access violations") - ; - - accesses - .name(name() + ".accesses") - .desc("DTB accesses") - ; - - hits = read_hits + write_hits; - misses = read_misses + write_misses; - acv = read_acv + write_acv; - accesses = read_accesses + write_accesses; -} - -Fault -AlphaDTB::translate(MemReqPtr &req, bool write) const -{ - ExecContext *xc = req->xc; - Addr pc = xc->readPC(); - - AlphaISA::mode_type mode = - (AlphaISA::mode_type)DTB_CM_CM(xc->readMiscReg(AlphaISA::IPR_DTB_CM)); - - - /** - * Check for alignment faults - */ - if (req->vaddr & (req->size - 1)) { - DPRINTF(TLB, "Alignment Fault on %#x, size = %d", req->vaddr, - req->size); - uint64_t flags = write ? MM_STAT_WR_MASK : 0; - return new DtbAlignmentFault(req->vaddr, req->flags, flags); - } - - if (pc & 0x1) { - mode = (req->flags & ALTMODE) ? - (AlphaISA::mode_type)ALT_MODE_AM( - xc->readMiscReg(AlphaISA::IPR_ALT_MODE)) - : AlphaISA::mode_kernel; - } - - if (req->flags & PHYSICAL) { - req->paddr = req->vaddr; - } else { - // verify that this is a good virtual address - if (!validVirtualAddress(req->vaddr)) { - if (write) { write_acv++; } else { read_acv++; } - uint64_t flags = (write ? MM_STAT_WR_MASK : 0) | - MM_STAT_BAD_VA_MASK | - MM_STAT_ACV_MASK; - return new DtbPageFault(req->vaddr, req->flags, flags); - } - - // Check for "superpage" mapping -#if ALPHA_TLASER - if ((MCSR_SP(xc->readMiscReg(AlphaISA::IPR_MCSR)) & 2) && - VAddrSpaceEV5(req->vaddr) == 2) { -#else - if (VAddrSpaceEV6(req->vaddr) == 0x7e) { -#endif - - // only valid in kernel mode - if (DTB_CM_CM(xc->readMiscReg(AlphaISA::IPR_DTB_CM)) != - AlphaISA::mode_kernel) { - if (write) { write_acv++; } else { read_acv++; } - uint64_t flags = ((write ? MM_STAT_WR_MASK : 0) | - MM_STAT_ACV_MASK); - return new DtbAcvFault(req->vaddr, req->flags, flags); - } - - req->paddr = req->vaddr & PAddrImplMask; - -#if !ALPHA_TLASER - // sign extend the physical address properly - if (req->paddr & PAddrUncachedBit40) - req->paddr |= ULL(0xf0000000000); - else - req->paddr &= ULL(0xffffffffff); -#endif - - } else { - if (write) - write_accesses++; - else - read_accesses++; - - int asn = DTB_ASN_ASN(xc->readMiscReg(AlphaISA::IPR_DTB_ASN)); - - // not a physical address: need to look up pte - AlphaISA::PTE *pte = lookup(AlphaISA::VAddr(req->vaddr).vpn(), - asn); - - if (!pte) { - // page fault - if (write) { write_misses++; } else { read_misses++; } - uint64_t flags = (write ? MM_STAT_WR_MASK : 0) | - MM_STAT_DTB_MISS_MASK; - return (req->flags & VPTE) ? - (Fault)(new PDtbMissFault(req->vaddr, req->flags, - flags)) : - (Fault)(new NDtbMissFault(req->vaddr, req->flags, - flags)); - } - - req->paddr = (pte->ppn << AlphaISA::PageShift) + - AlphaISA::VAddr(req->vaddr).offset(); - - if (write) { - if (!(pte->xwe & MODE2MASK(mode))) { - // declare the instruction access fault - write_acv++; - uint64_t flags = MM_STAT_WR_MASK | - MM_STAT_ACV_MASK | - (pte->fonw ? MM_STAT_FONW_MASK : 0); - return new DtbPageFault(req->vaddr, req->flags, flags); - } - if (pte->fonw) { - write_acv++; - uint64_t flags = MM_STAT_WR_MASK | - MM_STAT_FONW_MASK; - return new DtbPageFault(req->vaddr, req->flags, flags); - } - } else { - if (!(pte->xre & MODE2MASK(mode))) { - read_acv++; - uint64_t flags = MM_STAT_ACV_MASK | - (pte->fonr ? MM_STAT_FONR_MASK : 0); - return new DtbAcvFault(req->vaddr, req->flags, flags); - } - if (pte->fonr) { - read_acv++; - uint64_t flags = MM_STAT_FONR_MASK; - return new DtbPageFault(req->vaddr, req->flags, flags); - } - } - } - - if (write) - write_hits++; - else - read_hits++; - } - - // check that the physical address is ok (catch bad physical addresses) - if (req->paddr & ~PAddrImplMask) - return genMachineCheckFault(); - - checkCacheability(req); - - return NoFault; -} - -AlphaISA::PTE & -AlphaTLB::index(bool advance) -{ - AlphaISA::PTE *pte = &table[nlu]; - - if (advance) - nextnlu(); - - return *pte; -} - -DEFINE_SIM_OBJECT_CLASS_NAME("AlphaTLB", AlphaTLB) - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaITB) - - Param<int> size; - -END_DECLARE_SIM_OBJECT_PARAMS(AlphaITB) - -BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaITB) - - INIT_PARAM_DFLT(size, "TLB size", 48) - -END_INIT_SIM_OBJECT_PARAMS(AlphaITB) - - -CREATE_SIM_OBJECT(AlphaITB) -{ - return new AlphaITB(getInstanceName(), size); -} - -REGISTER_SIM_OBJECT("AlphaITB", AlphaITB) - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaDTB) - - Param<int> size; - -END_DECLARE_SIM_OBJECT_PARAMS(AlphaDTB) - -BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaDTB) - - INIT_PARAM_DFLT(size, "TLB size", 64) - -END_INIT_SIM_OBJECT_PARAMS(AlphaDTB) - - -CREATE_SIM_OBJECT(AlphaDTB) -{ - return new AlphaDTB(getInstanceName(), size); -} - -REGISTER_SIM_OBJECT("AlphaDTB", AlphaDTB) - diff --git a/arch/alpha/tlb.hh b/arch/alpha/tlb.hh deleted file mode 100644 index 676345f01..000000000 --- a/arch/alpha/tlb.hh +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (c) 2001-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __ALPHA_MEMORY_HH__ -#define __ALPHA_MEMORY_HH__ - -#include <map> - -#include "arch/alpha/ev5.hh" -#include "arch/alpha/isa_traits.hh" -#include "arch/alpha/faults.hh" -#include "base/statistics.hh" -#include "mem/mem_req.hh" -#include "sim/sim_object.hh" - -class ExecContext; - -class AlphaTLB : public SimObject -{ - protected: - typedef std::multimap<Addr, int> PageTable; - PageTable lookupTable; // Quick lookup into page table - - AlphaISA::PTE *table; // the Page Table - int size; // TLB Size - int nlu; // not last used entry (for replacement) - - void nextnlu() { if (++nlu >= size) nlu = 0; } - AlphaISA::PTE *lookup(Addr vpn, uint8_t asn) const; - - public: - AlphaTLB(const std::string &name, int size); - virtual ~AlphaTLB(); - - int getsize() const { return size; } - - AlphaISA::PTE &index(bool advance = true); - void insert(Addr vaddr, AlphaISA::PTE &pte); - - void flushAll(); - void flushProcesses(); - void flushAddr(Addr addr, uint8_t asn); - - // static helper functions... really EV5 VM traits - static bool validVirtualAddress(Addr vaddr) { - // unimplemented bits must be all 0 or all 1 - Addr unimplBits = vaddr & EV5::VAddrUnImplMask; - return (unimplBits == 0) || (unimplBits == EV5::VAddrUnImplMask); - } - - static void checkCacheability(MemReqPtr &req); - - // Checkpointing - virtual void serialize(std::ostream &os); - virtual void unserialize(Checkpoint *cp, const std::string §ion); -}; - -class AlphaITB : public AlphaTLB -{ - protected: - mutable Stats::Scalar<> hits; - mutable Stats::Scalar<> misses; - mutable Stats::Scalar<> acv; - mutable Stats::Formula accesses; - - public: - AlphaITB(const std::string &name, int size); - virtual void regStats(); - - Fault translate(MemReqPtr &req) const; -}; - -class AlphaDTB : public AlphaTLB -{ - protected: - mutable Stats::Scalar<> read_hits; - mutable Stats::Scalar<> read_misses; - mutable Stats::Scalar<> read_acv; - mutable Stats::Scalar<> read_accesses; - mutable Stats::Scalar<> write_hits; - mutable Stats::Scalar<> write_misses; - mutable Stats::Scalar<> write_acv; - mutable Stats::Scalar<> write_accesses; - Stats::Formula hits; - Stats::Formula misses; - Stats::Formula acv; - Stats::Formula accesses; - - public: - AlphaDTB(const std::string &name, int size); - virtual void regStats(); - - Fault translate(MemReqPtr &req, bool write) const; -}; - -#endif // __ALPHA_MEMORY_HH__ diff --git a/arch/alpha/tru64/process.cc b/arch/alpha/tru64/process.cc deleted file mode 100644 index ae83bb649..000000000 --- a/arch/alpha/tru64/process.cc +++ /dev/null @@ -1,542 +0,0 @@ -/* - * Copyright (c) 2001-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "arch/alpha/isa_traits.hh" -#include "arch/alpha/tru64/process.hh" -#include "cpu/exec_context.hh" -#include "kern/tru64/tru64.hh" -#include "mem/functional/functional.hh" -#include "sim/process.hh" -#include "sim/syscall_emul.hh" - -using namespace std; -using namespace AlphaISA; - -/// Target uname() handler. -static SyscallReturn -unameFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - TypedBufferArg<Tru64::utsname> name(xc->getSyscallArg(0)); - - strcpy(name->sysname, "OSF1"); - strcpy(name->nodename, "m5.eecs.umich.edu"); - strcpy(name->release, "V5.1"); - strcpy(name->version, "732"); - strcpy(name->machine, "alpha"); - - name.copyOut(xc->getMemPtr()); - return 0; -} - -/// Target getsysyinfo() handler. -static SyscallReturn -getsysinfoFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - unsigned op = xc->getSyscallArg(0); - unsigned nbytes = xc->getSyscallArg(2); - - switch (op) { - - case Tru64::GSI_MAX_CPU: { - TypedBufferArg<uint32_t> max_cpu(xc->getSyscallArg(1)); - *max_cpu = htog((uint32_t)process->numCpus()); - max_cpu.copyOut(xc->getMemPtr()); - return 1; - } - - case Tru64::GSI_CPUS_IN_BOX: { - TypedBufferArg<uint32_t> cpus_in_box(xc->getSyscallArg(1)); - *cpus_in_box = htog((uint32_t)process->numCpus()); - cpus_in_box.copyOut(xc->getMemPtr()); - return 1; - } - - case Tru64::GSI_PHYSMEM: { - TypedBufferArg<uint64_t> physmem(xc->getSyscallArg(1)); - *physmem = htog((uint64_t)1024 * 1024); // physical memory in KB - physmem.copyOut(xc->getMemPtr()); - return 1; - } - - case Tru64::GSI_CPU_INFO: { - TypedBufferArg<Tru64::cpu_info> infop(xc->getSyscallArg(1)); - - infop->current_cpu = htog(0); - infop->cpus_in_box = htog(process->numCpus()); - infop->cpu_type = htog(57); - infop->ncpus = htog(process->numCpus()); - uint64_t cpumask = (1 << process->numCpus()) - 1; - infop->cpus_present = infop->cpus_running = htog(cpumask); - infop->cpu_binding = htog(0); - infop->cpu_ex_binding = htog(0); - infop->mhz = htog(667); - - infop.copyOut(xc->getMemPtr()); - return 1; - } - - case Tru64::GSI_PROC_TYPE: { - TypedBufferArg<uint64_t> proc_type(xc->getSyscallArg(1)); - *proc_type = htog((uint64_t)11); - proc_type.copyOut(xc->getMemPtr()); - return 1; - } - - case Tru64::GSI_PLATFORM_NAME: { - BufferArg bufArg(xc->getSyscallArg(1), nbytes); - strncpy((char *)bufArg.bufferPtr(), - "COMPAQ Professional Workstation XP1000", - nbytes); - bufArg.copyOut(xc->getMemPtr()); - return 1; - } - - case Tru64::GSI_CLK_TCK: { - TypedBufferArg<uint64_t> clk_hz(xc->getSyscallArg(1)); - *clk_hz = htog((uint64_t)1024); - clk_hz.copyOut(xc->getMemPtr()); - return 1; - } - - default: - warn("getsysinfo: unknown op %d\n", op); - break; - } - - return 0; -} - -/// Target setsysyinfo() handler. -static SyscallReturn -setsysinfoFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - unsigned op = xc->getSyscallArg(0); - - switch (op) { - case Tru64::SSI_IEEE_FP_CONTROL: - warn("setsysinfo: ignoring ieee_set_fp_control() arg 0x%x\n", - xc->getSyscallArg(1)); - break; - - default: - warn("setsysinfo: unknown op %d\n", op); - break; - } - - return 0; -} - - -SyscallDesc AlphaTru64Process::syscallDescs[] = { - /* 0 */ SyscallDesc("syscall (#0)", Tru64::indirectSyscallFunc, - SyscallDesc::SuppressReturnValue), - /* 1 */ SyscallDesc("exit", exitFunc), - /* 2 */ SyscallDesc("fork", unimplementedFunc), - /* 3 */ SyscallDesc("read", readFunc), - /* 4 */ SyscallDesc("write", writeFunc), - /* 5 */ SyscallDesc("old_open", unimplementedFunc), - /* 6 */ SyscallDesc("close", closeFunc), - /* 7 */ SyscallDesc("wait4", unimplementedFunc), - /* 8 */ SyscallDesc("old_creat", unimplementedFunc), - /* 9 */ SyscallDesc("link", unimplementedFunc), - /* 10 */ SyscallDesc("unlink", unlinkFunc), - /* 11 */ SyscallDesc("execv", unimplementedFunc), - /* 12 */ SyscallDesc("chdir", unimplementedFunc), - /* 13 */ SyscallDesc("fchdir", unimplementedFunc), - /* 14 */ SyscallDesc("mknod", unimplementedFunc), - /* 15 */ SyscallDesc("chmod", unimplementedFunc), - /* 16 */ SyscallDesc("chown", unimplementedFunc), - /* 17 */ SyscallDesc("obreak", obreakFunc), - /* 18 */ SyscallDesc("pre_F64_getfsstat", unimplementedFunc), - /* 19 */ SyscallDesc("lseek", lseekFunc), - /* 20 */ SyscallDesc("getpid", getpidPseudoFunc), - /* 21 */ SyscallDesc("mount", unimplementedFunc), - /* 22 */ SyscallDesc("unmount", unimplementedFunc), - /* 23 */ SyscallDesc("setuid", setuidFunc), - /* 24 */ SyscallDesc("getuid", getuidPseudoFunc), - /* 25 */ SyscallDesc("exec_with_loader", unimplementedFunc), - /* 26 */ SyscallDesc("ptrace", unimplementedFunc), - /* 27 */ SyscallDesc("recvmsg", unimplementedFunc), - /* 28 */ SyscallDesc("sendmsg", unimplementedFunc), - /* 29 */ SyscallDesc("recvfrom", unimplementedFunc), - /* 30 */ SyscallDesc("accept", unimplementedFunc), - /* 31 */ SyscallDesc("getpeername", unimplementedFunc), - /* 32 */ SyscallDesc("getsockname", unimplementedFunc), - /* 33 */ SyscallDesc("access", unimplementedFunc), - /* 34 */ SyscallDesc("chflags", unimplementedFunc), - /* 35 */ SyscallDesc("fchflags", unimplementedFunc), - /* 36 */ SyscallDesc("sync", unimplementedFunc), - /* 37 */ SyscallDesc("kill", unimplementedFunc), - /* 38 */ SyscallDesc("old_stat", unimplementedFunc), - /* 39 */ SyscallDesc("setpgid", unimplementedFunc), - /* 40 */ SyscallDesc("old_lstat", unimplementedFunc), - /* 41 */ SyscallDesc("dup", unimplementedFunc), - /* 42 */ SyscallDesc("pipe", unimplementedFunc), - /* 43 */ SyscallDesc("set_program_attributes", unimplementedFunc), - /* 44 */ SyscallDesc("profil", unimplementedFunc), - /* 45 */ SyscallDesc("open", openFunc<Tru64>), - /* 46 */ SyscallDesc("obsolete osigaction", unimplementedFunc), - /* 47 */ SyscallDesc("getgid", getgidPseudoFunc), - /* 48 */ SyscallDesc("sigprocmask", ignoreFunc), - /* 49 */ SyscallDesc("getlogin", unimplementedFunc), - /* 50 */ SyscallDesc("setlogin", unimplementedFunc), - /* 51 */ SyscallDesc("acct", unimplementedFunc), - /* 52 */ SyscallDesc("sigpending", unimplementedFunc), - /* 53 */ SyscallDesc("classcntl", unimplementedFunc), - /* 54 */ SyscallDesc("ioctl", ioctlFunc<Tru64>), - /* 55 */ SyscallDesc("reboot", unimplementedFunc), - /* 56 */ SyscallDesc("revoke", unimplementedFunc), - /* 57 */ SyscallDesc("symlink", unimplementedFunc), - /* 58 */ SyscallDesc("readlink", unimplementedFunc), - /* 59 */ SyscallDesc("execve", unimplementedFunc), - /* 60 */ SyscallDesc("umask", unimplementedFunc), - /* 61 */ SyscallDesc("chroot", unimplementedFunc), - /* 62 */ SyscallDesc("old_fstat", unimplementedFunc), - /* 63 */ SyscallDesc("getpgrp", unimplementedFunc), - /* 64 */ SyscallDesc("getpagesize", getpagesizeFunc), - /* 65 */ SyscallDesc("mremap", unimplementedFunc), - /* 66 */ SyscallDesc("vfork", unimplementedFunc), - /* 67 */ SyscallDesc("pre_F64_stat", statFunc<Tru64::PreF64>), - /* 68 */ SyscallDesc("pre_F64_lstat", lstatFunc<Tru64::PreF64>), - /* 69 */ SyscallDesc("sbrk", unimplementedFunc), - /* 70 */ SyscallDesc("sstk", unimplementedFunc), - /* 71 */ SyscallDesc("mmap", mmapFunc<Tru64>), - /* 72 */ SyscallDesc("ovadvise", unimplementedFunc), - /* 73 */ SyscallDesc("munmap", munmapFunc), - /* 74 */ SyscallDesc("mprotect", ignoreFunc), - /* 75 */ SyscallDesc("madvise", unimplementedFunc), - /* 76 */ SyscallDesc("old_vhangup", unimplementedFunc), - /* 77 */ SyscallDesc("kmodcall", unimplementedFunc), - /* 78 */ SyscallDesc("mincore", unimplementedFunc), - /* 79 */ SyscallDesc("getgroups", unimplementedFunc), - /* 80 */ SyscallDesc("setgroups", unimplementedFunc), - /* 81 */ SyscallDesc("old_getpgrp", unimplementedFunc), - /* 82 */ SyscallDesc("setpgrp", unimplementedFunc), - /* 83 */ SyscallDesc("setitimer", unimplementedFunc), - /* 84 */ SyscallDesc("old_wait", unimplementedFunc), - /* 85 */ SyscallDesc("table", Tru64::tableFunc), - /* 86 */ SyscallDesc("getitimer", unimplementedFunc), - /* 87 */ SyscallDesc("gethostname", gethostnameFunc), - /* 88 */ SyscallDesc("sethostname", unimplementedFunc), - /* 89 */ SyscallDesc("getdtablesize", unimplementedFunc), - /* 90 */ SyscallDesc("dup2", unimplementedFunc), - /* 91 */ SyscallDesc("pre_F64_fstat", fstatFunc<Tru64::PreF64>), - /* 92 */ SyscallDesc("fcntl", fcntlFunc), - /* 93 */ SyscallDesc("select", unimplementedFunc), - /* 94 */ SyscallDesc("poll", unimplementedFunc), - /* 95 */ SyscallDesc("fsync", unimplementedFunc), - /* 96 */ SyscallDesc("setpriority", unimplementedFunc), - /* 97 */ SyscallDesc("socket", unimplementedFunc), - /* 98 */ SyscallDesc("connect", unimplementedFunc), - /* 99 */ SyscallDesc("old_accept", unimplementedFunc), - /* 100 */ SyscallDesc("getpriority", unimplementedFunc), - /* 101 */ SyscallDesc("old_send", unimplementedFunc), - /* 102 */ SyscallDesc("old_recv", unimplementedFunc), - /* 103 */ SyscallDesc("sigreturn", Tru64::sigreturnFunc, - SyscallDesc::SuppressReturnValue), - /* 104 */ SyscallDesc("bind", unimplementedFunc), - /* 105 */ SyscallDesc("setsockopt", unimplementedFunc), - /* 106 */ SyscallDesc("listen", unimplementedFunc), - /* 107 */ SyscallDesc("plock", unimplementedFunc), - /* 108 */ SyscallDesc("old_sigvec", unimplementedFunc), - /* 109 */ SyscallDesc("old_sigblock", unimplementedFunc), - /* 110 */ SyscallDesc("old_sigsetmask", unimplementedFunc), - /* 111 */ SyscallDesc("sigsuspend", unimplementedFunc), - /* 112 */ SyscallDesc("sigstack", ignoreFunc), - /* 113 */ SyscallDesc("old_recvmsg", unimplementedFunc), - /* 114 */ SyscallDesc("old_sendmsg", unimplementedFunc), - /* 115 */ SyscallDesc("obsolete vtrace", unimplementedFunc), - /* 116 */ SyscallDesc("gettimeofday", gettimeofdayFunc<Tru64>), - /* 117 */ SyscallDesc("getrusage", getrusageFunc<Tru64>), - /* 118 */ SyscallDesc("getsockopt", unimplementedFunc), - /* 119 */ SyscallDesc("numa_syscalls", unimplementedFunc), - /* 120 */ SyscallDesc("readv", unimplementedFunc), - /* 121 */ SyscallDesc("writev", unimplementedFunc), - /* 122 */ SyscallDesc("settimeofday", unimplementedFunc), - /* 123 */ SyscallDesc("fchown", unimplementedFunc), - /* 124 */ SyscallDesc("fchmod", unimplementedFunc), - /* 125 */ SyscallDesc("old_recvfrom", unimplementedFunc), - /* 126 */ SyscallDesc("setreuid", unimplementedFunc), - /* 127 */ SyscallDesc("setregid", unimplementedFunc), - /* 128 */ SyscallDesc("rename", renameFunc), - /* 129 */ SyscallDesc("truncate", truncateFunc), - /* 130 */ SyscallDesc("ftruncate", ftruncateFunc), - /* 131 */ SyscallDesc("flock", unimplementedFunc), - /* 132 */ SyscallDesc("setgid", unimplementedFunc), - /* 133 */ SyscallDesc("sendto", unimplementedFunc), - /* 134 */ SyscallDesc("shutdown", unimplementedFunc), - /* 135 */ SyscallDesc("socketpair", unimplementedFunc), - /* 136 */ SyscallDesc("mkdir", unimplementedFunc), - /* 137 */ SyscallDesc("rmdir", unimplementedFunc), - /* 138 */ SyscallDesc("utimes", unimplementedFunc), - /* 139 */ SyscallDesc("obsolete 4.2 sigreturn", unimplementedFunc), - /* 140 */ SyscallDesc("adjtime", unimplementedFunc), - /* 141 */ SyscallDesc("old_getpeername", unimplementedFunc), - /* 142 */ SyscallDesc("gethostid", unimplementedFunc), - /* 143 */ SyscallDesc("sethostid", unimplementedFunc), - /* 144 */ SyscallDesc("getrlimit", getrlimitFunc<Tru64>), - /* 145 */ SyscallDesc("setrlimit", ignoreFunc), - /* 146 */ SyscallDesc("old_killpg", unimplementedFunc), - /* 147 */ SyscallDesc("setsid", unimplementedFunc), - /* 148 */ SyscallDesc("quotactl", unimplementedFunc), - /* 149 */ SyscallDesc("oldquota", unimplementedFunc), - /* 150 */ SyscallDesc("old_getsockname", unimplementedFunc), - /* 151 */ SyscallDesc("pread", unimplementedFunc), - /* 152 */ SyscallDesc("pwrite", unimplementedFunc), - /* 153 */ SyscallDesc("pid_block", unimplementedFunc), - /* 154 */ SyscallDesc("pid_unblock", unimplementedFunc), - /* 155 */ SyscallDesc("signal_urti", unimplementedFunc), - /* 156 */ SyscallDesc("sigaction", ignoreFunc), - /* 157 */ SyscallDesc("sigwaitprim", unimplementedFunc), - /* 158 */ SyscallDesc("nfssvc", unimplementedFunc), - /* 159 */ SyscallDesc("getdirentries", Tru64::getdirentriesFunc), - /* 160 */ SyscallDesc("pre_F64_statfs", statfsFunc<Tru64::PreF64>), - /* 161 */ SyscallDesc("pre_F64_fstatfs", fstatfsFunc<Tru64::PreF64>), - /* 162 */ SyscallDesc("unknown #162", unimplementedFunc), - /* 163 */ SyscallDesc("async_daemon", unimplementedFunc), - /* 164 */ SyscallDesc("getfh", unimplementedFunc), - /* 165 */ SyscallDesc("getdomainname", unimplementedFunc), - /* 166 */ SyscallDesc("setdomainname", unimplementedFunc), - /* 167 */ SyscallDesc("unknown #167", unimplementedFunc), - /* 168 */ SyscallDesc("unknown #168", unimplementedFunc), - /* 169 */ SyscallDesc("exportfs", unimplementedFunc), - /* 170 */ SyscallDesc("unknown #170", unimplementedFunc), - /* 171 */ SyscallDesc("unknown #171", unimplementedFunc), - /* 172 */ SyscallDesc("unknown #172", unimplementedFunc), - /* 173 */ SyscallDesc("unknown #173", unimplementedFunc), - /* 174 */ SyscallDesc("unknown #174", unimplementedFunc), - /* 175 */ SyscallDesc("unknown #175", unimplementedFunc), - /* 176 */ SyscallDesc("unknown #176", unimplementedFunc), - /* 177 */ SyscallDesc("unknown #177", unimplementedFunc), - /* 178 */ SyscallDesc("unknown #178", unimplementedFunc), - /* 179 */ SyscallDesc("unknown #179", unimplementedFunc), - /* 180 */ SyscallDesc("unknown #180", unimplementedFunc), - /* 181 */ SyscallDesc("alt_plock", unimplementedFunc), - /* 182 */ SyscallDesc("unknown #182", unimplementedFunc), - /* 183 */ SyscallDesc("unknown #183", unimplementedFunc), - /* 184 */ SyscallDesc("getmnt", unimplementedFunc), - /* 185 */ SyscallDesc("unknown #185", unimplementedFunc), - /* 186 */ SyscallDesc("unknown #186", unimplementedFunc), - /* 187 */ SyscallDesc("alt_sigpending", unimplementedFunc), - /* 188 */ SyscallDesc("alt_setsid", unimplementedFunc), - /* 189 */ SyscallDesc("unknown #189", unimplementedFunc), - /* 190 */ SyscallDesc("unknown #190", unimplementedFunc), - /* 191 */ SyscallDesc("unknown #191", unimplementedFunc), - /* 192 */ SyscallDesc("unknown #192", unimplementedFunc), - /* 193 */ SyscallDesc("unknown #193", unimplementedFunc), - /* 194 */ SyscallDesc("unknown #194", unimplementedFunc), - /* 195 */ SyscallDesc("unknown #195", unimplementedFunc), - /* 196 */ SyscallDesc("unknown #196", unimplementedFunc), - /* 197 */ SyscallDesc("unknown #197", unimplementedFunc), - /* 198 */ SyscallDesc("unknown #198", unimplementedFunc), - /* 199 */ SyscallDesc("swapon", unimplementedFunc), - /* 200 */ SyscallDesc("msgctl", unimplementedFunc), - /* 201 */ SyscallDesc("msgget", unimplementedFunc), - /* 202 */ SyscallDesc("msgrcv", unimplementedFunc), - /* 203 */ SyscallDesc("msgsnd", unimplementedFunc), - /* 204 */ SyscallDesc("semctl", unimplementedFunc), - /* 205 */ SyscallDesc("semget", unimplementedFunc), - /* 206 */ SyscallDesc("semop", unimplementedFunc), - /* 207 */ SyscallDesc("uname", unameFunc), - /* 208 */ SyscallDesc("lchown", unimplementedFunc), - /* 209 */ SyscallDesc("shmat", unimplementedFunc), - /* 210 */ SyscallDesc("shmctl", unimplementedFunc), - /* 211 */ SyscallDesc("shmdt", unimplementedFunc), - /* 212 */ SyscallDesc("shmget", unimplementedFunc), - /* 213 */ SyscallDesc("mvalid", unimplementedFunc), - /* 214 */ SyscallDesc("getaddressconf", unimplementedFunc), - /* 215 */ SyscallDesc("msleep", unimplementedFunc), - /* 216 */ SyscallDesc("mwakeup", unimplementedFunc), - /* 217 */ SyscallDesc("msync", unimplementedFunc), - /* 218 */ SyscallDesc("signal", unimplementedFunc), - /* 219 */ SyscallDesc("utc_gettime", unimplementedFunc), - /* 220 */ SyscallDesc("utc_adjtime", unimplementedFunc), - /* 221 */ SyscallDesc("unknown #221", unimplementedFunc), - /* 222 */ SyscallDesc("security", unimplementedFunc), - /* 223 */ SyscallDesc("kloadcall", unimplementedFunc), - /* 224 */ SyscallDesc("stat", statFunc<Tru64::F64>), - /* 225 */ SyscallDesc("lstat", lstatFunc<Tru64::F64>), - /* 226 */ SyscallDesc("fstat", fstatFunc<Tru64::F64>), - /* 227 */ SyscallDesc("statfs", statfsFunc<Tru64::F64>), - /* 228 */ SyscallDesc("fstatfs", fstatfsFunc<Tru64::F64>), - /* 229 */ SyscallDesc("getfsstat", unimplementedFunc), - /* 230 */ SyscallDesc("gettimeofday64", unimplementedFunc), - /* 231 */ SyscallDesc("settimeofday64", unimplementedFunc), - /* 232 */ SyscallDesc("unknown #232", unimplementedFunc), - /* 233 */ SyscallDesc("getpgid", unimplementedFunc), - /* 234 */ SyscallDesc("getsid", unimplementedFunc), - /* 235 */ SyscallDesc("sigaltstack", ignoreFunc), - /* 236 */ SyscallDesc("waitid", unimplementedFunc), - /* 237 */ SyscallDesc("priocntlset", unimplementedFunc), - /* 238 */ SyscallDesc("sigsendset", unimplementedFunc), - /* 239 */ SyscallDesc("set_speculative", unimplementedFunc), - /* 240 */ SyscallDesc("msfs_syscall", unimplementedFunc), - /* 241 */ SyscallDesc("sysinfo", unimplementedFunc), - /* 242 */ SyscallDesc("uadmin", unimplementedFunc), - /* 243 */ SyscallDesc("fuser", unimplementedFunc), - /* 244 */ SyscallDesc("proplist_syscall", unimplementedFunc), - /* 245 */ SyscallDesc("ntp_adjtime", unimplementedFunc), - /* 246 */ SyscallDesc("ntp_gettime", unimplementedFunc), - /* 247 */ SyscallDesc("pathconf", unimplementedFunc), - /* 248 */ SyscallDesc("fpathconf", unimplementedFunc), - /* 249 */ SyscallDesc("sync2", unimplementedFunc), - /* 250 */ SyscallDesc("uswitch", unimplementedFunc), - /* 251 */ SyscallDesc("usleep_thread", unimplementedFunc), - /* 252 */ SyscallDesc("audcntl", unimplementedFunc), - /* 253 */ SyscallDesc("audgen", unimplementedFunc), - /* 254 */ SyscallDesc("sysfs", unimplementedFunc), - /* 255 */ SyscallDesc("subsys_info", unimplementedFunc), - /* 256 */ SyscallDesc("getsysinfo", getsysinfoFunc), - /* 257 */ SyscallDesc("setsysinfo", setsysinfoFunc), - /* 258 */ SyscallDesc("afs_syscall", unimplementedFunc), - /* 259 */ SyscallDesc("swapctl", unimplementedFunc), - /* 260 */ SyscallDesc("memcntl", unimplementedFunc), - /* 261 */ SyscallDesc("fdatasync", unimplementedFunc), - /* 262 */ SyscallDesc("oflock", unimplementedFunc), - /* 263 */ SyscallDesc("F64_readv", unimplementedFunc), - /* 264 */ SyscallDesc("F64_writev", unimplementedFunc), - /* 265 */ SyscallDesc("cdslxlate", unimplementedFunc), - /* 266 */ SyscallDesc("sendfile", unimplementedFunc), -}; - - - -SyscallDesc AlphaTru64Process::machSyscallDescs[] = { - /* 0 */ SyscallDesc("kern_invalid", unimplementedFunc), - /* 1 */ SyscallDesc("m5_mutex_lock", Tru64::m5_mutex_lockFunc), - /* 2 */ SyscallDesc("m5_mutex_trylock", Tru64::m5_mutex_trylockFunc), - /* 3 */ SyscallDesc("m5_mutex_unlock", Tru64::m5_mutex_unlockFunc), - /* 4 */ SyscallDesc("m5_cond_signal", Tru64::m5_cond_signalFunc), - /* 5 */ SyscallDesc("m5_cond_broadcast", Tru64::m5_cond_broadcastFunc), - /* 6 */ SyscallDesc("m5_cond_wait", Tru64::m5_cond_waitFunc), - /* 7 */ SyscallDesc("m5_thread_exit", Tru64::m5_thread_exitFunc), - /* 8 */ SyscallDesc("kern_invalid", unimplementedFunc), - /* 9 */ SyscallDesc("kern_invalid", unimplementedFunc), - /* 10 */ SyscallDesc("task_self", unimplementedFunc), - /* 11 */ SyscallDesc("thread_reply", unimplementedFunc), - /* 12 */ SyscallDesc("task_notify", unimplementedFunc), - /* 13 */ SyscallDesc("thread_self", unimplementedFunc), - /* 14 */ SyscallDesc("kern_invalid", unimplementedFunc), - /* 15 */ SyscallDesc("kern_invalid", unimplementedFunc), - /* 16 */ SyscallDesc("kern_invalid", unimplementedFunc), - /* 17 */ SyscallDesc("kern_invalid", unimplementedFunc), - /* 18 */ SyscallDesc("kern_invalid", unimplementedFunc), - /* 19 */ SyscallDesc("kern_invalid", unimplementedFunc), - /* 20 */ SyscallDesc("msg_send_trap", unimplementedFunc), - /* 21 */ SyscallDesc("msg_receive_trap", unimplementedFunc), - /* 22 */ SyscallDesc("msg_rpc_trap", unimplementedFunc), - /* 23 */ SyscallDesc("kern_invalid", unimplementedFunc), - /* 24 */ SyscallDesc("nxm_block", Tru64::nxm_blockFunc), - /* 25 */ SyscallDesc("nxm_unblock", Tru64::nxm_unblockFunc), - /* 26 */ SyscallDesc("kern_invalid", unimplementedFunc), - /* 27 */ SyscallDesc("kern_invalid", unimplementedFunc), - /* 28 */ SyscallDesc("kern_invalid", unimplementedFunc), - /* 29 */ SyscallDesc("nxm_thread_destroy", unimplementedFunc), - /* 30 */ SyscallDesc("lw_wire", unimplementedFunc), - /* 31 */ SyscallDesc("lw_unwire", unimplementedFunc), - /* 32 */ SyscallDesc("nxm_thread_create", Tru64::nxm_thread_createFunc), - /* 33 */ SyscallDesc("nxm_task_init", Tru64::nxm_task_initFunc), - /* 34 */ SyscallDesc("kern_invalid", unimplementedFunc), - /* 35 */ SyscallDesc("nxm_idle", Tru64::nxm_idleFunc), - /* 36 */ SyscallDesc("nxm_wakeup_idle", unimplementedFunc), - /* 37 */ SyscallDesc("nxm_set_pthid", unimplementedFunc), - /* 38 */ SyscallDesc("nxm_thread_kill", unimplementedFunc), - /* 39 */ SyscallDesc("nxm_thread_block", Tru64::nxm_thread_blockFunc), - /* 40 */ SyscallDesc("nxm_thread_wakeup", unimplementedFunc), - /* 41 */ SyscallDesc("init_process", unimplementedFunc), - /* 42 */ SyscallDesc("nxm_get_binding", unimplementedFunc), - /* 43 */ SyscallDesc("map_fd", unimplementedFunc), - /* 44 */ SyscallDesc("nxm_resched", unimplementedFunc), - /* 45 */ SyscallDesc("nxm_set_cancel", unimplementedFunc), - /* 46 */ SyscallDesc("nxm_set_binding", unimplementedFunc), - /* 47 */ SyscallDesc("stack_create", Tru64::stack_createFunc), - /* 48 */ SyscallDesc("nxm_get_state", unimplementedFunc), - /* 49 */ SyscallDesc("nxm_thread_suspend", unimplementedFunc), - /* 50 */ SyscallDesc("nxm_thread_resume", unimplementedFunc), - /* 51 */ SyscallDesc("nxm_signal_check", unimplementedFunc), - /* 52 */ SyscallDesc("htg_unix_syscall", unimplementedFunc), - /* 53 */ SyscallDesc("kern_invalid", unimplementedFunc), - /* 54 */ SyscallDesc("kern_invalid", unimplementedFunc), - /* 55 */ SyscallDesc("host_self", unimplementedFunc), - /* 56 */ SyscallDesc("host_priv_self", unimplementedFunc), - /* 57 */ SyscallDesc("kern_invalid", unimplementedFunc), - /* 58 */ SyscallDesc("kern_invalid", unimplementedFunc), - /* 59 */ SyscallDesc("swtch_pri", Tru64::swtch_priFunc), - /* 60 */ SyscallDesc("swtch", unimplementedFunc), - /* 61 */ SyscallDesc("thread_switch", unimplementedFunc), - /* 62 */ SyscallDesc("semop_fast", unimplementedFunc), - /* 63 */ SyscallDesc("nxm_pshared_init", unimplementedFunc), - /* 64 */ SyscallDesc("nxm_pshared_block", unimplementedFunc), - /* 65 */ SyscallDesc("nxm_pshared_unblock", unimplementedFunc), - /* 66 */ SyscallDesc("nxm_pshared_destroy", unimplementedFunc), - /* 67 */ SyscallDesc("nxm_swtch_pri", Tru64::swtch_priFunc), - /* 68 */ SyscallDesc("lw_syscall", unimplementedFunc), - /* 69 */ SyscallDesc("kern_invalid", unimplementedFunc), - /* 70 */ SyscallDesc("mach_sctimes_0", unimplementedFunc), - /* 71 */ SyscallDesc("mach_sctimes_1", unimplementedFunc), - /* 72 */ SyscallDesc("mach_sctimes_2", unimplementedFunc), - /* 73 */ SyscallDesc("mach_sctimes_3", unimplementedFunc), - /* 74 */ SyscallDesc("mach_sctimes_4", unimplementedFunc), - /* 75 */ SyscallDesc("mach_sctimes_5", unimplementedFunc), - /* 76 */ SyscallDesc("mach_sctimes_6", unimplementedFunc), - /* 77 */ SyscallDesc("mach_sctimes_7", unimplementedFunc), - /* 78 */ SyscallDesc("mach_sctimes_8", unimplementedFunc), - /* 79 */ SyscallDesc("mach_sctimes_9", unimplementedFunc), - /* 80 */ SyscallDesc("mach_sctimes_10", unimplementedFunc), - /* 81 */ SyscallDesc("mach_sctimes_11", unimplementedFunc), - /* 82 */ SyscallDesc("mach_sctimes_port_alloc_dealloc", unimplementedFunc) -}; - -SyscallDesc* -AlphaTru64Process::getDesc(int callnum) -{ - if (callnum < -Num_Mach_Syscall_Descs || callnum > Num_Syscall_Descs) - return NULL; - - if (callnum < 0) - return &machSyscallDescs[-callnum]; - else - return &syscallDescs[callnum]; -} - - -AlphaTru64Process::AlphaTru64Process(const std::string &name, - ObjectFile *objFile, - int stdin_fd, - int stdout_fd, - int stderr_fd, - std::vector<std::string> &argv, - std::vector<std::string> &envp) - : LiveProcess(name, objFile, stdin_fd, stdout_fd, stderr_fd, argv, envp), - Num_Syscall_Descs(sizeof(syscallDescs) / sizeof(SyscallDesc)), - Num_Mach_Syscall_Descs(sizeof(machSyscallDescs) / sizeof(SyscallDesc)) -{ -} diff --git a/arch/alpha/tru64/process.hh b/arch/alpha/tru64/process.hh deleted file mode 100644 index 051760702..000000000 --- a/arch/alpha/tru64/process.hh +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2003-2004 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __ALPHA_TRU64_PROCESS_HH__ -#define __ALPHA_TRU64_PROCESS_HH__ - -#include "sim/process.hh" - -/// A process with emulated Alpha Tru64 syscalls. -class AlphaTru64Process : public LiveProcess -{ - public: - /// Constructor. - AlphaTru64Process(const std::string &name, - ObjectFile *objFile, - int stdin_fd, int stdout_fd, int stderr_fd, - std::vector<std::string> &argv, - std::vector<std::string> &envp); - - /// Array of syscall descriptors, indexed by call number. - static SyscallDesc syscallDescs[]; - - /// Array of mach syscall descriptors, indexed by call number. - static SyscallDesc machSyscallDescs[]; - - const int Num_Syscall_Descs; - const int Num_Mach_Syscall_Descs; - - virtual SyscallDesc* getDesc(int callnum); -}; - - -#endif // __ALPHA_TRU64_PROCESS_HH__ diff --git a/arch/alpha/tru64/system.cc b/arch/alpha/tru64/system.cc deleted file mode 100644 index d09a0c85d..000000000 --- a/arch/alpha/tru64/system.cc +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "arch/alpha/tru64/system.hh" -#include "arch/isa_traits.hh" -#include "arch/vtophys.hh" -#include "base/loader/symtab.hh" -#include "base/trace.hh" -#include "cpu/base.hh" -#include "cpu/exec_context.hh" -#include "kern/tru64/tru64_events.hh" -#include "kern/system_events.hh" -#include "mem/functional/memory_control.hh" -#include "mem/functional/physical.hh" -#include "sim/builder.hh" - -using namespace std; - -Tru64AlphaSystem::Tru64AlphaSystem(Tru64AlphaSystem::Params *p) - : AlphaSystem(p) -{ - Addr addr = 0; - if (kernelSymtab->findAddress("enable_async_printf", addr)) { - Addr paddr = vtophys(physmem, addr); - uint8_t *enable_async_printf = - physmem->dma_addr(paddr, sizeof(uint32_t)); - - if (enable_async_printf) - *(uint32_t *)enable_async_printf = 0; - } - -#ifdef DEBUG - kernelPanicEvent = addKernelFuncEvent<BreakPCEvent>("panic"); - if (!kernelPanicEvent) - panic("could not find kernel symbol \'panic\'"); -#endif - - badaddrEvent = addKernelFuncEvent<BadAddrEvent>("badaddr"); - if (!badaddrEvent) - panic("could not find kernel symbol \'badaddr\'"); - - skipPowerStateEvent = - addKernelFuncEvent<SkipFuncEvent>("tl_v48_capture_power_state"); - skipScavengeBootEvent = - addKernelFuncEvent<SkipFuncEvent>("pmap_scavenge_boot"); - -#if TRACING_ON - printfEvent = addKernelFuncEvent<PrintfEvent>("printf"); - debugPrintfEvent = addKernelFuncEvent<DebugPrintfEvent>("m5printf"); - debugPrintfrEvent = addKernelFuncEvent<DebugPrintfrEvent>("m5printfr"); - dumpMbufEvent = addKernelFuncEvent<DumpMbufEvent>("m5_dump_mbuf"); -#endif -} - -Tru64AlphaSystem::~Tru64AlphaSystem() -{ -#ifdef DEBUG - delete kernelPanicEvent; -#endif - delete badaddrEvent; - delete skipPowerStateEvent; - delete skipScavengeBootEvent; -#if TRACING_ON - delete printfEvent; - delete debugPrintfEvent; - delete debugPrintfrEvent; - delete dumpMbufEvent; -#endif -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(Tru64AlphaSystem) - - Param<Tick> boot_cpu_frequency; - SimObjectParam<MemoryController *> memctrl; - SimObjectParam<PhysicalMemory *> physmem; - - Param<string> kernel; - Param<string> console; - Param<string> pal; - - Param<string> boot_osflags; - Param<string> readfile; - Param<unsigned int> init_param; - - Param<uint64_t> system_type; - Param<uint64_t> system_rev; - - Param<bool> bin; - VectorParam<string> binned_fns; - -END_DECLARE_SIM_OBJECT_PARAMS(Tru64AlphaSystem) - -BEGIN_INIT_SIM_OBJECT_PARAMS(Tru64AlphaSystem) - - INIT_PARAM(boot_cpu_frequency, "frequency of the boot cpu"), - INIT_PARAM(memctrl, "memory controller"), - INIT_PARAM(physmem, "phsyical memory"), - INIT_PARAM(kernel, "file that contains the kernel code"), - INIT_PARAM(console, "file that contains the console code"), - INIT_PARAM(pal, "file that contains palcode"), - INIT_PARAM_DFLT(boot_osflags, "flags to pass to the kernel during boot", - "a"), - INIT_PARAM_DFLT(readfile, "file to read startup script from", ""), - INIT_PARAM_DFLT(init_param, "numerical value to pass into simulator", 0), - INIT_PARAM_DFLT(system_type, "Type of system we are emulating", 12), - INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 2<<1), - INIT_PARAM_DFLT(bin, "is this system to be binned", false), - INIT_PARAM(binned_fns, "functions to be broken down and binned") - -END_INIT_SIM_OBJECT_PARAMS(Tru64AlphaSystem) - -CREATE_SIM_OBJECT(Tru64AlphaSystem) -{ - AlphaSystem::Params *p = new AlphaSystem::Params; - p->name = getInstanceName(); - p->boot_cpu_frequency = boot_cpu_frequency; - p->memctrl = memctrl; - p->physmem = physmem; - p->kernel_path = kernel; - p->console_path = console; - p->palcode = pal; - p->boot_osflags = boot_osflags; - p->init_param = init_param; - p->readfile = readfile; - p->system_type = system_type; - p->system_rev = system_rev; - p->bin = bin; - p->binned_fns = binned_fns; - p->bin_int = false; - - return new Tru64AlphaSystem(p); -} - -REGISTER_SIM_OBJECT("Tru64AlphaSystem", Tru64AlphaSystem) diff --git a/arch/alpha/vtophys.cc b/arch/alpha/vtophys.cc deleted file mode 100644 index 40261426d..000000000 --- a/arch/alpha/vtophys.cc +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright (c) 2002-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <string> - -#include "arch/alpha/vtophys.hh" -#include "base/trace.hh" -#include "cpu/exec_context.hh" -#include "mem/functional/physical.hh" - -using namespace std; -using namespace AlphaISA; - -AlphaISA::PageTableEntry -kernel_pte_lookup(PhysicalMemory *pmem, Addr ptbr, AlphaISA::VAddr vaddr) -{ - Addr level1_pte = ptbr + vaddr.level1(); - AlphaISA::PageTableEntry level1 = pmem->phys_read_qword(level1_pte); - if (!level1.valid()) { - DPRINTF(VtoPhys, "level 1 PTE not valid, va = %#\n", vaddr); - return 0; - } - - Addr level2_pte = level1.paddr() + vaddr.level2(); - AlphaISA::PageTableEntry level2 = pmem->phys_read_qword(level2_pte); - if (!level2.valid()) { - DPRINTF(VtoPhys, "level 2 PTE not valid, va = %#x\n", vaddr); - return 0; - } - - Addr level3_pte = level2.paddr() + vaddr.level3(); - AlphaISA::PageTableEntry level3 = pmem->phys_read_qword(level3_pte); - if (!level3.valid()) { - DPRINTF(VtoPhys, "level 3 PTE not valid, va = %#x\n", vaddr); - return 0; - } - return level3; -} - -Addr -vtophys(PhysicalMemory *xc, Addr vaddr) -{ - Addr paddr = 0; - if (AlphaISA::IsUSeg(vaddr)) - DPRINTF(VtoPhys, "vtophys: invalid vaddr %#x", vaddr); - else if (AlphaISA::IsK0Seg(vaddr)) - paddr = AlphaISA::K0Seg2Phys(vaddr); - else - panic("vtophys: ptbr is not set on virtual lookup"); - - DPRINTF(VtoPhys, "vtophys(%#x) -> %#x\n", vaddr, paddr); - - return paddr; -} - -Addr -vtophys(ExecContext *xc, Addr addr) -{ - AlphaISA::VAddr vaddr = addr; - Addr ptbr = xc->readMiscReg(AlphaISA::IPR_PALtemp20); - Addr paddr = 0; - //@todo Andrew couldn't remember why he commented some of this code - //so I put it back in. Perhaps something to do with gdb debugging? - if (AlphaISA::PcPAL(vaddr) && (vaddr < EV5::PalMax)) { - paddr = vaddr & ~ULL(1); - } else { - if (AlphaISA::IsK0Seg(vaddr)) { - paddr = AlphaISA::K0Seg2Phys(vaddr); - } else if (!ptbr) { - paddr = vaddr; - } else { - AlphaISA::PageTableEntry pte = - kernel_pte_lookup(xc->getPhysMemPtr(), ptbr, vaddr); - if (pte.valid()) - paddr = pte.paddr() | vaddr.offset(); - } - } - - - DPRINTF(VtoPhys, "vtophys(%#x) -> %#x\n", vaddr, paddr); - - return paddr; -} - -uint8_t * -ptomem(ExecContext *xc, Addr paddr, size_t len) -{ - return xc->getPhysMemPtr()->dma_addr(paddr, len); -} - -uint8_t * -vtomem(ExecContext *xc, Addr vaddr, size_t len) -{ - Addr paddr = vtophys(xc, vaddr); - return xc->getPhysMemPtr()->dma_addr(paddr, len); -} - -void -CopyOut(ExecContext *xc, void *dest, Addr src, size_t cplen) -{ - Addr paddr; - char *dmaaddr; - char *dst = (char *)dest; - int len; - - paddr = vtophys(xc, src); - len = min((int)(AlphaISA::PageBytes - (paddr & AlphaISA::PageOffset)), - (int)cplen); - dmaaddr = (char *)xc->getPhysMemPtr()->dma_addr(paddr, len); - assert(dmaaddr); - - memcpy(dst, dmaaddr, len); - if (len == cplen) - return; - - cplen -= len; - dst += len; - src += len; - - while (cplen > AlphaISA::PageBytes) { - paddr = vtophys(xc, src); - dmaaddr = (char *)xc->getPhysMemPtr()->dma_addr(paddr, - AlphaISA::PageBytes); - assert(dmaaddr); - - memcpy(dst, dmaaddr, AlphaISA::PageBytes); - cplen -= AlphaISA::PageBytes; - dst += AlphaISA::PageBytes; - src += AlphaISA::PageBytes; - } - - if (cplen > 0) { - paddr = vtophys(xc, src); - dmaaddr = (char *)xc->getPhysMemPtr()->dma_addr(paddr, cplen); - assert(dmaaddr); - - memcpy(dst, dmaaddr, cplen); - } -} - -void -CopyIn(ExecContext *xc, Addr dest, void *source, size_t cplen) -{ - Addr paddr; - char *dmaaddr; - char *src = (char *)source; - int len; - - paddr = vtophys(xc, dest); - len = min((int)(AlphaISA::PageBytes - (paddr & AlphaISA::PageOffset)), - (int)cplen); - dmaaddr = (char *)xc->getPhysMemPtr()->dma_addr(paddr, len); - assert(dmaaddr); - - memcpy(dmaaddr, src, len); - if (len == cplen) - return; - - cplen -= len; - src += len; - dest += len; - - while (cplen > AlphaISA::PageBytes) { - paddr = vtophys(xc, dest); - dmaaddr = (char *)xc->getPhysMemPtr()->dma_addr(paddr, - AlphaISA::PageBytes); - assert(dmaaddr); - - memcpy(dmaaddr, src, AlphaISA::PageBytes); - cplen -= AlphaISA::PageBytes; - src += AlphaISA::PageBytes; - dest += AlphaISA::PageBytes; - } - - if (cplen > 0) { - paddr = vtophys(xc, dest); - dmaaddr = (char *)xc->getPhysMemPtr()->dma_addr(paddr, cplen); - assert(dmaaddr); - - memcpy(dmaaddr, src, cplen); - } -} - -void -CopyString(ExecContext *xc, char *dst, Addr vaddr, size_t maxlen) -{ - Addr paddr; - char *dmaaddr; - int len; - - paddr = vtophys(xc, vaddr); - len = min((int)(AlphaISA::PageBytes - (paddr & AlphaISA::PageOffset)), - (int)maxlen); - dmaaddr = (char *)xc->getPhysMemPtr()->dma_addr(paddr, len); - assert(dmaaddr); - - char *term = (char *)memchr(dmaaddr, 0, len); - if (term) - len = term - dmaaddr + 1; - - memcpy(dst, dmaaddr, len); - - if (term || len == maxlen) - return; - - maxlen -= len; - dst += len; - vaddr += len; - - while (maxlen > AlphaISA::PageBytes) { - paddr = vtophys(xc, vaddr); - dmaaddr = (char *)xc->getPhysMemPtr()->dma_addr(paddr, - AlphaISA::PageBytes); - assert(dmaaddr); - - char *term = (char *)memchr(dmaaddr, 0, AlphaISA::PageBytes); - len = term ? (term - dmaaddr + 1) : AlphaISA::PageBytes; - - memcpy(dst, dmaaddr, len); - if (term) - return; - - maxlen -= AlphaISA::PageBytes; - dst += AlphaISA::PageBytes; - vaddr += AlphaISA::PageBytes; - } - - if (maxlen > 0) { - paddr = vtophys(xc, vaddr); - dmaaddr = (char *)xc->getPhysMemPtr()->dma_addr(paddr, maxlen); - assert(dmaaddr); - - char *term = (char *)memchr(dmaaddr, 0, maxlen); - len = term ? (term - dmaaddr + 1) : maxlen; - - memcpy(dst, dmaaddr, len); - - maxlen -= len; - } - - if (maxlen == 0) - dst[maxlen] = '\0'; -} diff --git a/arch/alpha/vtophys.hh b/arch/alpha/vtophys.hh deleted file mode 100644 index 95430ce77..000000000 --- a/arch/alpha/vtophys.hh +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2002-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __ARCH_ALPHA_VTOPHYS_H__ -#define __ARCH_ALPHA_VTOPHYS_H__ - -#include "arch/alpha/isa_traits.hh" - -class ExecContext; -class PhysicalMemory; - -AlphaISA::PageTableEntry -kernel_pte_lookup(PhysicalMemory *pmem, Addr ptbr, AlphaISA::VAddr vaddr); - -Addr vtophys(PhysicalMemory *xc, Addr vaddr); -Addr vtophys(ExecContext *xc, Addr vaddr); -uint8_t *vtomem(ExecContext *xc, Addr vaddr, size_t len); -uint8_t *ptomem(ExecContext *xc, Addr paddr, size_t len); - -void CopyOut(ExecContext *xc, void *dst, Addr src, size_t len); -void CopyIn(ExecContext *xc, Addr dst, void *src, size_t len); -void CopyString(ExecContext *xc, char *dst, Addr vaddr, size_t maxlen); - -#endif // __ARCH_ALPHA_VTOPHYS_H__ - diff --git a/arch/isa_parser.py b/arch/isa_parser.py deleted file mode 100755 index b0f10783f..000000000 --- a/arch/isa_parser.py +++ /dev/null @@ -1,1772 +0,0 @@ -# Copyright (c) 2003-2005 The Regents of The University of Michigan -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer; -# redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution; -# neither the name of the copyright holders nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -import os -import sys -import re -import string -import traceback -# get type names -from types import * - -# Prepend the directory where the PLY lex & yacc modules are found -# to the search path. Assumes we're compiling in a subdirectory -# of 'build' in the current tree. -sys.path[0:0] = [os.environ['M5_EXT'] + '/ply'] - -import lex -import yacc - -##################################################################### -# -# Lexer -# -# The PLY lexer module takes two things as input: -# - A list of token names (the string list 'tokens') -# - A regular expression describing a match for each token. The -# regexp for token FOO can be provided in two ways: -# - as a string variable named t_FOO -# - as the doc string for a function named t_FOO. In this case, -# the function is also executed, allowing an action to be -# associated with each token match. -# -##################################################################### - -# Reserved words. These are listed separately as they are matched -# using the same regexp as generic IDs, but distinguished in the -# t_ID() function. The PLY documentation suggests this approach. -reserved = ( - 'BITFIELD', 'DECODE', 'DECODER', 'DEFAULT', 'DEF', 'EXEC', 'FORMAT', - 'HEADER', 'LET', 'NAMESPACE', 'OPERAND_TYPES', 'OPERANDS', - 'OUTPUT', 'SIGNED', 'TEMPLATE' - ) - -# List of tokens. The lex module requires this. -tokens = reserved + ( - # identifier - 'ID', - - # integer literal - 'INTLIT', - - # string literal - 'STRLIT', - - # code literal - 'CODELIT', - - # ( ) [ ] { } < > , ; : :: * - 'LPAREN', 'RPAREN', - 'LBRACKET', 'RBRACKET', - 'LBRACE', 'RBRACE', - 'LESS', 'GREATER', 'EQUALS', - 'COMMA', 'SEMI', 'COLON', 'DBLCOLON', - 'ASTERISK', - - # C preprocessor directives - 'CPPDIRECTIVE' - -# The following are matched but never returned. commented out to -# suppress PLY warning - # newfile directive -# 'NEWFILE', - - # endfile directive -# 'ENDFILE' -) - -# Regular expressions for token matching -t_LPAREN = r'\(' -t_RPAREN = r'\)' -t_LBRACKET = r'\[' -t_RBRACKET = r'\]' -t_LBRACE = r'\{' -t_RBRACE = r'\}' -t_LESS = r'\<' -t_GREATER = r'\>' -t_EQUALS = r'=' -t_COMMA = r',' -t_SEMI = r';' -t_COLON = r':' -t_DBLCOLON = r'::' -t_ASTERISK = r'\*' - -# Identifiers and reserved words -reserved_map = { } -for r in reserved: - reserved_map[r.lower()] = r - -def t_ID(t): - r'[A-Za-z_]\w*' - t.type = reserved_map.get(t.value,'ID') - return t - -# Integer literal -def t_INTLIT(t): - r'(0x[\da-fA-F]+)|\d+' - try: - t.value = int(t.value,0) - except ValueError: - error(t.lineno, 'Integer value "%s" too large' % t.value) - t.value = 0 - return t - -# String literal. Note that these use only single quotes, and -# can span multiple lines. -def t_STRLIT(t): - r"(?m)'([^'])+'" - # strip off quotes - t.value = t.value[1:-1] - t.lineno += t.value.count('\n') - return t - - -# "Code literal"... like a string literal, but delimiters are -# '{{' and '}}' so they get formatted nicely under emacs c-mode -def t_CODELIT(t): - r"(?m)\{\{([^\}]|}(?!\}))+\}\}" - # strip off {{ & }} - t.value = t.value[2:-2] - t.lineno += t.value.count('\n') - return t - -def t_CPPDIRECTIVE(t): - r'^\#[^\#].*\n' - t.lineno += t.value.count('\n') - return t - -def t_NEWFILE(t): - r'^\#\#newfile\s+"[\w/.-]*"' - fileNameStack.push((t.value[11:-1], t.lineno)) - t.lineno = 0 - -def t_ENDFILE(t): - r'^\#\#endfile' - (old_filename, t.lineno) = fileNameStack.pop() - -# -# The functions t_NEWLINE, t_ignore, and t_error are -# special for the lex module. -# - -# Newlines -def t_NEWLINE(t): - r'\n+' - t.lineno += t.value.count('\n') - -# Comments -def t_comment(t): - r'//.*' - -# Completely ignored characters -t_ignore = ' \t\x0c' - -# Error handler -def t_error(t): - error(t.lineno, "illegal character '%s'" % t.value[0]) - t.skip(1) - -# Build the lexer -lex.lex() - -##################################################################### -# -# Parser -# -# Every function whose name starts with 'p_' defines a grammar rule. -# The rule is encoded in the function's doc string, while the -# function body provides the action taken when the rule is matched. -# The argument to each function is a list of the values of the -# rule's symbols: t[0] for the LHS, and t[1..n] for the symbols -# on the RHS. For tokens, the value is copied from the t.value -# attribute provided by the lexer. For non-terminals, the value -# is assigned by the producing rule; i.e., the job of the grammar -# rule function is to set the value for the non-terminal on the LHS -# (by assigning to t[0]). -##################################################################### - -# The LHS of the first grammar rule is used as the start symbol -# (in this case, 'specification'). Note that this rule enforces -# that there will be exactly one namespace declaration, with 0 or more -# global defs/decls before and after it. The defs & decls before -# the namespace decl will be outside the namespace; those after -# will be inside. The decoder function is always inside the namespace. -def p_specification(t): - 'specification : opt_defs_and_outputs name_decl opt_defs_and_outputs decode_block' - global_code = t[1] - isa_name = t[2] - namespace = isa_name + "Inst" - # wrap the decode block as a function definition - t[4].wrap_decode_block(''' -StaticInstPtr -%(isa_name)s::decodeInst(%(isa_name)s::ExtMachInst machInst) -{ - using namespace %(namespace)s; -''' % vars(), '}') - # both the latter output blocks and the decode block are in the namespace - namespace_code = t[3] + t[4] - # pass it all back to the caller of yacc.parse() - t[0] = (isa_name, namespace, global_code, namespace_code) - -# ISA name declaration looks like "namespace <foo>;" -def p_name_decl(t): - 'name_decl : NAMESPACE ID SEMI' - t[0] = t[2] - -# 'opt_defs_and_outputs' is a possibly empty sequence of -# def and/or output statements. -def p_opt_defs_and_outputs_0(t): - 'opt_defs_and_outputs : empty' - t[0] = GenCode() - -def p_opt_defs_and_outputs_1(t): - 'opt_defs_and_outputs : defs_and_outputs' - t[0] = t[1] - -def p_defs_and_outputs_0(t): - 'defs_and_outputs : def_or_output' - t[0] = t[1] - -def p_defs_and_outputs_1(t): - 'defs_and_outputs : defs_and_outputs def_or_output' - t[0] = t[1] + t[2] - -# The list of possible definition/output statements. -def p_def_or_output(t): - '''def_or_output : def_format - | def_bitfield - | def_template - | def_operand_types - | def_operands - | output_header - | output_decoder - | output_exec - | global_let''' - t[0] = t[1] - -# Output blocks 'output <foo> {{...}}' (C++ code blocks) are copied -# directly to the appropriate output section. - - -# Protect any non-dict-substitution '%'s in a format string -# (i.e. those not followed by '(') -def protect_non_subst_percents(s): - return re.sub(r'%(?!\()', '%%', s) - -# Massage output block by substituting in template definitions and bit -# operators. We handle '%'s embedded in the string that don't -# indicate template substitutions (or CPU-specific symbols, which get -# handled in GenCode) by doubling them first so that the format -# operation will reduce them back to single '%'s. -def process_output(s): - s = protect_non_subst_percents(s) - # protects cpu-specific symbols too - s = protect_cpu_symbols(s) - return substBitOps(s % templateMap) - -def p_output_header(t): - 'output_header : OUTPUT HEADER CODELIT SEMI' - t[0] = GenCode(header_output = process_output(t[3])) - -def p_output_decoder(t): - 'output_decoder : OUTPUT DECODER CODELIT SEMI' - t[0] = GenCode(decoder_output = process_output(t[3])) - -def p_output_exec(t): - 'output_exec : OUTPUT EXEC CODELIT SEMI' - t[0] = GenCode(exec_output = process_output(t[3])) - -# global let blocks 'let {{...}}' (Python code blocks) are executed -# directly when seen. Note that these execute in a special variable -# context 'exportContext' to prevent the code from polluting this -# script's namespace. -def p_global_let(t): - 'global_let : LET CODELIT SEMI' - updateExportContext() - try: - exec fixPythonIndentation(t[2]) in exportContext - except Exception, exc: - error(t.lineno(1), - 'error: %s in global let block "%s".' % (exc, t[2])) - t[0] = GenCode() # contributes nothing to the output C++ file - -# Define the mapping from operand type extensions to C++ types and bit -# widths (stored in operandTypeMap). -def p_def_operand_types(t): - 'def_operand_types : DEF OPERAND_TYPES CODELIT SEMI' - try: - userDict = eval('{' + t[3] + '}') - except Exception, exc: - error(t.lineno(1), - 'error: %s in def operand_types block "%s".' % (exc, t[3])) - buildOperandTypeMap(userDict, t.lineno(1)) - t[0] = GenCode() # contributes nothing to the output C++ file - -# Define the mapping from operand names to operand classes and other -# traits. Stored in operandNameMap. -def p_def_operands(t): - 'def_operands : DEF OPERANDS CODELIT SEMI' - if not globals().has_key('operandTypeMap'): - error(t.lineno(1), - 'error: operand types must be defined before operands') - try: - userDict = eval('{' + t[3] + '}') - except Exception, exc: - error(t.lineno(1), - 'error: %s in def operands block "%s".' % (exc, t[3])) - buildOperandNameMap(userDict, t.lineno(1)) - t[0] = GenCode() # contributes nothing to the output C++ file - -# A bitfield definition looks like: -# 'def [signed] bitfield <ID> [<first>:<last>]' -# This generates a preprocessor macro in the output file. -def p_def_bitfield_0(t): - 'def_bitfield : DEF opt_signed BITFIELD ID LESS INTLIT COLON INTLIT GREATER SEMI' - expr = 'bits(machInst, %2d, %2d)' % (t[6], t[8]) - if (t[2] == 'signed'): - expr = 'sext<%d>(%s)' % (t[6] - t[8] + 1, expr) - hash_define = '#undef %s\n#define %s\t%s\n' % (t[4], t[4], expr) - t[0] = GenCode(header_output = hash_define) - -# alternate form for single bit: 'def [signed] bitfield <ID> [<bit>]' -def p_def_bitfield_1(t): - 'def_bitfield : DEF opt_signed BITFIELD ID LESS INTLIT GREATER SEMI' - expr = 'bits(machInst, %2d, %2d)' % (t[6], t[6]) - if (t[2] == 'signed'): - expr = 'sext<%d>(%s)' % (1, expr) - hash_define = '#undef %s\n#define %s\t%s\n' % (t[4], t[4], expr) - t[0] = GenCode(header_output = hash_define) - -def p_opt_signed_0(t): - 'opt_signed : SIGNED' - t[0] = t[1] - -def p_opt_signed_1(t): - 'opt_signed : empty' - t[0] = '' - -# Global map variable to hold templates -templateMap = {} - -def p_def_template(t): - 'def_template : DEF TEMPLATE ID CODELIT SEMI' - templateMap[t[3]] = Template(t[4]) - t[0] = GenCode() - -# An instruction format definition looks like -# "def format <fmt>(<params>) {{...}};" -def p_def_format(t): - 'def_format : DEF FORMAT ID LPAREN param_list RPAREN CODELIT SEMI' - (id, params, code) = (t[3], t[5], t[7]) - defFormat(id, params, code, t.lineno(1)) - t[0] = GenCode() - -# The formal parameter list for an instruction format is a possibly -# empty list of comma-separated parameters. Positional (standard, -# non-keyword) parameters must come first, followed by keyword -# parameters, followed by a '*foo' parameter that gets excess -# positional arguments (as in Python). Each of these three parameter -# categories is optional. -# -# Note that we do not support the '**foo' parameter for collecting -# otherwise undefined keyword args. Otherwise the parameter list is -# (I believe) identical to what is supported in Python. -# -# The param list generates a tuple, where the first element is a list of -# the positional params and the second element is a dict containing the -# keyword params. -def p_param_list_0(t): - 'param_list : positional_param_list COMMA nonpositional_param_list' - t[0] = t[1] + t[3] - -def p_param_list_1(t): - '''param_list : positional_param_list - | nonpositional_param_list''' - t[0] = t[1] - -def p_positional_param_list_0(t): - 'positional_param_list : empty' - t[0] = [] - -def p_positional_param_list_1(t): - 'positional_param_list : ID' - t[0] = [t[1]] - -def p_positional_param_list_2(t): - 'positional_param_list : positional_param_list COMMA ID' - t[0] = t[1] + [t[3]] - -def p_nonpositional_param_list_0(t): - 'nonpositional_param_list : keyword_param_list COMMA excess_args_param' - t[0] = t[1] + t[3] - -def p_nonpositional_param_list_1(t): - '''nonpositional_param_list : keyword_param_list - | excess_args_param''' - t[0] = t[1] - -def p_keyword_param_list_0(t): - 'keyword_param_list : keyword_param' - t[0] = [t[1]] - -def p_keyword_param_list_1(t): - 'keyword_param_list : keyword_param_list COMMA keyword_param' - t[0] = t[1] + [t[3]] - -def p_keyword_param(t): - 'keyword_param : ID EQUALS expr' - t[0] = t[1] + ' = ' + t[3].__repr__() - -def p_excess_args_param(t): - 'excess_args_param : ASTERISK ID' - # Just concatenate them: '*ID'. Wrap in list to be consistent - # with positional_param_list and keyword_param_list. - t[0] = [t[1] + t[2]] - -# End of format definition-related rules. -############## - -# -# A decode block looks like: -# decode <field1> [, <field2>]* [default <inst>] { ... } -# -def p_decode_block(t): - 'decode_block : DECODE ID opt_default LBRACE decode_stmt_list RBRACE' - default_defaults = defaultStack.pop() - codeObj = t[5] - # use the "default defaults" only if there was no explicit - # default statement in decode_stmt_list - if not codeObj.has_decode_default: - codeObj += default_defaults - codeObj.wrap_decode_block('switch (%s) {\n' % t[2], '}\n') - t[0] = codeObj - -# The opt_default statement serves only to push the "default defaults" -# onto defaultStack. This value will be used by nested decode blocks, -# and used and popped off when the current decode_block is processed -# (in p_decode_block() above). -def p_opt_default_0(t): - 'opt_default : empty' - # no default specified: reuse the one currently at the top of the stack - defaultStack.push(defaultStack.top()) - # no meaningful value returned - t[0] = None - -def p_opt_default_1(t): - 'opt_default : DEFAULT inst' - # push the new default - codeObj = t[2] - codeObj.wrap_decode_block('\ndefault:\n', 'break;\n') - defaultStack.push(codeObj) - # no meaningful value returned - t[0] = None - -def p_decode_stmt_list_0(t): - 'decode_stmt_list : decode_stmt' - t[0] = t[1] - -def p_decode_stmt_list_1(t): - 'decode_stmt_list : decode_stmt decode_stmt_list' - if (t[1].has_decode_default and t[2].has_decode_default): - error(t.lineno(1), 'Two default cases in decode block') - t[0] = t[1] + t[2] - -# -# Decode statement rules -# -# There are four types of statements allowed in a decode block: -# 1. Format blocks 'format <foo> { ... }' -# 2. Nested decode blocks -# 3. Instruction definitions. -# 4. C preprocessor directives. - - -# Preprocessor directives found in a decode statement list are passed -# through to the output, replicated to all of the output code -# streams. This works well for ifdefs, so we can ifdef out both the -# declarations and the decode cases generated by an instruction -# definition. Handling them as part of the grammar makes it easy to -# keep them in the right place with respect to the code generated by -# the other statements. -def p_decode_stmt_cpp(t): - 'decode_stmt : CPPDIRECTIVE' - t[0] = GenCode(t[1], t[1], t[1], t[1]) - -# A format block 'format <foo> { ... }' sets the default instruction -# format used to handle instruction definitions inside the block. -# This format can be overridden by using an explicit format on the -# instruction definition or with a nested format block. -def p_decode_stmt_format(t): - 'decode_stmt : FORMAT push_format_id LBRACE decode_stmt_list RBRACE' - # The format will be pushed on the stack when 'push_format_id' is - # processed (see below). Once the parser has recognized the full - # production (though the right brace), we're done with the format, - # so now we can pop it. - formatStack.pop() - t[0] = t[4] - -# This rule exists so we can set the current format (& push the stack) -# when we recognize the format name part of the format block. -def p_push_format_id(t): - 'push_format_id : ID' - try: - formatStack.push(formatMap[t[1]]) - t[0] = ('', '// format %s' % t[1]) - except KeyError: - error(t.lineno(1), 'instruction format "%s" not defined.' % t[1]) - -# Nested decode block: if the value of the current field matches the -# specified constant, do a nested decode on some other field. -def p_decode_stmt_decode(t): - 'decode_stmt : case_label COLON decode_block' - label = t[1] - codeObj = t[3] - # just wrap the decoding code from the block as a case in the - # outer switch statement. - codeObj.wrap_decode_block('\n%s:\n' % label) - codeObj.has_decode_default = (label == 'default') - t[0] = codeObj - -# Instruction definition (finally!). -def p_decode_stmt_inst(t): - 'decode_stmt : case_label COLON inst SEMI' - label = t[1] - codeObj = t[3] - codeObj.wrap_decode_block('\n%s:' % label, 'break;\n') - codeObj.has_decode_default = (label == 'default') - t[0] = codeObj - -# The case label is either a list of one or more constants or 'default' -def p_case_label_0(t): - 'case_label : intlit_list' - t[0] = ': '.join(map(lambda a: 'case %#x' % a, t[1])) - -def p_case_label_1(t): - 'case_label : DEFAULT' - t[0] = 'default' - -# -# The constant list for a decode case label must be non-empty, but may have -# one or more comma-separated integer literals in it. -# -def p_intlit_list_0(t): - 'intlit_list : INTLIT' - t[0] = [t[1]] - -def p_intlit_list_1(t): - 'intlit_list : intlit_list COMMA INTLIT' - t[0] = t[1] - t[0].append(t[3]) - -# Define an instruction using the current instruction format (specified -# by an enclosing format block). -# "<mnemonic>(<args>)" -def p_inst_0(t): - 'inst : ID LPAREN arg_list RPAREN' - # Pass the ID and arg list to the current format class to deal with. - currentFormat = formatStack.top() - codeObj = currentFormat.defineInst(t[1], t[3], t.lineno(1)) - args = ','.join(map(str, t[3])) - args = re.sub('(?m)^', '//', args) - args = re.sub('^//', '', args) - comment = '\n// %s::%s(%s)\n' % (currentFormat.id, t[1], args) - codeObj.prepend_all(comment) - t[0] = codeObj - -# Define an instruction using an explicitly specified format: -# "<fmt>::<mnemonic>(<args>)" -def p_inst_1(t): - 'inst : ID DBLCOLON ID LPAREN arg_list RPAREN' - try: - format = formatMap[t[1]] - except KeyError: - error(t.lineno(1), 'instruction format "%s" not defined.' % t[1]) - codeObj = format.defineInst(t[3], t[5], t.lineno(1)) - comment = '\n// %s::%s(%s)\n' % (t[1], t[3], t[5]) - codeObj.prepend_all(comment) - t[0] = codeObj - -# The arg list generates a tuple, where the first element is a list of -# the positional args and the second element is a dict containing the -# keyword args. -def p_arg_list_0(t): - 'arg_list : positional_arg_list COMMA keyword_arg_list' - t[0] = ( t[1], t[3] ) - -def p_arg_list_1(t): - 'arg_list : positional_arg_list' - t[0] = ( t[1], {} ) - -def p_arg_list_2(t): - 'arg_list : keyword_arg_list' - t[0] = ( [], t[1] ) - -def p_positional_arg_list_0(t): - 'positional_arg_list : empty' - t[0] = [] - -def p_positional_arg_list_1(t): - 'positional_arg_list : expr' - t[0] = [t[1]] - -def p_positional_arg_list_2(t): - 'positional_arg_list : positional_arg_list COMMA expr' - t[0] = t[1] + [t[3]] - -def p_keyword_arg_list_0(t): - 'keyword_arg_list : keyword_arg' - t[0] = t[1] - -def p_keyword_arg_list_1(t): - 'keyword_arg_list : keyword_arg_list COMMA keyword_arg' - t[0] = t[1] - t[0].update(t[3]) - -def p_keyword_arg(t): - 'keyword_arg : ID EQUALS expr' - t[0] = { t[1] : t[3] } - -# -# Basic expressions. These constitute the argument values of -# "function calls" (i.e. instruction definitions in the decode block) -# and default values for formal parameters of format functions. -# -# Right now, these are either strings, integers, or (recursively) -# lists of exprs (using Python square-bracket list syntax). Note that -# bare identifiers are trated as string constants here (since there -# isn't really a variable namespace to refer to). -# -def p_expr_0(t): - '''expr : ID - | INTLIT - | STRLIT - | CODELIT''' - t[0] = t[1] - -def p_expr_1(t): - '''expr : LBRACKET list_expr RBRACKET''' - t[0] = t[2] - -def p_list_expr_0(t): - 'list_expr : expr' - t[0] = [t[1]] - -def p_list_expr_1(t): - 'list_expr : list_expr COMMA expr' - t[0] = t[1] + [t[3]] - -def p_list_expr_2(t): - 'list_expr : empty' - t[0] = [] - -# -# Empty production... use in other rules for readability. -# -def p_empty(t): - 'empty :' - pass - -# Parse error handler. Note that the argument here is the offending -# *token*, not a grammar symbol (hence the need to use t.value) -def p_error(t): - if t: - error(t.lineno, "syntax error at '%s'" % t.value) - else: - error(0, "unknown syntax error", True) - -# END OF GRAMMAR RULES -# -# Now build the parser. -yacc.yacc() - - -##################################################################### -# -# Support Classes -# -##################################################################### - -# Expand template with CPU-specific references into a dictionary with -# an entry for each CPU model name. The entry key is the model name -# and the corresponding value is the template with the CPU-specific -# refs substituted for that model. -def expand_cpu_symbols_to_dict(template): - # Protect '%'s that don't go with CPU-specific terms - t = re.sub(r'%(?!\(CPU_)', '%%', template) - result = {} - for cpu in cpu_models: - result[cpu.name] = t % cpu.strings - return result - -# *If* the template has CPU-specific references, return a single -# string containing a copy of the template for each CPU model with the -# corresponding values substituted in. If the template has no -# CPU-specific references, it is returned unmodified. -def expand_cpu_symbols_to_string(template): - if template.find('%(CPU_') != -1: - return reduce(lambda x,y: x+y, - expand_cpu_symbols_to_dict(template).values()) - else: - return template - -# Protect CPU-specific references by doubling the corresponding '%'s -# (in preparation for substituting a different set of references into -# the template). -def protect_cpu_symbols(template): - return re.sub(r'%(?=\(CPU_)', '%%', template) - -############### -# GenCode class -# -# The GenCode class encapsulates generated code destined for various -# output files. The header_output and decoder_output attributes are -# strings containing code destined for decoder.hh and decoder.cc -# respectively. The decode_block attribute contains code to be -# incorporated in the decode function itself (that will also end up in -# decoder.cc). The exec_output attribute is a dictionary with a key -# for each CPU model name; the value associated with a particular key -# is the string of code for that CPU model's exec.cc file. The -# has_decode_default attribute is used in the decode block to allow -# explicit default clauses to override default default clauses. - -class GenCode: - # Constructor. At this point we substitute out all CPU-specific - # symbols. For the exec output, these go into the per-model - # dictionary. For all other output types they get collapsed into - # a single string. - def __init__(self, - header_output = '', decoder_output = '', exec_output = '', - decode_block = '', has_decode_default = False): - self.header_output = expand_cpu_symbols_to_string(header_output) - self.decoder_output = expand_cpu_symbols_to_string(decoder_output) - if isinstance(exec_output, dict): - self.exec_output = exec_output - elif isinstance(exec_output, str): - # If the exec_output arg is a single string, we replicate - # it for each of the CPU models, substituting and - # %(CPU_foo)s params appropriately. - self.exec_output = expand_cpu_symbols_to_dict(exec_output) - self.decode_block = expand_cpu_symbols_to_string(decode_block) - self.has_decode_default = has_decode_default - - # Override '+' operator: generate a new GenCode object that - # concatenates all the individual strings in the operands. - def __add__(self, other): - exec_output = {} - for cpu in cpu_models: - n = cpu.name - exec_output[n] = self.exec_output[n] + other.exec_output[n] - return GenCode(self.header_output + other.header_output, - self.decoder_output + other.decoder_output, - exec_output, - self.decode_block + other.decode_block, - self.has_decode_default or other.has_decode_default) - - # Prepend a string (typically a comment) to all the strings. - def prepend_all(self, pre): - self.header_output = pre + self.header_output - self.decoder_output = pre + self.decoder_output - self.decode_block = pre + self.decode_block - for cpu in cpu_models: - self.exec_output[cpu.name] = pre + self.exec_output[cpu.name] - - # Wrap the decode block in a pair of strings (e.g., 'case foo:' - # and 'break;'). Used to build the big nested switch statement. - def wrap_decode_block(self, pre, post = ''): - self.decode_block = pre + indent(self.decode_block) + post - -################ -# Format object. -# -# A format object encapsulates an instruction format. It must provide -# a defineInst() method that generates the code for an instruction -# definition. - -exportContextSymbols = ('InstObjParams', 'CodeBlock', - 'makeList', 're', 'string') - -exportContext = {} - -def updateExportContext(): - exportContext.update(exportDict(*exportContextSymbols)) - exportContext.update(templateMap) - -def exportDict(*symNames): - return dict([(s, eval(s)) for s in symNames]) - - -class Format: - def __init__(self, id, params, code): - # constructor: just save away arguments - self.id = id - self.params = params - label = 'def format ' + id - self.user_code = compile(fixPythonIndentation(code), label, 'exec') - param_list = string.join(params, ", ") - f = '''def defInst(_code, _context, %s): - my_locals = vars().copy() - exec _code in _context, my_locals - return my_locals\n''' % param_list - c = compile(f, label + ' wrapper', 'exec') - exec c - self.func = defInst - - def defineInst(self, name, args, lineno): - context = {} - updateExportContext() - context.update(exportContext) - context.update({ 'name': name, 'Name': string.capitalize(name) }) - try: - vars = self.func(self.user_code, context, *args[0], **args[1]) - except Exception, exc: - error(lineno, 'error defining "%s": %s.' % (name, exc)) - for k in vars.keys(): - if k not in ('header_output', 'decoder_output', - 'exec_output', 'decode_block'): - del vars[k] - return GenCode(**vars) - -# Special null format to catch an implicit-format instruction -# definition outside of any format block. -class NoFormat: - def __init__(self): - self.defaultInst = '' - - def defineInst(self, name, args, lineno): - error(lineno, - 'instruction definition "%s" with no active format!' % name) - -# This dictionary maps format name strings to Format objects. -formatMap = {} - -# Define a new format -def defFormat(id, params, code, lineno): - # make sure we haven't already defined this one - if formatMap.get(id, None) != None: - error(lineno, 'format %s redefined.' % id) - # create new object and store in global map - formatMap[id] = Format(id, params, code) - - -############## -# Stack: a simple stack object. Used for both formats (formatStack) -# and default cases (defaultStack). Simply wraps a list to give more -# stack-like syntax and enable initialization with an argument list -# (as opposed to an argument that's a list). - -class Stack(list): - def __init__(self, *items): - list.__init__(self, items) - - def push(self, item): - self.append(item); - - def top(self): - return self[-1] - -# The global format stack. -formatStack = Stack(NoFormat()) - -# The global default case stack. -defaultStack = Stack( None ) - -# Global stack that tracks current file and line number. -# Each element is a tuple (filename, lineno) that records the -# *current* filename and the line number in the *previous* file where -# it was included. -fileNameStack = Stack() - -################### -# Utility functions - -# -# Indent every line in string 's' by two spaces -# (except preprocessor directives). -# Used to make nested code blocks look pretty. -# -def indent(s): - return re.sub(r'(?m)^(?!#)', ' ', s) - -# -# Munge a somewhat arbitrarily formatted piece of Python code -# (e.g. from a format 'let' block) into something whose indentation -# will get by the Python parser. -# -# The two keys here are that Python will give a syntax error if -# there's any whitespace at the beginning of the first line, and that -# all lines at the same lexical nesting level must have identical -# indentation. Unfortunately the way code literals work, an entire -# let block tends to have some initial indentation. Rather than -# trying to figure out what that is and strip it off, we prepend 'if -# 1:' to make the let code the nested block inside the if (and have -# the parser automatically deal with the indentation for us). -# -# We don't want to do this if (1) the code block is empty or (2) the -# first line of the block doesn't have any whitespace at the front. - -def fixPythonIndentation(s): - # get rid of blank lines first - s = re.sub(r'(?m)^\s*\n', '', s); - if (s != '' and re.match(r'[ \t]', s[0])): - s = 'if 1:\n' + s - return s - -# Error handler. Just call exit. Output formatted to work under -# Emacs compile-mode. Optional 'print_traceback' arg, if set to True, -# prints a Python stack backtrace too (can be handy when trying to -# debug the parser itself). -def error(lineno, string, print_traceback = False): - spaces = "" - for (filename, line) in fileNameStack[0:-1]: - print spaces + "In file included from " + filename + ":" - spaces += " " - # Print a Python stack backtrace if requested. - if (print_traceback): - traceback.print_exc() - if lineno != 0: - line_str = "%d:" % lineno - else: - line_str = "" - sys.exit(spaces + "%s:%s %s" % (fileNameStack[-1][0], line_str, string)) - - -##################################################################### -# -# Bitfield Operator Support -# -##################################################################### - -bitOp1ArgRE = re.compile(r'<\s*(\w+)\s*:\s*>') - -bitOpWordRE = re.compile(r'(?<![\w\.])([\w\.]+)<\s*(\w+)\s*:\s*(\w+)\s*>') -bitOpExprRE = re.compile(r'\)<\s*(\w+)\s*:\s*(\w+)\s*>') - -def substBitOps(code): - # first convert single-bit selectors to two-index form - # i.e., <n> --> <n:n> - code = bitOp1ArgRE.sub(r'<\1:\1>', code) - # simple case: selector applied to ID (name) - # i.e., foo<a:b> --> bits(foo, a, b) - code = bitOpWordRE.sub(r'bits(\1, \2, \3)', code) - # if selector is applied to expression (ending in ')'), - # we need to search backward for matching '(' - match = bitOpExprRE.search(code) - while match: - exprEnd = match.start() - here = exprEnd - 1 - nestLevel = 1 - while nestLevel > 0: - if code[here] == '(': - nestLevel -= 1 - elif code[here] == ')': - nestLevel += 1 - here -= 1 - if here < 0: - sys.exit("Didn't find '('!") - exprStart = here+1 - newExpr = r'bits(%s, %s, %s)' % (code[exprStart:exprEnd+1], - match.group(1), match.group(2)) - code = code[:exprStart] + newExpr + code[match.end():] - match = bitOpExprRE.search(code) - return code - - -#################### -# Template objects. -# -# Template objects are format strings that allow substitution from -# the attribute spaces of other objects (e.g. InstObjParams instances). - -class Template: - def __init__(self, t): - self.template = t - - def subst(self, d): - # Start with the template namespace. Make a copy since we're - # going to modify it. - myDict = templateMap.copy() - # if the argument is a dictionary, we just use it. - if isinstance(d, dict): - myDict.update(d) - # if the argument is an object, we use its attribute map. - elif hasattr(d, '__dict__'): - myDict.update(d.__dict__) - else: - raise TypeError, "Template.subst() arg must be or have dictionary" - # Protect non-Python-dict substitutions (e.g. if there's a printf - # in the templated C++ code) - template = protect_non_subst_percents(self.template) - # CPU-model-specific substitutions are handled later (in GenCode). - template = protect_cpu_symbols(template) - return template % myDict - - # Convert to string. This handles the case when a template with a - # CPU-specific term gets interpolated into another template or into - # an output block. - def __str__(self): - return expand_cpu_symbols_to_string(self.template) - -##################################################################### -# -# Code Parser -# -# The remaining code is the support for automatically extracting -# instruction characteristics from pseudocode. -# -##################################################################### - -# Force the argument to be a list. Useful for flags, where a caller -# can specify a singleton flag or a list of flags. Also usful for -# converting tuples to lists so they can be modified. -def makeList(arg): - if isinstance(arg, list): - return arg - elif isinstance(arg, tuple): - return list(arg) - elif not arg: - return [] - else: - return [ arg ] - -# Generate operandTypeMap from the user's 'def operand_types' -# statement. -def buildOperandTypeMap(userDict, lineno): - global operandTypeMap - operandTypeMap = {} - for (ext, (desc, size)) in userDict.iteritems(): - if desc == 'signed int': - ctype = 'int%d_t' % size - is_signed = 1 - elif desc == 'unsigned int': - ctype = 'uint%d_t' % size - is_signed = 0 - elif desc == 'float': - is_signed = 1 # shouldn't really matter - if size == 32: - ctype = 'float' - elif size == 64: - ctype = 'double' - if ctype == '': - error(lineno, 'Unrecognized type description "%s" in userDict') - operandTypeMap[ext] = (size, ctype, is_signed) - -# -# -# -# Base class for operand descriptors. An instance of this class (or -# actually a class derived from this one) represents a specific -# operand for a code block (e.g, "Rc.sq" as a dest). Intermediate -# derived classes encapsulates the traits of a particular operand type -# (e.g., "32-bit integer register"). -# -class Operand(object): - def __init__(self, full_name, ext, is_src, is_dest): - self.full_name = full_name - self.ext = ext - self.is_src = is_src - self.is_dest = is_dest - # The 'effective extension' (eff_ext) is either the actual - # extension, if one was explicitly provided, or the default. - if ext: - self.eff_ext = ext - else: - self.eff_ext = self.dflt_ext - - (self.size, self.ctype, self.is_signed) = operandTypeMap[self.eff_ext] - - # note that mem_acc_size is undefined for non-mem operands... - # template must be careful not to use it if it doesn't apply. - if self.isMem(): - self.mem_acc_size = self.makeAccSize() - self.mem_acc_type = self.ctype - - # Finalize additional fields (primarily code fields). This step - # is done separately since some of these fields may depend on the - # register index enumeration that hasn't been performed yet at the - # time of __init__(). - def finalize(self): - self.flags = self.getFlags() - self.constructor = self.makeConstructor() - self.op_decl = self.makeDecl() - - if self.is_src: - self.op_rd = self.makeRead() - self.op_src_decl = self.makeDecl() - else: - self.op_rd = '' - self.op_src_decl = '' - - if self.is_dest: - self.op_wb = self.makeWrite() - self.op_dest_decl = self.makeDecl() - else: - self.op_wb = '' - self.op_dest_decl = '' - - def isMem(self): - return 0 - - def isReg(self): - return 0 - - def isFloatReg(self): - return 0 - - def isIntReg(self): - return 0 - - def isControlReg(self): - return 0 - - def getFlags(self): - # note the empty slice '[:]' gives us a copy of self.flags[0] - # instead of a reference to it - my_flags = self.flags[0][:] - if self.is_src: - my_flags += self.flags[1] - if self.is_dest: - my_flags += self.flags[2] - return my_flags - - def makeDecl(self): - # Note that initializations in the declarations are solely - # to avoid 'uninitialized variable' errors from the compiler. - return self.ctype + ' ' + self.base_name + ' = 0;\n'; - -class IntRegOperand(Operand): - def isReg(self): - return 1 - - def isIntReg(self): - return 1 - - def makeConstructor(self): - c = '' - if self.is_src: - c += '\n\t_srcRegIdx[%d] = %s;' % \ - (self.src_reg_idx, self.reg_spec) - if self.is_dest: - c += '\n\t_destRegIdx[%d] = %s;' % \ - (self.dest_reg_idx, self.reg_spec) - return c - - def makeRead(self): - if (self.ctype == 'float' or self.ctype == 'double'): - error(0, 'Attempt to read integer register as FP') - if (self.size == self.dflt_size): - return '%s = xc->readIntReg(this, %d);\n' % \ - (self.base_name, self.src_reg_idx) - else: - return '%s = bits(xc->readIntReg(this, %d), %d, 0);\n' % \ - (self.base_name, self.src_reg_idx, self.size-1) - - def makeWrite(self): - if (self.ctype == 'float' or self.ctype == 'double'): - error(0, 'Attempt to write integer register as FP') - if (self.size != self.dflt_size and self.is_signed): - final_val = 'sext<%d>(%s)' % (self.size, self.base_name) - else: - final_val = self.base_name - wb = ''' - { - %s final_val = %s; - xc->setIntReg(this, %d, final_val);\n - if (traceData) { traceData->setData(final_val); } - }''' % (self.dflt_ctype, final_val, self.dest_reg_idx) - return wb - -class FloatRegOperand(Operand): - def isReg(self): - return 1 - - def isFloatReg(self): - return 1 - - def makeConstructor(self): - c = '' - if self.is_src: - c += '\n\t_srcRegIdx[%d] = %s + FP_Base_DepTag;' % \ - (self.src_reg_idx, self.reg_spec) - if self.is_dest: - c += '\n\t_destRegIdx[%d] = %s + FP_Base_DepTag;' % \ - (self.dest_reg_idx, self.reg_spec) - return c - - def makeRead(self): - bit_select = 0 - if (self.ctype == 'float'): - func = 'readFloatRegSingle' - elif (self.ctype == 'double'): - func = 'readFloatRegDouble' - else: - func = 'readFloatRegInt' - if (self.size != self.dflt_size): - bit_select = 1 - base = 'xc->%s(this, %d)' % \ - (func, self.src_reg_idx) - if bit_select: - return '%s = bits(%s, %d, 0);\n' % \ - (self.base_name, base, self.size-1) - else: - return '%s = %s;\n' % (self.base_name, base) - - def makeWrite(self): - final_val = self.base_name - final_ctype = self.ctype - if (self.ctype == 'float'): - func = 'setFloatRegSingle' - elif (self.ctype == 'double'): - func = 'setFloatRegDouble' - else: - func = 'setFloatRegInt' - final_ctype = 'uint%d_t' % self.dflt_size - if (self.size != self.dflt_size and self.is_signed): - final_val = 'sext<%d>(%s)' % (self.size, self.base_name) - wb = ''' - { - %s final_val = %s; - xc->%s(this, %d, final_val);\n - if (traceData) { traceData->setData(final_val); } - }''' % (final_ctype, final_val, func, self.dest_reg_idx) - return wb - -class ControlRegOperand(Operand): - def isReg(self): - return 1 - - def isControlReg(self): - return 1 - - def makeConstructor(self): - c = '' - if self.is_src: - c += '\n\t_srcRegIdx[%d] = %s;' % \ - (self.src_reg_idx, self.reg_spec) - if self.is_dest: - c += '\n\t_destRegIdx[%d] = %s;' % \ - (self.dest_reg_idx, self.reg_spec) - return c - - def makeRead(self): - bit_select = 0 - if (self.ctype == 'float' or self.ctype == 'double'): - error(0, 'Attempt to read control register as FP') - base = 'xc->readMiscReg(%s)' % self.reg_spec - if self.size == self.dflt_size: - return '%s = %s;\n' % (self.base_name, base) - else: - return '%s = bits(%s, %d, 0);\n' % \ - (self.base_name, base, self.size-1) - - def makeWrite(self): - if (self.ctype == 'float' or self.ctype == 'double'): - error(0, 'Attempt to write control register as FP') - wb = 'xc->setMiscReg(%s, %s);\n' % (self.reg_spec, self.base_name) - wb += 'if (traceData) { traceData->setData(%s); }' % \ - self.base_name - return wb - -class MemOperand(Operand): - def isMem(self): - return 1 - - def makeConstructor(self): - return '' - - def makeDecl(self): - # Note that initializations in the declarations are solely - # to avoid 'uninitialized variable' errors from the compiler. - # Declare memory data variable. - c = '%s %s = 0;\n' % (self.ctype, self.base_name) - return c - - def makeRead(self): - return '' - - def makeWrite(self): - return '' - - # Return the memory access size *in bits*, suitable for - # forming a type via "uint%d_t". Divide by 8 if you want bytes. - def makeAccSize(self): - return self.size - - -class NPCOperand(Operand): - def makeConstructor(self): - return '' - - def makeRead(self): - return '%s = xc->readPC() + 4;\n' % self.base_name - - def makeWrite(self): - return 'xc->setNextPC(%s);\n' % self.base_name - -class NNPCOperand(Operand): - def makeConstructor(self): - return '' - - def makeRead(self): - return '%s = xc->readPC() + 8;\n' % self.base_name - - def makeWrite(self): - return 'xc->setNextNPC(%s);\n' % self.base_name - -def buildOperandNameMap(userDict, lineno): - global operandNameMap - operandNameMap = {} - for (op_name, val) in userDict.iteritems(): - (base_cls_name, dflt_ext, reg_spec, flags, sort_pri) = val - (dflt_size, dflt_ctype, dflt_is_signed) = operandTypeMap[dflt_ext] - # Canonical flag structure is a triple of lists, where each list - # indicates the set of flags implied by this operand always, when - # used as a source, and when used as a dest, respectively. - # For simplicity this can be initialized using a variety of fairly - # obvious shortcuts; we convert these to canonical form here. - if not flags: - # no flags specified (e.g., 'None') - flags = ( [], [], [] ) - elif isinstance(flags, str): - # a single flag: assumed to be unconditional - flags = ( [ flags ], [], [] ) - elif isinstance(flags, list): - # a list of flags: also assumed to be unconditional - flags = ( flags, [], [] ) - elif isinstance(flags, tuple): - # it's a tuple: it should be a triple, - # but each item could be a single string or a list - (uncond_flags, src_flags, dest_flags) = flags - flags = (makeList(uncond_flags), - makeList(src_flags), makeList(dest_flags)) - # Accumulate attributes of new operand class in tmp_dict - tmp_dict = {} - for attr in ('dflt_ext', 'reg_spec', 'flags', 'sort_pri', - 'dflt_size', 'dflt_ctype', 'dflt_is_signed'): - tmp_dict[attr] = eval(attr) - tmp_dict['base_name'] = op_name - # New class name will be e.g. "IntReg_Ra" - cls_name = base_cls_name + '_' + op_name - # Evaluate string arg to get class object. Note that the - # actual base class for "IntReg" is "IntRegOperand", i.e. we - # have to append "Operand". - try: - base_cls = eval(base_cls_name + 'Operand') - except NameError: - error(lineno, - 'error: unknown operand base class "%s"' % base_cls_name) - # The following statement creates a new class called - # <cls_name> as a subclass of <base_cls> with the attributes - # in tmp_dict, just as if we evaluated a class declaration. - operandNameMap[op_name] = type(cls_name, (base_cls,), tmp_dict) - - # Define operand variables. - operands = userDict.keys() - - operandsREString = (r''' - (?<![\w\.]) # neg. lookbehind assertion: prevent partial matches - ((%s)(?:\.(\w+))?) # match: operand with optional '.' then suffix - (?![\w\.]) # neg. lookahead assertion: prevent partial matches - ''' - % string.join(operands, '|')) - - global operandsRE - operandsRE = re.compile(operandsREString, re.MULTILINE|re.VERBOSE) - - # Same as operandsREString, but extension is mandatory, and only two - # groups are returned (base and ext, not full name as above). - # Used for subtituting '_' for '.' to make C++ identifiers. - operandsWithExtREString = (r'(?<![\w\.])(%s)\.(\w+)(?![\w\.])' - % string.join(operands, '|')) - - global operandsWithExtRE - operandsWithExtRE = re.compile(operandsWithExtREString, re.MULTILINE) - - -class OperandList: - - # Find all the operands in the given code block. Returns an operand - # descriptor list (instance of class OperandList). - def __init__(self, code): - self.items = [] - self.bases = {} - # delete comments so we don't match on reg specifiers inside - code = commentRE.sub('', code) - # search for operands - next_pos = 0 - while 1: - match = operandsRE.search(code, next_pos) - if not match: - # no more matches: we're done - break - op = match.groups() - # regexp groups are operand full name, base, and extension - (op_full, op_base, op_ext) = op - # if the token following the operand is an assignment, this is - # a destination (LHS), else it's a source (RHS) - is_dest = (assignRE.match(code, match.end()) != None) - is_src = not is_dest - # see if we've already seen this one - op_desc = self.find_base(op_base) - if op_desc: - if op_desc.ext != op_ext: - error(0, 'Inconsistent extensions for operand %s' % \ - op_base) - op_desc.is_src = op_desc.is_src or is_src - op_desc.is_dest = op_desc.is_dest or is_dest - else: - # new operand: create new descriptor - op_desc = operandNameMap[op_base](op_full, op_ext, - is_src, is_dest) - self.append(op_desc) - # start next search after end of current match - next_pos = match.end() - self.sort() - # enumerate source & dest register operands... used in building - # constructor later - self.numSrcRegs = 0 - self.numDestRegs = 0 - self.numFPDestRegs = 0 - self.numIntDestRegs = 0 - self.memOperand = None - for op_desc in self.items: - if op_desc.isReg(): - if op_desc.is_src: - op_desc.src_reg_idx = self.numSrcRegs - self.numSrcRegs += 1 - if op_desc.is_dest: - op_desc.dest_reg_idx = self.numDestRegs - self.numDestRegs += 1 - if op_desc.isFloatReg(): - self.numFPDestRegs += 1 - elif op_desc.isIntReg(): - self.numIntDestRegs += 1 - elif op_desc.isMem(): - if self.memOperand: - error(0, "Code block has more than one memory operand.") - self.memOperand = op_desc - # now make a final pass to finalize op_desc fields that may depend - # on the register enumeration - for op_desc in self.items: - op_desc.finalize() - - def __len__(self): - return len(self.items) - - def __getitem__(self, index): - return self.items[index] - - def append(self, op_desc): - self.items.append(op_desc) - self.bases[op_desc.base_name] = op_desc - - def find_base(self, base_name): - # like self.bases[base_name], but returns None if not found - # (rather than raising exception) - return self.bases.get(base_name) - - # internal helper function for concat[Some]Attr{Strings|Lists} - def __internalConcatAttrs(self, attr_name, filter, result): - for op_desc in self.items: - if filter(op_desc): - result += getattr(op_desc, attr_name) - return result - - # return a single string that is the concatenation of the (string) - # values of the specified attribute for all operands - def concatAttrStrings(self, attr_name): - return self.__internalConcatAttrs(attr_name, lambda x: 1, '') - - # like concatAttrStrings, but only include the values for the operands - # for which the provided filter function returns true - def concatSomeAttrStrings(self, filter, attr_name): - return self.__internalConcatAttrs(attr_name, filter, '') - - # return a single list that is the concatenation of the (list) - # values of the specified attribute for all operands - def concatAttrLists(self, attr_name): - return self.__internalConcatAttrs(attr_name, lambda x: 1, []) - - # like concatAttrLists, but only include the values for the operands - # for which the provided filter function returns true - def concatSomeAttrLists(self, filter, attr_name): - return self.__internalConcatAttrs(attr_name, filter, []) - - def sort(self): - self.items.sort(lambda a, b: a.sort_pri - b.sort_pri) - -# Regular expression object to match C++ comments -# (used in findOperands()) -commentRE = re.compile(r'//.*\n') - -# Regular expression object to match assignment statements -# (used in findOperands()) -assignRE = re.compile(r'\s*=(?!=)', re.MULTILINE) - -# Munge operand names in code string to make legal C++ variable names. -# This means getting rid of the type extension if any. -# (Will match base_name attribute of Operand object.) -def substMungedOpNames(code): - return operandsWithExtRE.sub(r'\1', code) - -def joinLists(t): - return map(string.join, t) - -def makeFlagConstructor(flag_list): - if len(flag_list) == 0: - return '' - # filter out repeated flags - flag_list.sort() - i = 1 - while i < len(flag_list): - if flag_list[i] == flag_list[i-1]: - del flag_list[i] - else: - i += 1 - pre = '\n\tflags[' - post = '] = true;' - code = pre + string.join(flag_list, post + pre) + post - return code - -class CodeBlock: - def __init__(self, code): - self.orig_code = code - self.operands = OperandList(code) - self.code = substMungedOpNames(substBitOps(code)) - self.constructor = self.operands.concatAttrStrings('constructor') - self.constructor += \ - '\n\t_numSrcRegs = %d;' % self.operands.numSrcRegs - self.constructor += \ - '\n\t_numDestRegs = %d;' % self.operands.numDestRegs - self.constructor += \ - '\n\t_numFPDestRegs = %d;' % self.operands.numFPDestRegs - self.constructor += \ - '\n\t_numIntDestRegs = %d;' % self.operands.numIntDestRegs - - self.op_decl = self.operands.concatAttrStrings('op_decl') - - is_src = lambda op: op.is_src - is_dest = lambda op: op.is_dest - - self.op_src_decl = \ - self.operands.concatSomeAttrStrings(is_src, 'op_src_decl') - self.op_dest_decl = \ - self.operands.concatSomeAttrStrings(is_dest, 'op_dest_decl') - - self.op_rd = self.operands.concatAttrStrings('op_rd') - self.op_wb = self.operands.concatAttrStrings('op_wb') - - self.flags = self.operands.concatAttrLists('flags') - - if self.operands.memOperand: - self.mem_acc_size = self.operands.memOperand.mem_acc_size - self.mem_acc_type = self.operands.memOperand.mem_acc_type - - # Make a basic guess on the operand class (function unit type). - # These are good enough for most cases, and will be overridden - # later otherwise. - if 'IsStore' in self.flags: - self.op_class = 'MemWriteOp' - elif 'IsLoad' in self.flags or 'IsPrefetch' in self.flags: - self.op_class = 'MemReadOp' - elif 'IsFloating' in self.flags: - self.op_class = 'FloatAddOp' - else: - self.op_class = 'IntAluOp' - -# Assume all instruction flags are of the form 'IsFoo' -instFlagRE = re.compile(r'Is.*') - -# OpClass constants end in 'Op' except No_OpClass -opClassRE = re.compile(r'.*Op|No_OpClass') - -class InstObjParams: - def __init__(self, mnem, class_name, base_class = '', - code_block = None, opt_args = []): - self.mnemonic = mnem - self.class_name = class_name - self.base_class = base_class - if code_block: - for code_attr in code_block.__dict__.keys(): - setattr(self, code_attr, getattr(code_block, code_attr)) - else: - self.constructor = '' - self.flags = [] - # Optional arguments are assumed to be either StaticInst flags - # or an OpClass value. To avoid having to import a complete - # list of these values to match against, we do it ad-hoc - # with regexps. - for oa in opt_args: - if instFlagRE.match(oa): - self.flags.append(oa) - elif opClassRE.match(oa): - self.op_class = oa - else: - error(0, 'InstObjParams: optional arg "%s" not recognized ' - 'as StaticInst::Flag or OpClass.' % oa) - - # add flag initialization to contructor here to include - # any flags added via opt_args - self.constructor += makeFlagConstructor(self.flags) - - # if 'IsFloating' is set, add call to the FP enable check - # function (which should be provided by isa_desc via a declare) - if 'IsFloating' in self.flags: - self.fp_enable_check = 'fault = checkFpEnableFault(xc);' - else: - self.fp_enable_check = '' - -####################### -# -# Output file template -# - -file_template = ''' -/* - * DO NOT EDIT THIS FILE!!! - * - * It was automatically generated from the ISA description in %(filename)s - */ - -%(includes)s - -%(global_output)s - -namespace %(namespace)s { - -%(namespace_output)s - -} // namespace %(namespace)s - -%(decode_function)s -''' - - -# Update the output file only if the new contents are different from -# the current contents. Minimizes the files that need to be rebuilt -# after minor changes. -def update_if_needed(file, contents): - update = False - if os.access(file, os.R_OK): - f = open(file, 'r') - old_contents = f.read() - f.close() - if contents != old_contents: - print 'Updating', file - os.remove(file) # in case it's write-protected - update = True - else: - print 'File', file, 'is unchanged' - else: - print 'Generating', file - update = True - if update: - f = open(file, 'w') - f.write(contents) - f.close() - -# This regular expression matches '##include' directives -includeRE = re.compile(r'^\s*##include\s+"(?P<filename>[\w/.-]*)".*$', - re.MULTILINE) - -# Function to replace a matched '##include' directive with the -# contents of the specified file (with nested ##includes replaced -# recursively). 'matchobj' is an re match object (from a match of -# includeRE) and 'dirname' is the directory relative to which the file -# path should be resolved. -def replace_include(matchobj, dirname): - fname = matchobj.group('filename') - full_fname = os.path.normpath(os.path.join(dirname, fname)) - contents = '##newfile "%s"\n%s\n##endfile\n' % \ - (full_fname, read_and_flatten(full_fname)) - return contents - -# Read a file and recursively flatten nested '##include' files. -def read_and_flatten(filename): - current_dir = os.path.dirname(filename) - try: - contents = open(filename).read() - except IOError: - error(0, 'Error including file "%s"' % filename) - fileNameStack.push((filename, 0)) - # Find any includes and include them - contents = includeRE.sub(lambda m: replace_include(m, current_dir), - contents) - fileNameStack.pop() - return contents - -# -# Read in and parse the ISA description. -# -def parse_isa_desc(isa_desc_file, output_dir): - # Read file and (recursively) all included files into a string. - # PLY requires that the input be in a single string so we have to - # do this up front. - isa_desc = read_and_flatten(isa_desc_file) - - # Initialize filename stack with outer file. - fileNameStack.push((isa_desc_file, 0)) - - # Parse it. - (isa_name, namespace, global_code, namespace_code) = yacc.parse(isa_desc) - - # grab the last three path components of isa_desc_file to put in - # the output - filename = '/'.join(isa_desc_file.split('/')[-3:]) - - # generate decoder.hh - includes = '#include "base/bitfield.hh" // for bitfield support' - global_output = global_code.header_output - namespace_output = namespace_code.header_output - decode_function = '' - update_if_needed(output_dir + '/decoder.hh', file_template % vars()) - - # generate decoder.cc - includes = '#include "decoder.hh"' - global_output = global_code.decoder_output - namespace_output = namespace_code.decoder_output - # namespace_output += namespace_code.decode_block - decode_function = namespace_code.decode_block - update_if_needed(output_dir + '/decoder.cc', file_template % vars()) - - # generate per-cpu exec files - for cpu in cpu_models: - includes = '#include "decoder.hh"\n' - includes += cpu.includes - global_output = global_code.exec_output[cpu.name] - namespace_output = namespace_code.exec_output[cpu.name] - decode_function = '' - update_if_needed(output_dir + '/' + cpu.filename, - file_template % vars()) - -# global list of CpuModel objects (see cpu_models.py) -cpu_models = [] - -# Called as script: get args from command line. -# Args are: <path to cpu_models.py> <isa desc file> <output dir> <cpu models> -if __name__ == '__main__': - execfile(sys.argv[1]) # read in CpuModel definitions - cpu_models = [CpuModel.dict[cpu] for cpu in sys.argv[4:]] - parse_isa_desc(sys.argv[2], sys.argv[3]) diff --git a/arch/isa_specific.hh b/arch/isa_specific.hh deleted file mode 100644 index 44f8e9d64..000000000 --- a/arch/isa_specific.hh +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __ARCH_ISA_SPECIFIC_HH__ -#define __ARCH_ISA_SPECIFIC_HH__ - -//This file provides a mechanism for other source code to bring in -//files from the ISA being compiled with - -//These are constants so you can selective compile code based on the isa -//To use them, do something like -// -//#if THE_ISA == YOUR_FAVORITE_ISA -// conditional_code -//#endif -// -//Note that this is how this file sets up the other isa "hooks" - -//These macros have numerical values because otherwise the preprocessor -//would treat them as 0 in comparisons. -#define ALPHA_ISA 21064 -#define SPARC_ISA 42 -#define MIPS_ISA 1337 - -//These tell the preprocessor where to find the files of a particular -//ISA, and set the "TheISA" macro for use elsewhere. -#if THE_ISA == ALPHA_ISA - #define TheISA AlphaISA -#elif THE_ISA == SPARC_ISA - #define TheISA SparcISA -#elif THE_ISA == MIPS_ISA - #define TheISA MipsISA -#else - #error "THE_ISA not set" -#endif - -#endif diff --git a/arch/mips/SConscript b/arch/mips/SConscript deleted file mode 100644 index b8efa7ef9..000000000 --- a/arch/mips/SConscript +++ /dev/null @@ -1,83 +0,0 @@ -# -*- mode:python -*- - -# Copyright (c) 2004-2005 The Regents of The University of Michigan -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer; -# redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution; -# neither the name of the copyright holders nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -import os -import sys -from os.path import isdir - -# Import build environment variable from SConstruct. -Import('env') - -################################################### -# -# Define needed sources. -# -################################################### - -# Base sources used by all configurations. -base_sources = Split(''' - faults.cc - isa_traits.cc - ''') - -# Full-system sources -full_system_sources = Split(''' - memory.cc - arguments.cc - mips34k.cc - osfpal.cc - stacktrace.cc - vtophys.cc - ''') - -# Syscall emulation (non-full-system) sources -syscall_emulation_sources = Split(''' - common_syscall_emul.cc - linux_process.cc - tru64_process.cc - ''') - -# Set up complete list of sources based on configuration. -sources = base_sources - -if env['FULL_SYSTEM']: - sources += full_system_sources -else: - sources += syscall_emulation_sources - -# Convert file names to SCons File objects. This takes care of the -# path relative to the top of the directory tree. -sources = [File(s) for s in sources] - -# Add in files generated by the ISA description. -isa_desc_files = env.ISADesc('isa/main.isa') -# Only non-header files need to be compiled. -isa_desc_sources = [f for f in isa_desc_files if not f.path.endswith('.hh')] -sources += isa_desc_sources - -Return('sources') diff --git a/arch/mips/faults.cc b/arch/mips/faults.cc deleted file mode 100644 index 142dfe0a4..000000000 --- a/arch/mips/faults.cc +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "arch/mips/faults.hh" - -ResetFaultType * const ResetFault = - new ResetFaultType("reset", 1, 0x0001); -ArithmeticFaultType * const ArithmeticFault = - new ArithmeticFaultType("arith", 3, 0x0501); -InterruptFaultType * const InterruptFault = - new InterruptFaultType("interrupt", 4, 0x0101); -NDtbMissFaultType * const NDtbMissFault = - new NDtbMissFaultType("dtb_miss_single", 5, 0x0201); -PDtbMissFaultType * const PDtbMissFault = - new PDtbMissFaultType("dtb_miss_double", 6, 0x0281); -DtbPageFaultType * const DtbPageFault = - new DtbPageFaultType("dfault", 8, 0x0381); -DtbAcvFaultType * const DtbAcvFault = - new DtbAcvFaultType("dfault", 9, 0x0381); -ItbMissFaultType * const ItbMissFault = - new ItbMissFaultType("itbmiss", 10, 0x0181); -ItbPageFaultType * const ItbPageFault = - new ItbPageFaultType("itbmiss", 11, 0x0181); -ItbAcvFaultType * const ItbAcvFault = - new ItbAcvFaultType("iaccvio", 12, 0x0081); -UnimplementedOpcodeFaultType * const UnimplementedOpcodeFault = - new UnimplementedOpcodeFaultType("opdec", 13, 0x0481); -FloatEnableFaultType * const FloatEnableFault = - new FloatEnableFaultType("fen", 14, 0x0581); -PalFaultType * const PalFault = - new PalFaultType("pal", 15, 0x2001); -IntegerOverflowFaultType * const IntegerOverflowFault = - new IntegerOverflowFaultType("intover", 16, 0x0501); - -Fault ** ListOfFaults[] = { - (Fault **)&NoFault, - (Fault **)&ResetFault, - (Fault **)&MachineCheckFault, - (Fault **)&ArithmeticFault, - (Fault **)&InterruptFault, - (Fault **)&NDtbMissFault, - (Fault **)&PDtbMissFault, - (Fault **)&AlignmentFault, - (Fault **)&DtbPageFault, - (Fault **)&DtbAcvFault, - (Fault **)&ItbMissFault, - (Fault **)&ItbPageFault, - (Fault **)&ItbAcvFault, - (Fault **)&UnimplementedOpcodeFault, - (Fault **)&FloatEnableFault, - (Fault **)&PalFault, - (Fault **)&IntegerOverflowFault, - }; - -int NumFaults = sizeof(ListOfFaults) / sizeof(Fault **); diff --git a/arch/mips/faults.hh b/arch/mips/faults.hh deleted file mode 100644 index c1cb956b0..000000000 --- a/arch/mips/faults.hh +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __MIPS_FAULTS_HH__ -#define __MIPS_FAULTS_HH__ - -#include "sim/faults.hh" -#include "arch/isa_traits.hh" //For the Addr type - -class MipsFault : public FaultBase -{ - public: - MipsFault(char * newName, int newId, Addr newVect) - : FaultBase(newName, newId), vect(newVect) - {;} - - Addr vect; -}; - -extern class ResetFaultType : public MipsFault -{ - public: - ResetFaultType(char * newName, int newId, Addr newVect) - : MipsFault(newName, newId, newVect) - {;} -} * const ResetFault; - -extern class ArithmeticFaultType : public MipsFault -{ - public: - ArithmeticFaultType(char * newName, int newId, Addr newVect) - : MipsFault(newName, newId, newVect) - {;} -} * const ArithmeticFault; - -extern class InterruptFaultType : public MipsFault -{ - public: - InterruptFaultType(char * newName, int newId, Addr newVect) - : MipsFault(newName, newId, newVect) - {;} -} * const InterruptFault; - -extern class NDtbMissFaultType : public MipsFault -{ - public: - NDtbMissFaultType(char * newName, int newId, Addr newVect) - : MipsFault(newName, newId, newVect) - {;} -} * const NDtbMissFault; - -extern class PDtbMissFaultType : public MipsFault -{ - public: - PDtbMissFaultType(char * newName, int newId, Addr newVect) - : MipsFault(newName, newId, newVect) - {;} -} * const PDtbMissFault; - -extern class DtbPageFaultType : public MipsFault -{ - public: - DtbPageFaultType(char * newName, int newId, Addr newVect) - : MipsFault(newName, newId, newVect) - {;} -} * const DtbPageFault; - -extern class DtbAcvFaultType : public MipsFault -{ - public: - DtbAcvFaultType(char * newName, int newId, Addr newVect) - : MipsFault(newName, newId, newVect) - {;} -} * const DtbAcvFault; - -extern class ItbMissFaultType : public MipsFault -{ - public: - ItbMissFaultType(char * newName, int newId, Addr newVect) - : MipsFault(newName, newId, newVect) - {;} -} * const ItbMissFault; - -extern class ItbPageFaultType : public MipsFault -{ - public: - ItbPageFaultType(char * newName, int newId, Addr newVect) - : MipsFault(newName, newId, newVect) - {;} -} * const ItbPageFault; - -extern class ItbAcvFaultType : public MipsFault -{ - public: - ItbAcvFaultType(char * newName, int newId, Addr newVect) - : MipsFault(newName, newId, newVect) - {;} -} * const ItbAcvFault; - -extern class UnimplementedOpcodeFaultType : public MipsFault -{ - public: - UnimplementedOpcodeFaultType(char * newName, int newId, Addr newVect) - : MipsFault(newName, newId, newVect) - {;} -} * const UnimplementedOpcodeFault; - -extern class FloatEnableFaultType : public MipsFault -{ - public: - FloatEnableFaultType(char * newName, int newId, Addr newVect) - : MipsFault(newName, newId, newVect) - {;} -} * const FloatEnableFault; - -extern class PalFaultType : public MipsFault -{ - public: - PalFaultType(char * newName, int newId, Addr newVect) - : MipsFault(newName, newId, newVect) - {;} -} * const PalFault; - -extern class IntegerOverflowFaultType : public MipsFault -{ - public: - IntegerOverflowFaultType(char * newName, int newId, Addr newVect) - : MipsFault(newName, newId, newVect) - {;} -} * const IntegerOverflowFault; - -extern Fault ** ListOfFaults[]; -extern int NumFaults; - -#endif // __FAULTS_HH__ diff --git a/arch/mips/isa/base.isa b/arch/mips/isa/base.isa deleted file mode 100644 index 4125b5101..000000000 --- a/arch/mips/isa/base.isa +++ /dev/null @@ -1,96 +0,0 @@ -// -*- mode:c++ -*- - -//////////////////////////////////////////////////////////////////// -// -// Base class for MIPS instructions, and some support functions -// - -//Outputs to decoder.hh -output header {{ - -#define R31 31 -#include "arch/mips/faults.hh" -#include "arch/mips/isa_traits.hh" - - using namespace MipsISA; - - - /** - * Base class for all MIPS static instructions. - */ - class MipsStaticInst : public StaticInst - { - protected: - - /// Make MipsISA register dependence tags directly visible in - /// this class and derived classes. Maybe these should really - /// live here and not in the MipsISA namespace. - /*enum DependenceTags { - FP_Base_DepTag = MipsISA::FP_Base_DepTag, - Fpcr_DepTag = MipsISA::Fpcr_DepTag, - Uniq_DepTag = MipsISA::Uniq_DepTag, - IPR_Base_DepTag = MipsISA::IPR_Base_DepTag - };*/ - - // Constructor - MipsStaticInst(const char *mnem, MachInst _machInst, OpClass __opClass) - : StaticInst(mnem, _machInst, __opClass) - { - } - - /// Print a register name for disassembly given the unique - /// dependence tag number (FP or int). - void printReg(std::ostream &os, int reg) const; - - std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; - -}}; - -//Ouputs to decoder.cc -output decoder {{ - - void MipsStaticInst::printReg(std::ostream &os, int reg) const - { - if (reg < FP_Base_DepTag) { - ccprintf(os, "r%d", reg); - } - else { - ccprintf(os, "f%d", reg - FP_Base_DepTag); - } - } - - std::string MipsStaticInst::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { - std::stringstream ss; - - ccprintf(ss, "%-10s ", mnemonic); - - // just print the first two source regs... if there's - // a third one, it's a read-modify-write dest (Rc), - // e.g. for CMOVxx - if(_numSrcRegs > 0) - { - printReg(ss, _srcRegIdx[0]); - } - - if(_numSrcRegs > 1) - { - ss << ","; - printReg(ss, _srcRegIdx[1]); - } - - // just print the first dest... if there's a second one, - // it's generally implicit - if(_numDestRegs > 0) - { - if(_numSrcRegs > 0) - ss << ","; - printReg(ss, _destRegIdx[0]); - } - - return ss.str(); - } - -}}; - diff --git a/arch/mips/isa/bitfields.isa b/arch/mips/isa/bitfields.isa deleted file mode 100644 index 58d487ad2..000000000 --- a/arch/mips/isa/bitfields.isa +++ /dev/null @@ -1,67 +0,0 @@ -// -*- mode:c++ -*- - -//////////////////////////////////////////////////////////////////// -// -// Bitfield definitions. -// - -def bitfield OPCODE <31:26>; -def bitfield OPCODE_HI <31:29>; -def bitfield OPCODE_LO <28:26>; - -def bitfield REGIMM <20:16>; -def bitfield REGIMM_HI <20:19>; -def bitfield REGIMM_LO <18:16>; - -def bitfield FUNCTION < 5: 0>; -def bitfield FUNCTION_HI < 5: 3>; -def bitfield FUNCTION_LO < 2: 0>; - -// Integer operate format -def bitfield RT <20:16>; -def bitfield RT_HI <20:19>; -def bitfield RT_LO <18:16>; - -def bitfield RS <25:21>; -def bitfield RS_MSB <25:25>; -def bitfield RS_HI <25:24>; -def bitfield RS_LO <23:21>; - -def bitfield RD <15:11>; - -def bitfield INTIMM <15: 0>; // integer immediate (literal) - -// Floating-point operate format -def bitfield FMT <25:21>; -def bitfield FR <25:21>; -def bitfield FT <20:16>; -def bitfield FS <15:11>; -def bitfield FD <10:6>; - -def bitfield CC <20:18>; -def bitfield ND <17:17>; -def bitfield TF <16:16>; -def bitfield MOVCI <16:16>; -def bitfield MOVCF <16:16>; -def bitfield SRL <21:21>; -def bitfield SRLV < 6: 6>; -def bitfield SA <10: 6>; - -// CP0 Register Select -def bitfield SEL < 2: 0>; - -// Interrupts -def bitfield SC < 5: 5>; - -// Branch format -def bitfield OFFSET <15: 0>; // displacement - -// Jmp format -def bitfield JMPTARG <25: 0>; -def bitfield HINT <10: 6>; - -def bitfield SYSCALLCODE <25: 6>; -def bitfield TRAPCODE <15:13>; - -// M5 instructions -def bitfield M5FUNC <7:0>; diff --git a/arch/mips/isa/decoder.isa b/arch/mips/isa/decoder.isa deleted file mode 100644 index 3f054f6a5..000000000 --- a/arch/mips/isa/decoder.isa +++ /dev/null @@ -1,930 +0,0 @@ -// -*- mode:c++ -*- - -//////////////////////////////////////////////////////////////////// -// -// The actual MIPS32 ISA decoder -// ----------------------------- -// The following instructions are specified in the MIPS32 ISA -// Specification. Decoding closely follows the style specified -// in the MIPS32 ISAthe specification document starting with Table -// A-2 (document available @ www.mips.com) -// -//@todo: Distinguish "unknown/future" use insts from "reserved" -// ones -decode OPCODE_HI default Unknown::unknown() { - - // Derived From ... Table A-2 MIPS32 ISA Manual - 0x0: decode OPCODE_LO { - - 0x0: decode FUNCTION_HI { - 0x0: decode FUNCTION_LO { - 0x1: decode MOVCI { - format BasicOp { - 0: movf({{ if (xc->readMiscReg(FPCR,0) != CC) Rd = Rs}}); - 1: movt({{ if (xc->readMiscReg(FPCR,0) == CC) Rd = Rs}}); - } - } - - format BasicOp { - - //Table A-3 Note: "1. Specific encodings of the rt, rd, and sa fields - //are used to distinguish among the SLL, NOP, SSNOP and EHB functions." - - 0x0: decode RS { - 0x0: decode RT default BasicOp::sll({{ Rd = Rt.uw << SA; }}) { - 0x0: decode RD{ - 0x0: decode HINT { - 0x0:nop({{}}); //really sll r0,r0,0 - 0x1:ssnop({{}});//really sll r0,r0,1 - 0x3:ehb({{}}); //really sll r0,r0,3 - } - } - } - } - - 0x2: decode SRL { - 0: srl({{ Rd = Rt.uw >> SA; }}); - - //Hardcoded assuming 32-bit ISA, probably need parameter here - 1: rotr({{ Rd = (Rt.uw << (32 - SA)) | (Rt.uw >> SA);}}); - } - - 0x3: sra({{ Rd = Rt.sw >> SA; }}); - - 0x4: sllv({{ Rd = Rt.uw << Rs<4:0>; }}); - - 0x6: decode SRLV { - 0: srlv({{ Rd = Rt.uw >> Rs<4:0>; }}); - - //Hardcoded assuming 32-bit ISA, probably need parameter here - 1: rotrv({{ Rd = (Rt.uw << (32 - Rs<4:0>)) | (Rt.uw >> Rs<4:0>);}}); - } - - 0x7: srav({{ Rd = Rt.sw >> Rs<4:0>; }}); - } - } - - 0x1: decode FUNCTION_LO { - - //Table A-3 Note: "Specific encodings of the hint field are used - //to distinguish JR from JR.HB and JALR from JALR.HB" - format Jump { - 0x0: decode HINT { - 0:jr({{ NNPC = Rs & ~1; }},IsReturn); - - 1:jr_hb({{ NNPC = Rs & ~1; clear_exe_inst_hazards(); }},IsReturn); - } - - 0x1: decode HINT { - 0: jalr({{ NNPC = Rs; }},IsCall,IsReturn); - - 1: jalr_hb({{ NNPC = Rs; clear_exe_inst_hazards();}},IsCall,IsReturn); - } - } - - format BasicOp { - 0x2: movz({{ if (Rt == 0) Rd = Rs; }}); - 0x3: movn({{ if (Rt != 0) Rd = Rs; }}); - } - - format WarnUnimpl { - 0x4: syscall();//{{ xc->syscall()}},IsNonSpeculative - 0x5: break(); - 0x7: sync(); - } - } - - 0x2: decode FUNCTION_LO { - format BasicOp { - 0x0: mfhi({{ Rd = xc->readMiscReg(Hi); }}); - 0x1: mthi({{ xc->setMiscReg(Hi,Rs); }}); - 0x2: mflo({{ Rd = xc->readMiscReg(Lo); }}); - 0x3: mtlo({{ xc->setMiscReg(Lo,Rs); }}); - } - } - - 0x3: decode FUNCTION_LO { - format IntOp { - 0x0: mult({{ - int64_t temp1 = Rs.sw * Rt.sw; - xc->setMiscReg(Hi,temp1<63:32>); - xc->setMiscReg(Lo,temp1<31:0>); - }}); - - 0x1: multu({{ - int64_t temp1 = Rs.uw * Rt.uw; - xc->setMiscReg(Hi,temp1<63:32>); - xc->setMiscReg(Lo,temp1<31:0>); - }}); - - 0x2: div({{ - xc->setMiscReg(Hi,Rs.sw % Rt.sw); - xc->setMiscReg(Lo,Rs.sw / Rt.sw); - }}); - - 0x3: divu({{ - xc->setMiscReg(Hi,Rs.uw % Rt.uw); - xc->setMiscReg(Lo,Rs.uw / Rt.uw); - }}); - } - } - - 0x4: decode FUNCTION_LO { - format IntOp { - 0x0: add({{ Rd.sw = Rs.sw + Rt.sw;/*Trap on Overflow*/}}); - 0x1: addu({{ Rd.sw = Rs.sw + Rt.sw;}}); - 0x2: sub({{ Rd.sw = Rs.sw - Rt.sw; /*Trap on Overflow*/}}); - 0x3: subu({{ Rd.sw = Rs.sw - Rt.uw;}}); - 0x4: and({{ Rd = Rs & Rt;}}); - 0x5: or({{ Rd = Rs | Rt;}}); - 0x6: xor({{ Rd = Rs ^ Rt;}}); - 0x7: nor({{ Rd = ~(Rs | Rt);}}); - } - } - - 0x5: decode FUNCTION_LO { - format IntOp{ - 0x2: slt({{ Rd.sw = ( Rs.sw < Rt.sw ) ? 1 : 0}}); - 0x3: sltu({{ Rd.uw = ( Rs.uw < Rt.uw ) ? 1 : 0}}); - } - } - - 0x6: decode FUNCTION_LO { - format Trap { - 0x0: tge({{ cond = (Rs.sw >= Rt.sw); }}); - 0x1: tgeu({{ cond = (Rs.uw >= Rt.uw); }}); - 0x2: tlt({{ cond = (Rs.sw < Rt.sw); }}); - 0x3: tltu({{ cond = (Rs.uw >= Rt.uw); }}); - 0x4: teq({{ cond = (Rs.sw == Rt.sw); }}); - 0x6: tne({{ cond = (Rs.sw != Rt.sw); }}); - } - } - } - - 0x1: decode REGIMM_HI { - 0x0: decode REGIMM_LO { - format Branch { - 0x0: bltz({{ cond = (Rs.sw < 0); }}); - 0x1: bgez({{ cond = (Rs.sw >= 0); }}); - } - - format BranchLikely { - //MIPS obsolete instructions - 0x2: bltzl({{ cond = (Rs.sw < 0); }}); - 0x3: bgezl({{ cond = (Rs.sw >= 0); }}); - } - } - - 0x1: decode REGIMM_LO { - format Trap { - 0x0: tgei( {{ cond = (Rs.sw >= INTIMM); }}); - 0x1: tgeiu({{ cond = (Rs.uw >= INTIMM); }}); - 0x2: tlti( {{ cond = (Rs.sw < INTIMM); }}); - 0x3: tltiu({{ cond = (Rs.uw < INTIMM); }}); - 0x4: teqi( {{ cond = (Rs.sw == INTIMM);}}); - 0x6: tnei( {{ cond = (Rs.sw != INTIMM);}}); - } - } - - 0x2: decode REGIMM_LO { - format Branch { - 0x0: bltzal({{ cond = (Rs.sw < 0); }}, IsCall,IsReturn); - 0x1: bgezal({{ cond = (Rs.sw >= 0); }}, IsCall,IsReturn); - } - - format BranchLikely { - //Will be removed in future MIPS releases - 0x2: bltzall({{ cond = (Rs.sw < 0); }}, IsCall, IsReturn); - 0x3: bgezall({{ cond = (Rs.sw >= 0); }}, IsCall, IsReturn); - } - } - - 0x3: decode REGIMM_LO { - format WarnUnimpl { - 0x7: synci(); - } - } - } - - format Jump { - 0x2: j({{ NNPC = (NPC & 0xF0000000) | (JMPTARG << 2);}}); - - 0x3: jal({{ NNPC = (NPC & 0xF0000000) | (JMPTARG << 2); }},IsCall,IsReturn); - } - - format Branch { - 0x4: beq({{ cond = (Rs.sw == Rt.sw); }}); - 0x5: bne({{ cond = (Rs.sw != Rt.sw); }}); - 0x6: blez({{ cond = (Rs.sw <= 0); }}); - 0x7: bgtz({{ cond = (Rs.sw > 0); }}); - } - } - - 0x1: decode OPCODE_LO { - format IntOp { - 0x0: addi({{ Rt.sw = Rs.sw + imm; /*Trap If Overflow*/}}); - 0x1: addiu({{ Rt.sw = Rs.sw + imm;}}); - 0x2: slti({{ Rt.sw = ( Rs.sw < imm) ? 1 : 0 }}); - 0x3: sltiu({{ Rt.sw = ( Rs.sw < imm ) ? 1 : 0 }}); - 0x4: andi({{ Rt.sw = Rs.sw & INTIMM;}}); - 0x5: ori({{ Rt.sw = Rs.sw | INTIMM;}}); - 0x6: xori({{ Rt.sw = Rs.sw ^ INTIMM;}}); - 0x7: lui({{ Rt = INTIMM << 16}}); - } - } - - 0x2: decode OPCODE_LO { - - //Table A-11 MIPS32 COP0 Encoding of rs Field - 0x0: decode RS_MSB { - 0x0: decode RS { - format System { - 0x0: mfc0({{ - //uint64_t reg_num = Rd.uw; - - Rt = xc->readMiscReg(RD << 5 | SEL); - }}); - - 0x4: mtc0({{ - //uint64_t reg_num = Rd.uw; - - xc->setMiscReg(RD << 5 | SEL,Rt); - }}); - - 0x8: mftr({{ - //The contents of the coprocessor 0 register specified by the - //combination of rd and sel are loaded into general register - //rt. Note that not all coprocessor 0 registers support the - //sel field. In those instances, the sel field must be zero. - - //MT Code Needed Here - }}); - - 0xC: mttr({{ - //The contents of the coprocessor 0 register specified by the - //combination of rd and sel are loaded into general register - //rt. Note that not all coprocessor 0 registers support the - //sel field. In those instances, the sel field must be zero. - - //MT Code Needed Here - }}); - - - 0xA: rdpgpr({{ - //Accessing Previous Shadow Set Register Number - //uint64_t prev = xc->readMiscReg(SRSCtl)/*[PSS]*/; - //uint64_t reg_num = Rt.uw; - - //Rd = xc->regs.IntRegFile[prev]; - //Rd = xc->shadowIntRegFile[prev][reg_num]; - }}); - - 0xB: decode RD { - - 0x0: decode SC { - 0x0: dvpe({{ - int idx; - int sel; - getMiscRegIdx(MVPControl,idx,sel); - Rt.sw = xc->readMiscReg(idx,sel); - xc->setMiscReg(idx,sel); - }}); - - 0x1: evpe({{ - int idx; - int sel; - getMiscRegIdx(MVPControl,idx,sel); - Rt.sw = xc->readMiscReg(idx,sel); - xc->setMiscReg(idx,sel,1); - }}); - } - - 0x1: decode SC { - 0x0: dmt({{ - int idx; - int sel; - getMiscRegIdx(VPEControl,idx,sel); - Rt.sw = xc->readMiscReg(idx,sel); - xc->setMiscReg(idx,sel); - }}); - - 0x1: emt({{ - int idx; - int sel; - getMiscRegIdx(VPEControl,idx,sel); - Rt.sw = xc->readMiscReg(idx,sel); - xc->setMiscReg(idx,sel,1); - }}); - } - - 0xC: decode SC { - 0x0: di({{ - int idx; - int sel; - getMiscRegIdx(Status,idx,sel); - Rt.sw = xc->readMiscReg(idx,sel); - xc->setMiscReg(idx,sel); - }}); - - 0x1: ei({{ - int idx; - int sel; - getMiscRegIdx(Status,idx,sel); - Rt.sw = xc->readMiscReg(idx,sel); - xc->setMiscReg(idx,sel,1); - }}); - } - } - - 0xE: wrpgpr({{ - //Accessing Previous Shadow Set Register Number - //uint64_t prev = xc->readMiscReg(SRSCtl/*[PSS]*/); - //uint64_t reg_num = Rd.uw; - - //xc->regs.IntRegFile[prev]; - //xc->shadowIntRegFile[prev][reg_num] = Rt; - }}); - } - } - - //Table A-12 MIPS32 COP0 Encoding of Function Field When rs=CO - 0x1: decode FUNCTION { - format System { - 0x01: tlbr({{ }}); - 0x02: tlbwi({{ }}); - 0x06: tlbwr({{ }}); - 0x08: tlbp({{ }}); - } - - format WarnUnimpl { - 0x18: eret(); - 0x1F: deret(); - 0x20: wait(); - } - } - } - - //Table A-13 MIPS32 COP1 Encoding of rs Field - 0x1: decode RS_MSB { - - 0x0: decode RS_HI { - 0x0: decode RS_LO { - format FloatOp { - 0x0: mfc1({{ /*Rt.uw = Fs.ud<31:0>;*/ }}); - 0x2: cfc1({{ /*Rt.uw = xc->readMiscReg(FPCR[Fs]);*/}}); - 0x3: mfhc1({{ /*Rt.uw = Fs.ud<63:32>*/;}}); - 0x4: mtc1({{ /*Fs = Rt.uw*/}}); - 0x6: ctc1({{ /*xc->setMiscReg(FPCR[Fs],Rt);*/}}); - 0x7: mthc1({{ /*Fs<63:32> = Rt.uw*/}}); - } - } - - 0x1: decode ND { - 0x0: decode TF { - format Branch { - 0x0: bc1f({{ cond = (xc->readMiscReg(FPCR) == 0); }}); - 0x1: bc1t({{ cond = (xc->readMiscReg(FPCR) == 1); }}); - } - } - - 0x1: decode TF { - format BranchLikely { - 0x0: bc1fl({{ cond = (xc->readMiscReg(FPCR) == 0); }}); - 0x1: bc1tl({{ cond = (xc->readMiscReg(FPCR) == 1); }}); - } - } - } - } - - 0x1: decode RS_HI { - 0x2: decode RS_LO { - - //Table A-14 MIPS32 COP1 Encoding of Function Field When rs=S - //(( single-word )) - 0x0: decode RS_HI { - 0x0: decode RS_LO { - format FloatOp { - 0x0: adds({{ Fd.sf = Fs.sf + Ft.sf;}}); - 0x1: subs({{ Fd.sf = Fs.sf - Ft.sf;}}); - 0x2: muls({{ Fd.sf = Fs.sf * Ft.sf;}}); - 0x3: divs({{ Fd.sf = Fs.sf / Ft.sf;}}); - 0x4: sqrts({{ Fd.sf = sqrt(Fs.sf);}}); - 0x5: abss({{ Fd.sf = fabs(Fs.sf);}}); - 0x6: movs({{ Fd.sf = Fs.sf;}}); - 0x7: negs({{ Fd.sf = -1 * Fs.sf;}}); - } - } - - 0x1: decode RS_LO { - //only legal for 64 bit-FP - format Float64Op { - 0x0: round_l_s({{ Fd = convert_and_round(Fs.sf,RND_NEAREST,FP_LONG,FP_SINGLE);}}); - 0x1: trunc_l_s({{ Fd = convert_and_round(Fs.sf,RND_ZERO,FP_LONG,FP_SINGLE);}}); - 0x2: ceil_l_s({{ Fd = convert_and_round(Fs.sf,RND_UP,FP_LONG,FP_SINGLE);}}); - 0x3: floor_l_s({{ Fd = convert_and_round(Fs.sf,RND_DOWN,FP_LONG,FP_SINGLE);}}); - } - - format FloatOp { - 0x4: round_w_s({{ Fd = convert_and_round(Fs.sf,RND_NEAREST,FP_WORD,FP_SINGLE);}}); - 0x5: trunc_w_s({{ Fd = convert_and_round(Fs.sf,RND_ZERO,FP_WORD,FP_SINGLE);}}); - 0x6: ceil_w_s({{ Fd = convert_and_round(Fs.sf,RND_UP,FP_WORD,FP_SINGLE);}}); - 0x7: floor_w_s({{ Fd = convert_and_round(Fs.sf,RND_DOWN,FP_WORD,FP_SINGLE);}}); - } - } - - 0x2: decode RS_LO { - 0x1: decode MOVCF { - format FloatOp { - 0x0: movfs({{if (xc->readMiscReg(FPCR) != CC) Fd = Fs; }}); - 0x1: movts({{if (xc->readMiscReg(FPCR) == CC) Fd = Fs;}}); - } - } - - format BasicOp { - 0x2: movzs({{ if (Rt == 0) Fd = Fs; }}); - 0x3: movns({{ if (Rt != 0) Fd = Fs; }}); - } - - format Float64Op { - 0x5: recips({{ Fd = 1 / Fs; }}); - 0x6: rsqrts({{ Fd = 1 / sqrt((double)Fs.ud);}}); - } - } - - 0x4: decode RS_LO { - - format FloatOp { - 0x1: cvt_d_s({{ int rnd_mode = xc->readMiscReg(FCSR); - Fd = convert_and_round(Fs.sf,rnd_mode,FP_DOUBLE,FP_SINGLE); - }}); - - 0x4: cvt_w_s({{ int rnd_mode = xc->readMiscReg(FCSR); - Fd = convert_and_round(Fs.sf,rnd_mode,FP_WORD,FP_SINGLE); - }}); - } - - //only legal for 64 bit - format Float64Op { - 0x5: cvt_l_s({{ int rnd_mode = xc->readMiscReg(FCSR); - Fd = convert_and_round(Fs.sf,rnd_mode,FP_LONG,FP_SINGLE); - }}); - - 0x6: cvt_ps_s({{ /*Fd.df = Fs.df<31:0> | Ft.df<31:0>;*/ }}); - } - } - } - - //Table A-15 MIPS32 COP1 Encoding of Function Field When rs=D - 0x1: decode RS_HI { - 0x0: decode RS_LO { - format FloatOp { - 0x0: addd({{ Fd.df = Fs.df + Ft.df;}}); - 0x1: subd({{ Fd.df = Fs.df - Ft.df;}}); - 0x2: muld({{ Fd.df = Fs.df * Ft.df;}}); - 0x3: divd({{ Fd.df = Fs.df / Ft.df;}}); - 0x4: sqrtd({{ Fd.df = sqrt(Fs.df);}}); - 0x5: absd({{ Fd.df = fabs(Fs.df);}}); - 0x6: movd({{ Fd.df = Fs.df;}}); - 0x7: negd({{ Fd.df = -1 * Fs.df;}}); - } - } - - 0x1: decode RS_LO { - //only legal for 64 bit - format Float64Op { - 0x0: round_l_d({{ Fd = convert_and_round(Fs.df,RND_NEAREST,FP_LONG,FP_DOUBLE); }}); - 0x1: trunc_l_d({{ Fd = convert_and_round(Fs.df,RND_ZERO,FP_LONG,FP_DOUBLE);}}); - 0x2: ceil_l_d({{ Fd = convert_and_round(Fs.df,RND_UP,FP_LONG,FP_DOUBLE);}}); - 0x3: floor_l_d({{ Fd = convert_and_round(Fs.df,RND_DOWN,FP_LONG,FP_DOUBLE);}}); - } - - format FloatOp { - 0x4: round_w_d({{ Fd = convert_and_round(Fs.df,RND_NEAREST,FP_LONG,FP_DOUBLE); }}); - 0x5: trunc_w_d({{ Fd = convert_and_round(Fs.df,RND_ZERO,FP_LONG,FP_DOUBLE); }}); - 0x6: ceil_w_d({{ Fd = convert_and_round(Fs.df,RND_UP,FP_LONG,FP_DOUBLE); }}); - 0x7: floor_w_d({{ Fd = convert_and_round(Fs.df,RND_DOWN,FP_LONG,FP_DOUBLE); }}); - } - } - - 0x2: decode RS_LO { - 0x1: decode MOVCF { - format FloatOp { - 0x0: movfd({{if (xc->readMiscReg(FPCR) != CC) Fd.df = Fs.df; }}); - 0x1: movtd({{if (xc->readMiscReg(FPCR) == CC) Fd.df = Fs.df; }}); - } - } - - format BasicOp { - 0x2: movzd({{ if (Rt == 0) Fd.df = Fs.df; }}); - 0x3: movnd({{ if (Rt != 0) Fd.df = Fs.df; }}); - } - - format Float64Op { - 0x5: recipd({{ Fd.df = 1 / Fs.df}}); - 0x6: rsqrtd({{ Fd.df = 1 / sqrt(Fs.df) }}); - } - } - - 0x4: decode RS_LO { - format FloatOp { - 0x0: cvt_s_d({{ - int rnd_mode = xc->readMiscReg(FCSR); - Fd = convert_and_round(Fs.df,rnd_mode,FP_SINGLE,FP_DOUBLE); - }}); - - 0x4: cvt_w_d({{ - int rnd_mode = xc->readMiscReg(FCSR); - Fd = convert_and_round(Fs.df,rnd_mode,FP_WORD,FP_DOUBLE); - }}); - } - - //only legal for 64 bit - format Float64Op { - 0x5: cvt_l_d({{ - int rnd_mode = xc->readMiscReg(FCSR); - Fd = convert_and_round(Fs.df,rnd_mode,FP_LONG,FP_DOUBLE); - }}); - } - } - } - - //Table A-16 MIPS32 COP1 Encoding of Function Field When rs=W - 0x4: decode FUNCTION { - format FloatOp { - 0x20: cvt_s({{ - int rnd_mode = xc->readMiscReg(FCSR); - Fd = convert_and_round(Fs.df,rnd_mode,FP_SINGLE,FP_WORD); - }}); - - 0x21: cvt_d({{ - int rnd_mode = xc->readMiscReg(FCSR); - Fd = convert_and_round(Fs.df,rnd_mode,FP_DOUBLE,FP_WORD); - }}); - } - } - - //Table A-16 MIPS32 COP1 Encoding of Function Field When rs=L1 - //Note: "1. Format type L is legal only if 64-bit floating point operations - //are enabled." - 0x5: decode FUNCTION_HI { - format FloatOp { - 0x10: cvt_s_l({{ - int rnd_mode = xc->readMiscReg(FCSR); - Fd = convert_and_round(Fs.df,rnd_mode,FP_SINGLE,FP_LONG); - }}); - - 0x11: cvt_d_l({{ - int rnd_mode = xc->readMiscReg(FCSR); - Fd = convert_and_round(Fs.df,rnd_mode,FP_DOUBLE,FP_LONG); - }}); - } - } - - //Table A-17 MIPS64 COP1 Encoding of Function Field When rs=PS1 - //Note: "1. Format type PS is legal only if 64-bit floating point operations - //are enabled. " - 0x6: decode RS_HI { - 0x0: decode RS_LO { - format Float64Op { - 0x0: addps({{ //Must Check for Exception Here... Supposed to Operate on Upper and - //Lower Halves Independently but we take simulator shortcut - Fd.df = Fs.df + Ft.df; - }}); - - 0x1: subps({{ //Must Check for Exception Here... Supposed to Operate on Upper and - //Lower Halves Independently but we take simulator shortcut - Fd.df = Fs.df - Ft.df; - }}); - - 0x2: mulps({{ //Must Check for Exception Here... Supposed to Operate on Upper and - //Lower Halves Independently but we take simulator shortcut - Fd.df = Fs.df * Ft.df; - }}); - - 0x5: absps({{ //Must Check for Exception Here... Supposed to Operate on Upper and - //Lower Halves Independently but we take simulator shortcut - Fd.df = fabs(Fs.df); - }}); - - 0x6: movps({{ //Must Check for Exception Here... Supposed to Operate on Upper and - //Lower Halves Independently but we take simulator shortcut - //Fd.df = Fs<31:0> | Ft<31:0>; - }}); - - 0x7: negps({{ //Must Check for Exception Here... Supposed to Operate on Upper and - //Lower Halves Independently but we take simulator shortcut - Fd.df = -1 * Fs.df; - }}); - } - } - - 0x2: decode RS_LO { - 0x1: decode MOVCF { - format Float64Op { - 0x0: movfps({{if (xc->readMiscReg(FPCR) != CC) Fd = Fs;}}); - 0x1: movtps({{if (xc->readMiscReg(FPCR) == CC) Fd = Fs;}}); - } - } - - format BasicOp { - 0x2: movzps({{if (xc->readMiscReg(FPCR) != CC) Fd = Fs; }}); - 0x3: movnps({{if (xc->readMiscReg(FPCR) == CC) Fd = Fs; }}); - } - - } - - 0x4: decode RS_LO { - 0x0: Float64Op::cvt_s_pu({{ - int rnd_mode = xc->readMiscReg(FCSR); - Fd = convert_and_round(Fs.df,rnd_mode,FP_DOUBLE,FP_PS_HI); - }}); - } - - 0x5: decode RS_LO { - format Float64Op { - 0x0: cvt_s_pl({{ - int rnd_mode = xc->readMiscReg(FCSR); - Fd = convert_and_round(Fs.df,rnd_mode,FP_SINGLE,FP_PS_LO); - }}); - 0x4: pll({{ /*Fd.df = Fs<31:0> | Ft<31:0>*/}}); - 0x5: plu({{ /*Fd.df = Fs<31:0> | Ft<63:32>*/}}); - 0x6: pul({{ /*Fd.df = Fs<63:32> | Ft<31:0>*/}}); - 0x7: puu({{ /*Fd.df = Fs<63:32 | Ft<63:32>*/}}); - } - } - } - } - } - } - - //Table A-19 MIPS32 COP2 Encoding of rs Field - 0x2: decode RS_MSB { - 0x0: decode RS_HI { - 0x0: decode RS_LO { - format WarnUnimpl { - 0x0: mfc2(); - 0x2: cfc2(); - 0x3: mfhc2(); - 0x4: mtc2(); - 0x6: ctc2(); - 0x7: mftc2(); - } - } - - 0x1: decode ND { - 0x0: decode TF { - format WarnUnimpl { - 0x0: bc2f(); - 0x1: bc2t(); - } - } - - 0x1: decode TF { - format WarnUnimpl { - 0x0: bc2fl(); - 0x1: bc2tl(); - } - } - } - } - } - - //Table A-20 MIPS64 COP1X Encoding of Function Field 1 - //Note: "COP1X instructions are legal only if 64-bit floating point - //operations are enabled." - 0x3: decode FUNCTION_HI { - 0x0: decode FUNCTION_LO { - format LoadMemory2 { - 0x0: lwxc1({{ EA = Rs + Rt; }},{{ /*F_t<31:0> = Mem.sf; */}}); - 0x1: ldxc1({{ EA = Rs + Rt; }},{{ /*F_t<63:0> = Mem.df;*/ }}); - 0x5: luxc1({{ //Need to make EA<2:0> = 0 - EA = Rs + Rt; - }}, - {{ /*F_t<31:0> = Mem.df; */}}); - } - } - - 0x1: decode FUNCTION_LO { - format StoreMemory2 { - 0x0: swxc1({{ EA = Rs + Rt; }},{{ /*Mem.sf = Ft<31:0>; */}}); - 0x1: sdxc1({{ EA = Rs + Rt; }},{{ /*Mem.df = Ft<63:0> */}}); - 0x5: suxc1({{ //Need to make EA<2:0> = 0 - EA = Rs + Rt; - }}, - {{ /*Mem.df = F_t<63:0>;*/}}); - } - - 0x7: WarnUnimpl::prefx(); - } - - format FloatOp { - 0x3: WarnUnimpl::alnv_ps(); - - format BasicOp { - 0x4: decode FUNCTION_LO { - 0x0: madd_s({{ Fd.sf = (Fs.sf * Fs.sf) + Fr.sf; }}); - 0x1: madd_d({{ Fd.df = (Fs.df * Fs.df) + Fr.df; }}); - 0x6: madd_ps({{ - //Must Check for Exception Here... Supposed to Operate on Upper and - //Lower Halves Independently but we take simulator shortcut - Fd.df = (Fs.df * Fs.df) + Fr.df; - }}); - } - - 0x5: decode FUNCTION_LO { - 0x0: msub_s({{ Fd.sf = (Fs.sf * Fs.sf) - Fr.sf; }}); - 0x1: msub_d({{ Fd.df = (Fs.df * Fs.df) - Fr.df; }}); - 0x6: msub_ps({{ - //Must Check for Exception Here... Supposed to Operate on Upper and - //Lower Halves Independently but we take simulator shortcut - Fd.df = (Fs.df * Fs.df) - Fr.df; - }}); - } - - 0x6: decode FUNCTION_LO { - 0x0: nmadd_s({{ Fd.sf = (-1 * Fs.sf * Fs.sf) - Fr.sf; }}); - 0x1: nmadd_d({{ Fd.df = (-1 * Fs.df * Fs.df) + Fr.df; }}); - 0x6: nmadd_ps({{ - //Must Check for Exception Here... Supposed to Operate on Upper and - //Lower Halves Independently but we take simulator shortcut - Fd.df = (-1 * Fs.df * Fs.df) + Fr.df; - }}); - } - - 0x7: decode FUNCTION_LO { - 0x0: nmsub_s({{ Fd.sf = (-1 * Fs.sf * Fs.sf) - Fr.sf; }}); - 0x1: nmsub_d({{ Fd.df = (-1 * Fs.df * Fs.df) - Fr.df; }}); - 0x6: nmsub_ps({{ - //Must Check for Exception Here... Supposed to Operate on Upper and - //Lower Halves Independently but we take simulator shortcut - Fd.df = (-1 * Fs.df * Fs.df) + Fr.df; - }}); - } - } - } - } - - //MIPS obsolete instructions - format BranchLikely { - 0x4: beql({{ cond = (Rs.sw == 0); }}); - 0x5: bnel({{ cond = (Rs.sw != 0); }}); - 0x6: blezl({{ cond = (Rs.sw <= 0); }}); - 0x7: bgtzl({{ cond = (Rs.sw > 0); }}); - } - } - - 0x3: decode OPCODE_LO default FailUnimpl::reserved() { - - //Table A-5 MIPS32 SPECIAL2 Encoding of Function Field - 0x4: decode FUNCTION_HI { - - 0x0: decode FUNCTION_LO { - format IntOp { - 0x0: madd({{ - int64_t temp1 = xc->readMiscReg(Hi) << 32 | xc->readMiscReg(Lo) >> 32; - temp1 = temp1 + (Rs.sw * Rt.sw); - xc->setMiscReg(Hi,temp1<63:32>); - xc->setMiscReg(Lo,temp1<31:0>); - }}); - - 0x1: maddu({{ - int64_t temp1 = xc->readMiscReg(Hi) << 32 | xc->readMiscReg(Lo) >> 32; - temp1 = temp1 + (Rs.uw * Rt.uw); - xc->setMiscReg(Hi,temp1<63:32>); - xc->setMiscReg(Lo,temp1<31:0>); - }}); - - 0x2: mul({{ Rd.sw = Rs.sw * Rt.sw; }}); - - 0x4: msub({{ - int64_t temp1 = xc->readMiscReg(Hi) << 32 | xc->readMiscReg(Lo) >> 32; - temp1 = temp1 - (Rs.sw * Rt.sw); - xc->setMiscReg(Hi,temp1<63:32>); - xc->setMiscReg(Lo,temp1<31:0>); - }}); - - 0x5: msubu({{ - int64_t temp1 = xc->readMiscReg(Hi) << 32 | xc->readMiscReg(Lo) >> 32; - temp1 = temp1 - (Rs.uw * Rt.uw); - xc->setMiscReg(Hi,temp1<63:32>); - xc->setMiscReg(Lo,temp1<31:0>); - }}); - } - } - - 0x4: decode FUNCTION_LO { - format BasicOp { - 0x0: clz({{ - /*int cnt = 0; - int idx = 0; - while ( Rs.uw<idx> != 1) { - cnt++; - idx--; - } - - Rd.uw = cnt;*/ - }}); - - 0x1: clo({{ - /*int cnt = 0; - int idx = 0; - while ( Rs.uw<idx> != 0) { - cnt++; - idx--; - } - - Rd.uw = cnt;*/ - }}); - } - } - - 0x7: decode FUNCTION_LO { - 0x7: WarnUnimpl::sdbbp(); - } - } - - //Table A-6 MIPS32 SPECIAL3 Encoding of Function Field for Release 2 of the Architecture - 0x7: decode FUNCTION_HI { - - 0x0: decode FUNCTION_LO { - format WarnUnimpl { - 0x1: ext(); - 0x4: ins(); - } - } - - 0x1: decode FUNCTION_LO { - format WarnUnimpl { - 0x0: fork(); - 0x1: yield(); - } - } - - - //Table A-10 MIPS32 BSHFL Encoding of sa Field - 0x4: decode SA { - - 0x02: WarnUnimpl::wsbh(); - - format BasicOp { - 0x10: seb({{ Rd.sw = /* sext32(Rt<7>,24) | */ Rt<7:0>}}); - 0x18: seh({{ Rd.sw = /* sext32(Rt<15>,16) | */ Rt<15:0>}}); - } - } - - 0x6: decode FUNCTION_LO { - 0x7: BasicOp::rdhwr({{ /*Rt = xc->hwRegs[RD];*/ }}); - } - } - } - - 0x4: decode OPCODE_LO default FailUnimpl::reserved() { - format LoadMemory { - 0x0: lb({{ Rt.sw = Mem.sb; }}); - 0x1: lh({{ Rt.sw = Mem.sh; }}); - 0x2: lwl({{ Rt.sw = Mem.sw; }});//, WordAlign); - 0x3: lw({{ Rt.sw = Mem.sb; }}); - 0x4: lbu({{ Rt.uw = Mem.ub; }}); - 0x5: lhu({{ Rt.uw = Mem.uh; }}); - 0x6: lwr({{ Rt.uw = Mem.uw; }});//, WordAlign); - } - - 0x7: FailUnimpl::reserved(); - } - - 0x5: decode OPCODE_LO default FailUnimpl::reserved() { - format StoreMemory { - 0x0: sb({{ Mem.ub = Rt<7:0>; }}); - 0x1: sh({{ Mem.uh = Rt<15:0>; }}); - 0x2: swl({{ Mem.ub = Rt<31:0>; }});//,WordAlign); - 0x3: sw({{ Mem.ub = Rt<31:0>; }}); - 0x6: swr({{ Mem.ub = Rt<31:0>; }});//,WordAlign); - } - - format WarnUnimpl { - 0x7: cache(); - } - - } - - 0x6: decode OPCODE_LO default FailUnimpl::reserved() { - 0x0: WarnUnimpl::ll(); - - format LoadMemory { - 0x1: lwc1({{ /*F_t<31:0> = Mem.sf; */}}); - 0x5: ldc1({{ /*F_t<63:0> = Mem.df; */}}); - } - } - - - 0x7: decode OPCODE_LO default FailUnimpl::reserved() { - 0x0: WarnUnimpl::sc(); - - format StoreMemory { - 0x1: swc1({{ //Mem.sf = Ft<31:0>; }}); - 0x5: sdc1({{ //Mem.df = Ft<63:0>; }}); - } - } -} - - diff --git a/arch/mips/isa/formats.isa b/arch/mips/isa/formats.isa deleted file mode 100644 index f7a9e4ce2..000000000 --- a/arch/mips/isa/formats.isa +++ /dev/null @@ -1,35 +0,0 @@ -// -*- mode:c++ -*- - -//Templates from this format are used later -//Include the basic format -##include "m5/arch/mips/isa/formats/basic.isa" - -//Include the basic format -##include "m5/arch/mips/isa/formats/noop.isa" - -//Include utility formats/functions -##include "m5/arch/mips/isa/formats/util.isa" - -//Include the cop0 formats -##include "m5/arch/mips/isa/formats/cop0.isa" - -//Include the integer formats -##include "m5/arch/mips/isa/formats/int.isa" - -//Include the floatOp format -##include "m5/arch/mips/isa/formats/fp.isa" - -//Include the mem format -##include "m5/arch/mips/isa/formats/mem.isa" - -//Include the trap format -##include "m5/arch/mips/isa/formats/trap.isa" - -//Include the branch format -##include "m5/arch/mips/isa/formats/branch.isa" - -//Include the noop format -##include "m5/arch/mips/isa/formats/unimp.isa" - -//Include the noop format -##include "m5/arch/mips/isa/formats/unknown.isa" diff --git a/arch/mips/isa/formats/branch.isa b/arch/mips/isa/formats/branch.isa deleted file mode 100644 index 0d2ad7855..000000000 --- a/arch/mips/isa/formats/branch.isa +++ /dev/null @@ -1,322 +0,0 @@ -// -*- mode:c++ -*- - -//////////////////////////////////////////////////////////////////// -// -// Control transfer instructions -// - -output header {{ - -#include <iostream> - using namespace std; - - /** - * Base class for instructions whose disassembly is not purely a - * function of the machine instruction (i.e., it depends on the - * PC). This class overrides the disassemble() method to check - * the PC and symbol table values before re-using a cached - * disassembly string. This is necessary for branches and jumps, - * where the disassembly string includes the target address (which - * may depend on the PC and/or symbol table). - */ - class PCDependentDisassembly : public MipsStaticInst - { - protected: - /// Cached program counter from last disassembly - mutable Addr cachedPC; - - /// Cached symbol table pointer from last disassembly - mutable const SymbolTable *cachedSymtab; - - /// Constructor - PCDependentDisassembly(const char *mnem, MachInst _machInst, - OpClass __opClass) - : MipsStaticInst(mnem, _machInst, __opClass), - cachedPC(0), cachedSymtab(0) - { - } - - const std::string & - disassemble(Addr pc, const SymbolTable *symtab) const; - }; - - /** - * Base class for branches (PC-relative control transfers), - * conditional or unconditional. - */ - class Branch : public PCDependentDisassembly - { - protected: - /// target address (signed) Displacement . - int32_t disp; - - /// Constructor. - Branch(const char *mnem, MachInst _machInst, OpClass __opClass) - : PCDependentDisassembly(mnem, _machInst, __opClass), - disp(OFFSET << 2) - { - //If Bit 17 is 1 then Sign Extend - if ( (disp & 0x00020000) > 0 ) { - disp |= 0xFFFE0000; - } - } - - Addr branchTarget(Addr branchPC) const; - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; - - /** - * Base class for branch likely branches (PC-relative control transfers), - */ - class BranchLikely : public PCDependentDisassembly - { - protected: - /// target address (signed) Displacement . - int32_t disp; - - /// Constructor. - BranchLikely(const char *mnem, MachInst _machInst, OpClass __opClass) - : PCDependentDisassembly(mnem, _machInst, __opClass), - disp(OFFSET << 2) - { - - } - - Addr branchTarget(Addr branchPC) const; - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; - - /** - * Base class for jumps (register-indirect control transfers). In - * the Mips ISA, these are always unconditional. - */ - class Jump : public PCDependentDisassembly - { - protected: - - /// Displacement to target address (signed). - int32_t disp; - - uint32_t target; - - public: - /// Constructor - Jump(const char *mnem, MachInst _machInst, OpClass __opClass) - : PCDependentDisassembly(mnem, _machInst, __opClass), - disp(JMPTARG << 2) - { - } - - Addr branchTarget(ExecContext *xc) const; - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; -}}; - -output decoder {{ - Addr - Branch::branchTarget(Addr branchPC) const - { - return branchPC + 4 + disp; - } - - Addr - BranchLikely::branchTarget(Addr branchPC) const - { - return branchPC + 4 + disp; - } - - Addr - Jump::branchTarget(ExecContext *xc) const - { - Addr NPC = xc->readPC() + 4; - uint64_t Rb = xc->readIntReg(_srcRegIdx[0]); - return (Rb & ~3) | (NPC & 1); - } - - const std::string & - PCDependentDisassembly::disassemble(Addr pc, - const SymbolTable *symtab) const - { - if (!cachedDisassembly || - pc != cachedPC || symtab != cachedSymtab) - { - if (cachedDisassembly) - delete cachedDisassembly; - - cachedDisassembly = - new std::string(generateDisassembly(pc, symtab)); - cachedPC = pc; - cachedSymtab = symtab; - } - - return *cachedDisassembly; - } - - std::string - Branch::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { - std::stringstream ss; - - ccprintf(ss, "%-10s ", mnemonic); - - // There's only one register arg (RA), but it could be - // either a source (the condition for conditional - // branches) or a destination (the link reg for - // unconditional branches) - if (_numSrcRegs == 1) { - printReg(ss, _srcRegIdx[0]); - ss << ","; - } else if(_numSrcRegs == 2) { - printReg(ss, _srcRegIdx[0]); - ss << ","; - printReg(ss, _srcRegIdx[1]); - ss << ","; - } - - Addr target = pc + 8 + disp; - - std::string str; - if (symtab && symtab->findSymbol(target, str)) - ss << str; - else - ccprintf(ss, "0x%x", target); - - return ss.str(); - } - - std::string - BranchLikely::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { - std::stringstream ss; - - ccprintf(ss, "%-10s ", mnemonic); - - // There's only one register arg (RA), but it could be - // either a source (the condition for conditional - // branches) or a destination (the link reg for - // unconditional branches) - if (_numSrcRegs > 0) { - printReg(ss, _srcRegIdx[0]); - ss << ","; - } - else if (_numDestRegs > 0) { - printReg(ss, _destRegIdx[0]); - ss << ","; - } - - Addr target = pc + 4 + disp; - - std::string str; - if (symtab && symtab->findSymbol(target, str)) - ss << str; - else - ccprintf(ss, "0x%x", target); - - return ss.str(); - } - - std::string - Jump::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { - std::stringstream ss; - - ccprintf(ss, "%-10s ", mnemonic); - - if ( mnemonic == "jal" ) { - Addr npc = pc + 4; - ccprintf(ss,"0x%x",(npc & 0xF0000000) | disp); - } else if (_numSrcRegs == 0) { - std::string str; - if (symtab && symtab->findSymbol(disp, str)) - ss << str; - else - ccprintf(ss, "0x%x", disp); - } else if (_numSrcRegs == 1) { - printReg(ss, _srcRegIdx[0]); - } else if(_numSrcRegs == 2) { - printReg(ss, _srcRegIdx[0]); - ss << ","; - printReg(ss, _srcRegIdx[1]); - } else { - panic(">= 3 Source Registers!!!"); - } - - return ss.str(); - } -}}; - -def format Branch(code,*flags) {{ - #Add Link Code if Link instruction - strlen = len(name) - if name[strlen-2:] == 'al': - code += 'r31 = NNPC;\n' - - #Condition code - code = 'bool cond;\n' + code - code += 'if (cond) {\n' - code += ' NNPC = NPC + disp;\n' - code += '} else {\n' - code += ' NNPC = NNPC;\n' - code += '} \n' - - code += 'cout << hex << "NPC: " << NPC << " + " << disp << " = " << NNPC << endl;' - - iop = InstObjParams(name, Name, 'Branch', CodeBlock(code), - ('IsDirectControl', 'IsCondControl')) - - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = BasicDecode.subst(iop) - exec_output = BasicExecute.subst(iop) -}}; - - -def format BranchLikely(code,*flags) {{ - #Add Link Code if Link instruction - strlen = len(name) - if name[strlen-3:] == 'all': - code += 'r31 = NNPC;\n' - - #Condition code - code = 'bool cond;\n' + code - code += 'if (cond) {' - code += 'NNPC = NPC + disp;\n' - code += '} \n' - - - iop = InstObjParams(name, Name, 'Branch', CodeBlock(code), - ('IsDirectControl', 'IsCondControl','IsCondDelaySlot')) - - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = BasicDecode.subst(iop) - exec_output = BasicExecute.subst(iop) -}}; - -def format Jump(code,*flags) {{ - #Add Link Code if Link instruction - strlen = len(name) - if strlen > 1 and name[1:] == 'al': - code = 'r31 = NNPC;\n' + code - - #code += 'if(NNPC == 0x80000638) { NNPC = r31; cout << "SKIPPING JUMP TO SIM_GET_MEM_CONF" << endl;}' - #code += 'target = NNPC;' - - iop = InstObjParams(name, Name, 'Jump', CodeBlock(code),\ - ('IsIndirectControl', 'IsUncondControl')) - - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = BasicDecode.subst(iop) - exec_output = BasicExecute.subst(iop) -}}; - - - - diff --git a/arch/mips/isa/formats/fp.isa b/arch/mips/isa/formats/fp.isa deleted file mode 100644 index 34b71acf7..000000000 --- a/arch/mips/isa/formats/fp.isa +++ /dev/null @@ -1,49 +0,0 @@ -// -*- mode:c++ -*- - -//////////////////////////////////////////////////////////////////// -// -// Floating Point operate instructions -// - -output header {{ - /** - * Base class for FP operations. - */ - class FPOp : public MipsStaticInst - { - protected: - - /// Constructor - FPOp(const char *mnem, MachInst _machInst, OpClass __opClass) : MipsStaticInst(mnem, _machInst, __opClass) - { - } - - std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; -}}; - -output decoder {{ - std::string FPOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { - return "Disassembly of integer instruction\n"; - } -}}; - - -// Primary format for integer operate instructions: -def format FloatOp(code, *flags) {{ - iop = InstObjParams(name, Name, 'MipsStaticInst', CodeBlock(code), flags) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = BasicDecode.subst(iop) - exec_output = BasicExecute.subst(iop) -}}; - -// Primary format for integer operate instructions: -def format Float64Op(code, *flags) {{ - iop = InstObjParams(name, Name, 'MipsStaticInst', CodeBlock(code), flags) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = BasicDecode.subst(iop) - exec_output = BasicExecute.subst(iop) -}}; diff --git a/arch/mips/isa/formats/int.isa b/arch/mips/isa/formats/int.isa deleted file mode 100644 index a47844bee..000000000 --- a/arch/mips/isa/formats/int.isa +++ /dev/null @@ -1,130 +0,0 @@ -// -*- mode:c++ -*- - -//////////////////////////////////////////////////////////////////// -// -// Integer operate instructions -// - -//Outputs to decoder.hh -output header {{ -#include <iostream> - using namespace std; - /** - * Base class for integer operations. - */ - class IntOp : public MipsStaticInst - { - protected: - - /// Constructor - IntOp(const char *mnem, MachInst _machInst, OpClass __opClass) : - MipsStaticInst(mnem, _machInst, __opClass) - { - } - - std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; - - class IntImmOp : public MipsStaticInst - { - protected: - - int32_t imm; - - /// Constructor - IntImmOp(const char *mnem, MachInst _machInst, OpClass __opClass) : - MipsStaticInst(mnem, _machInst, __opClass),imm(INTIMM) - { - //If Bit 15 is 1 then Sign Extend - int32_t temp = imm & 0x00008000; - - if (temp > 0 && mnemonic != "lui") { - imm |= 0xFFFF0000; - } - } - - std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; - - - }; - -}}; - -//Outputs to decoder.cc -output decoder {{ - std::string IntOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { - std::stringstream ss; - - ccprintf(ss, "%-10s ", mnemonic); - - // just print the first dest... if there's a second one, - // it's generally implicit - if (_numDestRegs > 0) { - printReg(ss, _destRegIdx[0]); - } - - ss << ","; - - // just print the first two source regs... if there's - // a third one, it's a read-modify-write dest (Rc), - // e.g. for CMOVxx - if (_numSrcRegs > 0) { - printReg(ss, _srcRegIdx[0]); - } - - if (_numSrcRegs > 1) { - ss << ","; - printReg(ss, _srcRegIdx[1]); - } - - return ss.str(); - } - - std::string IntImmOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { - std::stringstream ss; - - ccprintf(ss, "%-10s ", mnemonic); - - if (_numDestRegs > 0) { - printReg(ss, _destRegIdx[0]); - } - - ss << ","; - - if (_numSrcRegs > 0) { - printReg(ss, _srcRegIdx[0]); - ss << ","; - } - - if( mnemonic == "lui") - ccprintf(ss, "%08p ", imm); - else - ss << (int) imm; - - return ss.str(); - } - -}}; - -//Used by decoder.isa -def format IntOp(code, *opt_flags) {{ - orig_code = code - cblk = CodeBlock(code) - - # Figure out if we are creating a IntImmOp or a IntOp - # by looking at the instruction name - iop = InstObjParams(name, Name, 'IntOp', cblk, opt_flags) - strlen = len(name) - if name[strlen-1] == 'i' or name[strlen-2:] == 'iu': - iop = InstObjParams(name, Name, 'IntImmOp', cblk, opt_flags) - - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = OperateNopCheckDecode.subst(iop) - exec_output = BasicExecute.subst(iop) -}}; - - - diff --git a/arch/mips/isa/formats/mem.isa b/arch/mips/isa/formats/mem.isa deleted file mode 100644 index 8a07e63d4..000000000 --- a/arch/mips/isa/formats/mem.isa +++ /dev/null @@ -1,469 +0,0 @@ -// -*- mode:c++ -*- - -// Copyright (c) 2003-2005 The Regents of The University of Michigan -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer; -// redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution; -// neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -output header {{ - /** - * Base class for general Mips memory-format instructions. - */ - class Memory : public MipsStaticInst - { - protected: - - /// Memory request flags. See mem_req_base.hh. - unsigned memAccessFlags; - /// Pointer to EAComp object. - const StaticInstPtr eaCompPtr; - /// Pointer to MemAcc object. - const StaticInstPtr memAccPtr; - - /// Displacement for EA calculation (signed). - int32_t disp; - - /// Constructor - Memory(const char *mnem, MachInst _machInst, OpClass __opClass, - StaticInstPtr _eaCompPtr = nullStaticInstPtr, - StaticInstPtr _memAccPtr = nullStaticInstPtr) - : MipsStaticInst(mnem, _machInst, __opClass), - memAccessFlags(0), eaCompPtr(_eaCompPtr), memAccPtr(_memAccPtr), - disp(OFFSET) - { - //If Bit 15 is 1 then Sign Extend - int32_t temp = disp & 0x00008000; - - if (temp > 0) { - disp |= 0xFFFF0000; - } - } - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - - public: - - const StaticInstPtr &eaCompInst() const { return eaCompPtr; } - const StaticInstPtr &memAccInst() const { return memAccPtr; } - }; - -}}; - - -output decoder {{ - std::string - Memory::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { - return csprintf("%-10s %c%d,%d(r%d)", mnemonic, - flags[IsFloating] ? 'f' : 'r', RT, disp, RS); - } - -}}; - -def format LoadAddress(code) {{ - iop = InstObjParams(name, Name, 'MemoryDisp32', CodeBlock(code)) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = BasicDecode.subst(iop) - exec_output = BasicExecute.subst(iop) -}}; - - -def template LoadStoreDeclare {{ - /** - * Static instruction class for "%(mnemonic)s". - */ - class %(class_name)s : public %(base_class)s - { - protected: - - /** - * "Fake" effective address computation class for "%(mnemonic)s". - */ - class EAComp : public %(base_class)s - { - public: - /// Constructor - EAComp(MachInst machInst); - - %(BasicExecDeclare)s - }; - - /** - * "Fake" memory access instruction class for "%(mnemonic)s". - */ - class MemAcc : public %(base_class)s - { - public: - /// Constructor - MemAcc(MachInst machInst); - - %(BasicExecDeclare)s - }; - - public: - - /// Constructor. - %(class_name)s(MachInst machInst); - - %(BasicExecDeclare)s - - %(InitiateAccDeclare)s - - %(CompleteAccDeclare)s - }; -}}; - - -def template InitiateAccDeclare {{ - Fault initiateAcc(%(CPU_exec_context)s *, Trace::InstRecord *) const; -}}; - - -def template CompleteAccDeclare {{ - Fault completeAcc(uint8_t *, %(CPU_exec_context)s *, Trace::InstRecord *) const; -}}; - - -def template LoadStoreConstructor {{ - /** TODO: change op_class to AddrGenOp or something (requires - * creating new member of OpClass enum in op_class.hh, updating - * config files, etc.). */ - inline %(class_name)s::EAComp::EAComp(MachInst machInst) - : %(base_class)s("%(mnemonic)s (EAComp)", machInst, IntAluOp) - { - %(ea_constructor)s; - } - - inline %(class_name)s::MemAcc::MemAcc(MachInst machInst) - : %(base_class)s("%(mnemonic)s (MemAcc)", machInst, %(op_class)s) - { - %(memacc_constructor)s; - } - - inline %(class_name)s::%(class_name)s(MachInst machInst) - : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, - new EAComp(machInst), new MemAcc(machInst)) - { - %(constructor)s; - } -}}; - - -def template EACompExecute {{ - Fault - %(class_name)s::EAComp::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Addr EA; - Fault fault = NoFault; - - %(fp_enable_check)s; - %(op_decl)s; - %(op_rd)s; - %(code)s; - - if (fault == NoFault) { - %(op_wb)s; - xc->setEA(EA); - } - - return fault; - } -}}; - -def template LoadMemAccExecute {{ - Fault - %(class_name)s::MemAcc::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Addr EA; - Fault fault = NoFault; - - %(fp_enable_check)s; - %(op_decl)s; - %(op_rd)s; - EA = xc->getEA(); - - if (fault == NoFault) { - fault = xc->read(EA, (uint%(mem_acc_size)d_t&)Mem, memAccessFlags); - %(code)s; - } - - if (fault == NoFault) { - %(op_wb)s; - } - - return fault; - } -}}; - - -def template LoadExecute {{ - Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Addr EA; - Fault fault = NoFault; - - %(fp_enable_check)s; - %(op_decl)s; - %(op_rd)s; - %(ea_code)s; - - if (fault == NoFault) { - fault = xc->read(EA, (uint%(mem_acc_size)d_t&)Mem, memAccessFlags); - %(memacc_code)s; - } - - if (fault == NoFault) { - %(op_wb)s; - } - - return fault; - } -}}; - - -def template LoadInitiateAcc {{ - Fault %(class_name)s::initiateAcc(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Addr EA; - Fault fault = NoFault; - - %(fp_enable_check)s; - %(op_src_decl)s; - %(op_rd)s; - %(ea_code)s; - - if (fault == NoFault) { - fault = xc->read(EA, (uint%(mem_acc_size)d_t &)Mem, memAccessFlags); - } - - return fault; - } -}}; - - -def template LoadCompleteAcc {{ - Fault %(class_name)s::completeAcc(uint8_t *data, - %(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Fault fault = NoFault; - - %(fp_enable_check)s; - %(op_src_decl)s; - %(op_dest_decl)s; - - memcpy(&Mem, data, sizeof(Mem)); - - if (fault == NoFault) { - %(memacc_code)s; - } - - if (fault == NoFault) { - %(op_wb)s; - } - - return fault; - } -}}; - - -def template StoreMemAccExecute {{ - Fault - %(class_name)s::MemAcc::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Addr EA; - Fault fault = NoFault; - uint64_t write_result = 0; - - %(fp_enable_check)s; - %(op_decl)s; - %(op_rd)s; - EA = xc->getEA(); - - if (fault == NoFault) { - %(code)s; - } - - if (fault == NoFault) { - fault = xc->write((uint%(mem_acc_size)d_t&)Mem, EA, - memAccessFlags, &write_result); - if (traceData) { traceData->setData(Mem); } - } - - if (fault == NoFault) { - %(postacc_code)s; - } - - if (fault == NoFault) { - %(op_wb)s; - } - - return fault; - } -}}; - - -def template StoreExecute {{ - Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Addr EA; - Fault fault = NoFault; - uint64_t write_result = 0; - - %(fp_enable_check)s; - %(op_decl)s; - %(op_rd)s; - %(ea_code)s; - - if (fault == NoFault) { - %(memacc_code)s; - } - - if (fault == NoFault) { - fault = xc->write((uint%(mem_acc_size)d_t&)Mem, EA, - memAccessFlags, &write_result); - if (traceData) { traceData->setData(Mem); } - } - - if (fault == NoFault) { - %(postacc_code)s; - } - - if (fault == NoFault) { - %(op_wb)s; - } - - return fault; - } -}}; - -def template StoreInitiateAcc {{ - Fault %(class_name)s::initiateAcc(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Addr EA; - Fault fault = NoFault; - uint64_t write_result = 0; - - %(fp_enable_check)s; - %(op_src_decl)s; - %(op_dest_decl)s; - %(op_rd)s; - %(ea_code)s; - - if (fault == NoFault) { - %(memacc_code)s; - } - - if (fault == NoFault) { - fault = xc->write((uint%(mem_acc_size)d_t&)Mem, EA, - memAccessFlags, &write_result); - if (traceData) { traceData->setData(Mem); } - } - - return fault; - } -}}; - - -def template StoreCompleteAcc {{ - Fault %(class_name)s::completeAcc(uint8_t *data, - %(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Fault fault = NoFault; - uint64_t write_result = 0; - - %(fp_enable_check)s; - %(op_dest_decl)s; - - memcpy(&write_result, data, sizeof(write_result)); - - if (fault == NoFault) { - %(postacc_code)s; - } - - if (fault == NoFault) { - %(op_wb)s; - } - - return fault; - } -}}; - -// load instructions use Rt as dest, so check for -// Rt == 31 to detect nops -def template LoadNopCheckDecode {{ - { - MipsStaticInst *i = new %(class_name)s(machInst); - if (RT == 0) { - i = makeNop(i); - } - return i; - } -}}; - -def format LoadMemory(memacc_code, ea_code = {{ EA = Rs + disp; }}, - mem_flags = [], inst_flags = []) {{ - (header_output, decoder_output, decode_block, exec_output) = \ - LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, - decode_template = LoadNopCheckDecode, - exec_template_base = 'Load') -}}; - - -def format StoreMemory(memacc_code, ea_code = {{ EA = Rs + disp; }}, - mem_flags = [], inst_flags = []) {{ - (header_output, decoder_output, decode_block, exec_output) = \ - LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, - exec_template_base = 'Store') -}}; - -//FP loads are offloaded to these formats for now ... -def format LoadMemory2(ea_code = {{ EA = Rs + disp; }}, memacc_code = {{ }}, - mem_flags = [], inst_flags = []) {{ - (header_output, decoder_output, decode_block, exec_output) = \ - LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, - decode_template = LoadNopCheckDecode, - exec_template_base = 'Load') -}}; - - -//FP stores are offloaded to these formats for now ... -def format StoreMemory2(ea_code = {{ EA = Rs + disp; }},memacc_code = {{ }}, - mem_flags = [], inst_flags = []) {{ - (header_output, decoder_output, decode_block, exec_output) = \ - LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, - decode_template = LoadNopCheckDecode, - exec_template_base = 'Store') -}}; - diff --git a/arch/mips/isa/formats/noop.isa b/arch/mips/isa/formats/noop.isa deleted file mode 100644 index d35179005..000000000 --- a/arch/mips/isa/formats/noop.isa +++ /dev/null @@ -1,90 +0,0 @@ -// -*- mode:c++ -*- - -//////////////////////////////////////////////////////////////////// -// -// Nop -// - -output header {{ - /** - * Static instruction class for no-ops. This is a leaf class. - */ - class Nop : public MipsStaticInst - { - /// Disassembly of original instruction. - const std::string originalDisassembly; - - public: - /// Constructor - Nop(const std::string _originalDisassembly, MachInst _machInst) - : MipsStaticInst("nop", _machInst, No_OpClass), - originalDisassembly(_originalDisassembly) - { - flags[IsNop] = true; - } - - ~Nop() { } - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - - %(BasicExecDeclare)s - }; -}}; - -output decoder {{ - std::string Nop::generateDisassembly(Addr pc, - const SymbolTable *symtab) const - { -#ifdef SS_COMPATIBLE_DISASSEMBLY - return originalDisassembly; -#else - return csprintf("%-10s (%s)", "nop", originalDisassembly); -#endif - } - - /// Helper function for decoding nops. Substitute Nop object - /// for original inst passed in as arg (and delete latter). - inline - MipsStaticInst * - makeNop(MipsStaticInst *inst) - { - MipsStaticInst *nop = new Nop(inst->disassemble(0), inst->machInst); - delete inst; - return nop; - } -}}; - -output exec {{ - Fault - Nop::execute(%(CPU_exec_context)s *, Trace::InstRecord *) const - { - return NoFault; - } -}}; - -// integer & FP operate instructions use RT as dest, so check for -// RT == 0 to detect nops -def template OperateNopCheckDecode {{ - { - MipsStaticInst *i = new %(class_name)s(machInst); - - //if (RD == 0) { - // i = makeNop(i); - //} - - return i; - } -}}; - - -// Like BasicOperate format, but generates NOP if RC/FC == 31 -def format BasicOperateWithNopCheck(code, *opt_args) {{ - iop = InstObjParams(name, Name, 'MipsStaticInst', CodeBlock(code), - opt_args) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = OperateNopCheckDecode.subst(iop) - exec_output = BasicExecute.subst(iop) -}}; - diff --git a/arch/mips/isa/formats/unimp.isa b/arch/mips/isa/formats/unimp.isa deleted file mode 100644 index adbd5b5b1..000000000 --- a/arch/mips/isa/formats/unimp.isa +++ /dev/null @@ -1,165 +0,0 @@ -// -*- mode:c++ -*- - -// Copyright (c) 2003-2005 The Regents of The University of Michigan -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer; -// redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution; -// neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -output header {{ - /** - * Static instruction class for unimplemented instructions that - * cause simulator termination. Note that these are recognized - * (legal) instructions that the simulator does not support; the - * 'Unknown' class is used for unrecognized/illegal instructions. - * This is a leaf class. - */ - class FailUnimplemented : public MipsStaticInst - { - public: - /// Constructor - FailUnimplemented(const char *_mnemonic, MachInst _machInst) - : MipsStaticInst(_mnemonic, _machInst, No_OpClass) - { - // don't call execute() (which panics) if we're on a - // speculative path - flags[IsNonSpeculative] = true; - } - - %(BasicExecDeclare)s - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; - - /** - * Base class for unimplemented instructions that cause a warning - * to be printed (but do not terminate simulation). This - * implementation is a little screwy in that it will print a - * warning for each instance of a particular unimplemented machine - * instruction, not just for each unimplemented opcode. Should - * probably make the 'warned' flag a static member of the derived - * class. - */ - class WarnUnimplemented : public MipsStaticInst - { - private: - /// Have we warned on this instruction yet? - mutable bool warned; - - public: - /// Constructor - WarnUnimplemented(const char *_mnemonic, MachInst _machInst) - : MipsStaticInst(_mnemonic, _machInst, No_OpClass), warned(false) - { - // don't call execute() (which panics) if we're on a - // speculative path - flags[IsNonSpeculative] = true; - } - - %(BasicExecDeclare)s - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; -}}; - -output decoder {{ - std::string - FailUnimplemented::generateDisassembly(Addr pc, - const SymbolTable *symtab) const - { - return csprintf("%-10s (unimplemented)", mnemonic); - } - - std::string - WarnUnimplemented::generateDisassembly(Addr pc, - const SymbolTable *symtab) const - { -#ifdef SS_COMPATIBLE_DISASSEMBLY - return csprintf("%-10s", mnemonic); -#else - return csprintf("%-10s (unimplemented)", mnemonic); -#endif - } -}}; - -output exec {{ - Fault - FailUnimplemented::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - panic("attempt to execute unimplemented instruction '%s' " - "(inst 0x%08x, opcode 0x%x)", mnemonic, machInst, OPCODE); - return UnimplementedOpcodeFault; - } - - Fault - WarnUnimplemented::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - if (!warned) { - warn("instruction '%s' unimplemented\n", mnemonic); - warned = true; - } - - return NoFault; - } -}}; - - -def format FailUnimpl() {{ - iop = InstObjParams(name, 'FailUnimplemented') - decode_block = BasicDecodeWithMnemonic.subst(iop) -}}; - -def format WarnUnimpl() {{ - iop = InstObjParams(name, 'WarnUnimplemented') - decode_block = BasicDecodeWithMnemonic.subst(iop) -}}; - -output header {{ - /** - * Static instruction class for unknown (illegal) instructions. - * These cause simulator termination if they are executed in a - * non-speculative mode. This is a leaf class. - */ - class Unknown : public MipsStaticInst - { - public: - /// Constructor - Unknown(MachInst _machInst) - : MipsStaticInst("unknown", _machInst, No_OpClass) - { - // don't call execute() (which panics) if we're on a - // speculative path - flags[IsNonSpeculative] = true; - } - - %(BasicExecDeclare)s - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; -}}; - diff --git a/arch/mips/isa/formats/unknown.isa b/arch/mips/isa/formats/unknown.isa deleted file mode 100644 index 4601b3684..000000000 --- a/arch/mips/isa/formats/unknown.isa +++ /dev/null @@ -1,52 +0,0 @@ -// -*- mode:c++ -*- - -// Copyright (c) 2003-2005 The Regents of The University of Michigan -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer; -// redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution; -// neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -output decoder {{ - std::string - Unknown::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { - return csprintf("%-10s (inst 0x%x, opcode 0x%x)", - "unknown", machInst, OPCODE); - } -}}; - -output exec {{ - Fault - Unknown::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - panic("attempt to execute unknown instruction " - "(inst 0x%08x, opcode 0x%x)", machInst, OPCODE); - return UnimplementedOpcodeFault; - } -}}; - -def format Unknown() {{ - decode_block = 'return new Unknown(machInst);\n' -}}; - diff --git a/arch/mips/isa/formats/util.isa b/arch/mips/isa/formats/util.isa deleted file mode 100644 index db4bf204a..000000000 --- a/arch/mips/isa/formats/util.isa +++ /dev/null @@ -1,148 +0,0 @@ -// -*- mode:c++ -*- - -let {{ -def LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, - postacc_code = '', base_class = 'Memory', - decode_template = BasicDecode, exec_template_base = ''): - # Make sure flags are in lists (convert to lists if not). - mem_flags = makeList(mem_flags) - inst_flags = makeList(inst_flags) - - # add hook to get effective addresses into execution trace output. - ea_code += '\nif (traceData) { traceData->setAddr(EA); }\n' - - # generate code block objects - ea_cblk = CodeBlock(ea_code) - memacc_cblk = CodeBlock(memacc_code) - postacc_cblk = CodeBlock(postacc_code) - - # Some CPU models execute the memory operation as an atomic unit, - # while others want to separate them into an effective address - # computation and a memory access operation. As a result, we need - # to generate three StaticInst objects. Note that the latter two - # are nested inside the larger "atomic" one. - - # generate InstObjParams for EAComp object - ea_iop = InstObjParams(name, Name, base_class, ea_cblk, inst_flags) - - # generate InstObjParams for MemAcc object - memacc_iop = InstObjParams(name, Name, base_class, memacc_cblk, inst_flags) - # in the split execution model, the MemAcc portion is responsible - # for the post-access code. - memacc_iop.postacc_code = postacc_cblk.code - - # generate InstObjParams for InitiateAcc, CompleteAcc object - # The code used depends on the template being used - if (exec_template_base == 'Load'): - initiateacc_cblk = CodeBlock(ea_code + memacc_code) - completeacc_cblk = CodeBlock(memacc_code + postacc_code) - elif (exec_template_base == 'Store'): - initiateacc_cblk = CodeBlock(ea_code + memacc_code) - completeacc_cblk = CodeBlock(postacc_code) - else: - initiateacc_cblk = '' - completeacc_cblk = '' - - initiateacc_iop = InstObjParams(name, Name, base_class, initiateacc_cblk, - inst_flags) - - completeacc_iop = InstObjParams(name, Name, base_class, completeacc_cblk, - inst_flags) - - if (exec_template_base == 'Load'): - initiateacc_iop.ea_code = ea_cblk.code - initiateacc_iop.memacc_code = memacc_cblk.code - completeacc_iop.memacc_code = memacc_cblk.code - completeacc_iop.postacc_code = postacc_cblk.code - elif (exec_template_base == 'Store'): - initiateacc_iop.ea_code = ea_cblk.code - initiateacc_iop.memacc_code = memacc_cblk.code - completeacc_iop.postacc_code = postacc_cblk.code - - # generate InstObjParams for unified execution - cblk = CodeBlock(ea_code + memacc_code + postacc_code) - iop = InstObjParams(name, Name, base_class, cblk, inst_flags) - - iop.ea_constructor = ea_cblk.constructor - iop.ea_code = ea_cblk.code - iop.memacc_constructor = memacc_cblk.constructor - iop.memacc_code = memacc_cblk.code - iop.postacc_code = postacc_cblk.code - - if mem_flags: - s = '\n\tmemAccessFlags = ' + string.join(mem_flags, '|') + ';' - iop.constructor += s - memacc_iop.constructor += s - - # select templates - memAccExecTemplate = eval(exec_template_base + 'MemAccExecute') - fullExecTemplate = eval(exec_template_base + 'Execute') - initiateAccTemplate = eval(exec_template_base + 'InitiateAcc') - completeAccTemplate = eval(exec_template_base + 'CompleteAcc') - - # (header_output, decoder_output, decode_block, exec_output) - return (LoadStoreDeclare.subst(iop), LoadStoreConstructor.subst(iop), - decode_template.subst(iop), - EACompExecute.subst(ea_iop) - + memAccExecTemplate.subst(memacc_iop) - + fullExecTemplate.subst(iop) - + initiateAccTemplate.subst(initiateacc_iop) - + completeAccTemplate.subst(completeacc_iop)) -}}; - - -output exec {{ - -using namespace MipsISA; - - - /// CLEAR ALL CPU INST/EXE HAZARDS - inline void - clear_exe_inst_hazards() - { - //CODE HERE - } - - - /// Check "FP enabled" machine status bit. Called when executing any FP - /// instruction in full-system mode. - /// @retval Full-system mode: NoFault if FP is enabled, FenFault - /// if not. Non-full-system mode: always returns NoFault. -#if FULL_SYSTEM - inline Fault checkFpEnableFault(%(CPU_exec_context)s *xc) - { - Fault fault = NoFault; // dummy... this ipr access should not fault - if (!Mips34k::ICSR_FPE(xc->readIpr(MipsISA::IPR_ICSR, fault))) { - fault = FloatEnableFault; - } - return fault; - } -#else - inline Fault checkFpEnableFault(%(CPU_exec_context)s *xc) - { - return NoFault; - } -#endif - - double convert_and_round(float w, int x, int y, int z) - { - double temp = .34000; - - return temp; - } - - enum FPTypes{ - FP_SINGLE, - FP_DOUBLE, - FP_LONG, - FP_PS_LO, - FP_PS_HI, - FP_WORD, - RND_NEAREST, - RND_ZERO, - RND_UP, - RND_DOWN - }; -}}; - - diff --git a/arch/mips/isa/includes.isa b/arch/mips/isa/includes.isa deleted file mode 100644 index da919be00..000000000 --- a/arch/mips/isa/includes.isa +++ /dev/null @@ -1,39 +0,0 @@ -//////////////////////////////////////////////////////////////////// -// -// Output include file directives. -// - -output header {{ -#include <sstream> -#include <iostream> -#include <iomanip> - -#include "cpu/static_inst.hh" -#include "mem/mem_req.hh" // some constructors use MemReq flags -}}; - -output decoder {{ -#include "base/cprintf.hh" -#include "base/loader/symtab.hh" -#include "cpu/exec_context.hh" // for Jump::branchTarget() - -#include <math.h> -#if defined(linux) -#include <fenv.h> -#endif -}}; - -output exec {{ -#include <math.h> -#if defined(linux) -#include <fenv.h> -#endif - -#ifdef FULL_SYSTEM -//#include "arch/alpha/pseudo_inst.hh" -#endif -#include "cpu/base.hh" -#include "cpu/exetrace.hh" -#include "sim/sim_exit.hh" -}}; - diff --git a/arch/mips/isa/main.isa b/arch/mips/isa/main.isa deleted file mode 100644 index 411e398b4..000000000 --- a/arch/mips/isa/main.isa +++ /dev/null @@ -1,52 +0,0 @@ -// -*- mode:c++ -*- - -// Copyright (c) 2003-2005 The Regents of The University of Michigan -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer; -// redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution; -// neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -##include "m5/arch/mips/isa/includes.isa" - -//////////////////////////////////////////////////////////////////// -// -// Namespace statement. Everything below this line will be in the -// MipsISAInst namespace. -// - -namespace MipsISA; - -//Include the bitfield definitions -##include "m5/arch/mips/isa/bitfields.isa" - -//Include the operand_types and operand definitions -##include "m5/arch/mips/isa/operands.isa" - -//Include the base class for mips instructions, and some support code -##include "m5/arch/mips/isa/base.isa" - -//Include the definitions for the instruction formats -##include "m5/arch/mips/isa/formats.isa" - -//Include the decoder definition -##include "m5/arch/mips/isa/decoder.isa" diff --git a/arch/mips/isa/operands.isa b/arch/mips/isa/operands.isa deleted file mode 100644 index 13870337b..000000000 --- a/arch/mips/isa/operands.isa +++ /dev/null @@ -1,33 +0,0 @@ -def operand_types {{ - 'sb' : ('signed int', 8), - 'ub' : ('unsigned int', 8), - 'sh' : ('signed int', 16), - 'uh' : ('unsigned int', 16), - 'sw' : ('signed int', 32), - 'uw' : ('unsigned int', 32), - 'sd' : ('signed int', 64), - 'ud' : ('unsigned int', 64), - 'sf' : ('float', 32), - 'df' : ('float', 64), - 'qf' : ('float', 128) -}}; - -def operands {{ - 'Rd': ('IntReg', 'uw', 'RD', 'IsInteger', 1), - 'Rs': ('IntReg', 'uw', 'RS', 'IsInteger', 2), - 'Rt': ('IntReg', 'uw', 'RT', 'IsInteger', 3), - 'r31': ('IntReg', 'uw','R31','IsInteger', 4), - 'R0': ('IntReg', 'uw','R0', 'IsInteger', 5), - - 'IntImm': ('IntReg', 'uw', 'INTIMM', 'IsInteger', 3), - - 'Fd': ('FloatReg', 'sf', 'FD', 'IsFloating', 1), - 'Fs': ('FloatReg', 'sf', 'FS', 'IsFloating', 2), - 'Ft': ('FloatReg', 'sf', 'FT', 'IsFloating', 3), - 'Fr': ('FloatReg', 'sf', 'FR', 'IsFloating', 3), - - 'Mem': ('Mem', 'ud', None, ('IsMemRef', 'IsLoad', 'IsStore'), 4), - - 'NPC': ('NPC', 'uw', None, ( None, None, 'IsControl' ), 4), - 'NNPC':('NNPC', 'uw', None, ( None, None, 'IsControl' ), 4) -}}; diff --git a/arch/mips/isa_traits.cc b/arch/mips/isa_traits.cc deleted file mode 100644 index d01fa6bd4..000000000 --- a/arch/mips/isa_traits.cc +++ /dev/null @@ -1,403 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "arch/mips/isa_traits.hh" -#include "config/full_system.hh" -#include "cpu/static_inst.hh" -#include "sim/serialize.hh" - -using namespace MipsISA; - - -//Function now Obsolete in current state. -//If anyting this should return the correct miscreg index -//but that is handled implicitly with enums anyway -void -MipsISA::getMiscRegIdx(int reg_name,int &idx, int &sel) -{ - switch(reg_name) - { - case Index: idx = 0; sel = 0; break; //0-0 Index into the TLB array - case MVPControl: idx = 0; sel = 1; break; //0-1 Per-processor register containing global - case MVPConf0: idx = 0; sel = 2; break; //0-2 Per-processor register containing global - case MVPConf1: idx = 0; sel = 3; break; //0-3 Per-processor register containing global - case Random: idx = 1; sel = 3; break; //1-0 Randomly generated index into the TLB array - case VPEControl: idx = 1; sel = 1; break; //1-1 Per-VPE register containing relatively volatile - //thread configuration data - case VPEConf0: idx = 1; sel = 2; break; //1-2 Per-VPE multi-thread configuration - //information - case VPEConf1: idx = 1; sel = 3; break; //1-3 Per-VPE multi-thread configuration - //information - case YQMask: idx = 1; sel = 4; break; //Per-VPE register defining which YIELD - //qualifier bits may be used without generating - //an exception - case VPESchedule: idx = 1; sel = 5; break; - case VPEScheFBack: idx = 1; sel = 6; break; - case VPEOpt: idx = 1; sel = 7; break; - case EntryLo0: idx = 1; sel = 5; break; - case TCStatus: idx = 1; sel = 5; break; - case TCBind: idx = 1; sel = 5; break; - case TCRestart: idx = 1; sel = 5; break; - case TCHalt: idx = 1; sel = 5; break; - case TCContext: idx = 1; sel = 5; break; - case TCSchedule: idx = 1; sel = 5; break; - case TCScheFBack: panic("Accessing Unimplemented CP0 Register"); break; - case EntryLo1: panic("Accessing Unimplemented CP0 Register"); break; - case Context: panic("Accessing Unimplemented CP0 Register"); break; - case ContextConfig: panic("Accessing Unimplemented CP0 Register"); break; - //case PageMask: panic("Accessing Unimplemented CP0 Register"); break; - case PageGrain: panic("Accessing Unimplemented CP0 Register"); break; - case Wired: panic("Accessing Unimplemented CP0 Register"); break; - case SRSConf0: panic("Accessing Unimplemented CP0 Register"); break; - case SRSConf1: panic("Accessing Unimplemented CP0 Register"); break; - case SRSConf2: panic("Accessing Unimplemented CP0 Register"); break; - case SRSConf3: panic("Accessing Unimplemented CP0 Register"); break; - case SRSConf4: panic("Accessing Unimplemented CP0 Register"); break; - case BadVAddr: panic("Accessing Unimplemented CP0 Register"); break; - case Count: panic("Accessing Unimplemented CP0 Register"); break; - case EntryHi: panic("Accessing Unimplemented CP0 Register"); break; - case Compare: panic("Accessing Unimplemented CP0 Register"); break; - case Status: idx = 12; sel = 0; break; //12-0 Processor status and control - case IntCtl: idx = 12; sel = 1; break; //12-1 Interrupt system status and control - case SRSCtl: idx = 12; sel = 2; break; //12-2 Shadow register set status and control - case SRSMap: idx = 12; sel = 3; break; //12-3 Shadow set IPL mapping - case Cause: idx = 13; sel = 0; break; //13-0 Cause of last general exception - case EPC: idx = 14; sel = 0; break; //14-0 Program counter at last exception - case PrId: idx = 15; sel = 0; break; //15-0 Processor identification and revision - case EBase: idx = 15; sel = 1; break; //15-1 Exception vector base register - case Config: panic("Accessing Unimplemented CP0 Register"); break; - case Config1: panic("Accessing Unimplemented CP0 Register"); break; - case Config2: panic("Accessing Unimplemented CP0 Register"); break; - case Config3: panic("Accessing Unimplemented CP0 Register"); break; - case LLAddr: panic("Accessing Unimplemented CP0 Register"); break; - case WatchLo: panic("Accessing Unimplemented CP0 Register"); break; - case WatchHi: panic("Accessing Unimplemented CP0 Register"); break; - case Debug: panic("Accessing Unimplemented CP0 Register"); break; - case TraceControl1: panic("Accessing Unimplemented CP0 Register"); break; - case TraceControl2: panic("Accessing Unimplemented CP0 Register"); break; - case UserTraceData: panic("Accessing Unimplemented CP0 Register"); break; - case TraceBPC: panic("Accessing Unimplemented CP0 Register"); break; - case DEPC: panic("Accessing Unimplemented CP0 Register"); break; - case PerfCnt: panic("Accessing Unimplemented CP0 Register"); break; - case ErrCtl: panic("Accessing Unimplemented CP0 Register"); break; - case CacheErr0: panic("Accessing Unimplemented CP0 Register"); break; - case CacheErr1: panic("Accessing Unimplemented CP0 Register"); break; - case CacheErr2: panic("Accessing Unimplemented CP0 Register"); break; - case CacheErr3: panic("Accessing Unimplemented CP0 Register"); break; - case TagLo: panic("Accessing Unimplemented CP0 Register"); break; - case DataLo: panic("Accessing Unimplemented CP0 Register"); break; - case TagHi: panic("Accessing Unimplemented CP0 Register"); break; - case DataHi: panic("Accessing Unimplemented CP0 Register"); break; - case ErrorEPC: panic("Accessing Unimplemented CP0 Register"); break; - - default: - panic("Accessing Unimplemented Misc. Register"); - } -} - -void RegFile::coldReset() -{ - //CP0 Random Reg: - //Randomly generated index into the TLB array - miscRegs[Random] = 0x0000003f; - - //CP0 Wired Reg. - miscRegs[Wired] = 0x0000000; - - //CP0 HWRENA - miscRegs[HWRena] = 0x0000000; - - //CP0 Status Reg. - miscRegs[Status] = 0x0400004; - - //CP0 INTCNTL - miscRegs[IntCtl] = 0xfc00000; - - //CP0 SRSCNTL - miscRegs[SRSCtl] = 0x0c00000; - - //CP0 SRSMAP - miscRegs[SRSMap] = 0x0000000; - - //CP0 Cause - miscRegs[Cause] = 0x0000000; - - //CP0 Processor ID - miscRegs[PrId] = 0x0019300; - - //CP0 EBASE - miscRegs[EBase] = 0x8000000; - - //CP0 Config Reg. - miscRegs[Config] = 0x80040482; - - //CP0 Config 1 Reg. - miscRegs[Config1] = 0xfee3719e; - - //CP0 Config 2 Reg. - miscRegs[Config2] = 0x8000000; - - //CP0 Config 3 Reg. - miscRegs[Config3] = 0x0000020; - - //CP0 Config 7 Reg. - miscRegs[Config7] = 0x0000000; - - //CP0 Debug - miscRegs[Debug] = 0x0201800; - - //CP0 PERFCNTL1 - miscRegs[PerfCnt0] = 0x0000000; - - //CP0 PERFCNTL2 - miscRegs[PerfCnt1] = 0x0000000; - -} - -void RegFile::createCP0Regs() -{ -//Resize Coprocessor Register Banks to -// the number specified in MIPS32K VOL.III -// Chapter 8 - /* - //Cop-0 Regs. Bank 0: Index, - miscRegs[0].resize(4); - - //Cop-0 Regs. Bank 1: - miscRegs[1].resize(8); - - //Cop-0 Regs. Bank 2: - miscRegs[2].resize(8); - - //Cop-0 Regs. Bank 3: - miscRegs[3].resize(1); - - //Cop-0 Regs. Bank 4: - miscRegs[4].resize(2); - - //Cop-0 Regs. Bank 5: - miscRegs[5].resize(2); - - //Cop-0 Regs. Bank 6: - miscRegs[6].resize(6); - - //Cop-0 Regs. Bank 7: - miscRegs[7].resize(1); - - //Cop-0 Regs. Bank 8: - miscRegs[8].resize(1); - - //Cop-0 Regs. Bank 9: - miscRegs[9].resize(1); - - //Cop-0 Regs. Bank 10: - miscRegs[10].resize(1); - - //Cop-0 Regs. Bank 11: - miscRegs[11].resize(1); - - //Cop-0 Regs. Bank 12: - miscRegs[12].resize(4); - - //Cop-0 Regs. Bank 13: - miscRegs[13].resize(1); - - //Cop-0 Regs. Bank 14: - miscRegs[14].resize(1); - - //Cop-0 Regs. Bank 15: - miscRegs[15].resize(2); - - //Cop-0 Regs. Bank 16: - miscRegs[16].resize(4); - - //Cop-0 Regs. Bank 17: - miscRegs[17].resize(1); - - //Cop-0 Regs. Bank 18: - miscRegs[18].resize(8); - - //Cop-0 Regs. Bank 19: - miscRegs[19].resize(8); - - //Cop-0 Regs. Bank 20: - miscRegs[20].resize(1); - - //Cop-0 Regs. Bank 21: - //miscRegs[21].resize(1); - //Reserved for future extensions - - //Cop-0 Regs. Bank 22: - //miscRegs[22].resize(4); - //Available for implementation dependent use - - //Cop-0 Regs. Bank 23: - miscRegs[23].resize(5); - - //Cop-0 Regs. Bank 24: - miscRegs[24].resize(1); - - //Cop-0 Regs. Bank 25: - miscRegs[25].resize(8); - - //Cop-0 Regs. Bank 26: - miscRegs[26].resize(1); - - //Cop-0 Regs. Bank 27: - miscRegs[27].resize(4); - - //Cop-0 Regs. Bank 28: - miscRegs[28].resize(8); - - //Cop-0 Regs. Bank 29: - miscRegs[29].resize(8); - - //Cop-0 Regs. Bank 30: - miscRegs[30].resize(1); - - //Cop-0 Regs. Bank 31: - miscRegs[31].resize(1);*/ - -} - - -const Addr MipsISA::PageShift = 13; -const Addr MipsISA::PageBytes = ULL(1) << PageShift; -const Addr MipsISA::PageMask = ~(PageBytes - 1); -const Addr MipsISA::PageOffset = PageBytes - 1; - -#if FULL_SYSTEM - -//////////////////////////////////////////////////////////////////////// -// -// Translation stuff -// - -const Addr MipsISA::PteShift = 3; -const Addr MipsISA::NPtePageShift = PageShift - PteShift; -const Addr MipsISA::NPtePage = ULL(1) << NPtePageShift; -const Addr MipsISA::PteMask = NPtePage - 1; - -// User Virtual -const Addr MipsISA::USegBase = ULL(0x0); -const Addr MipsISA::USegEnd = ULL(0x000003ffffffffff); - -// Kernel Direct Mapped -const Addr MipsISA::K0SegBase = ULL(0xfffffc0000000000); -const Addr MipsISA::K0SegEnd = ULL(0xfffffdffffffffff); - -// Kernel Virtual -const Addr MipsISA::K1SegBase = ULL(0xfffffe0000000000); -const Addr MipsISA::K1SegEnd = ULL(0xffffffffffffffff); - -#endif - -// Mips UNOP (sll r0,r0,r0) -const MachInst MipsISA::NoopMachInst = 0x00000000; - -static inline Addr -TruncPage(Addr addr) -{ return addr & ~(MipsISA::PageBytes - 1); } - -static inline Addr -RoundPage(Addr addr) -{ return (addr + MipsISA::PageBytes - 1) & ~(MipsISA::PageBytes - 1); } - -void -RegFile::serialize(std::ostream &os) -{ - SERIALIZE_ARRAY(intRegFile, NumIntRegs); - SERIALIZE_ARRAY(floatRegFile.q, NumFloatRegs); - //SERIALIZE_SCALAR(miscRegs.fpcr); - //SERIALIZE_SCALAR(miscRegs.uniq); - //SERIALIZE_SCALAR(miscRegs.lock_flag); - //SERIALIZE_SCALAR(miscRegs.lock_addr); - SERIALIZE_SCALAR(pc); - SERIALIZE_SCALAR(npc); - SERIALIZE_SCALAR(nnpc); -#if FULL_SYSTEM - SERIALIZE_ARRAY(palregs, NumIntRegs); - SERIALIZE_ARRAY(ipr, NumInternalProcRegs); - SERIALIZE_SCALAR(intrflag); - SERIALIZE_SCALAR(pal_shadow); -#endif -} - - -void -RegFile::unserialize(Checkpoint *cp, const std::string §ion) -{ - UNSERIALIZE_ARRAY(intRegFile, NumIntRegs); - UNSERIALIZE_ARRAY(floatRegFile.q, NumFloatRegs); - //UNSERIALIZE_SCALAR(miscRegs.fpcr); - //UNSERIALIZE_SCALAR(miscRegs.uniq); - //UNSERIALIZE_SCALAR(miscRegs.lock_flag); - //UNSERIALIZE_SCALAR(miscRegs.lock_addr); - UNSERIALIZE_SCALAR(pc); - UNSERIALIZE_SCALAR(npc); - UNSERIALIZE_SCALAR(nnpc); -#if FULL_SYSTEM - UNSERIALIZE_ARRAY(palregs, NumIntRegs); - UNSERIALIZE_ARRAY(ipr, NumInternalProcRegs); - UNSERIALIZE_SCALAR(intrflag); - UNSERIALIZE_SCALAR(pal_shadow); -#endif -} - - -#if FULL_SYSTEM -void -PTE::serialize(std::ostream &os) -{ - SERIALIZE_SCALAR(tag); - SERIALIZE_SCALAR(ppn); - SERIALIZE_SCALAR(xre); - SERIALIZE_SCALAR(xwe); - SERIALIZE_SCALAR(asn); - SERIALIZE_SCALAR(asma); - SERIALIZE_SCALAR(fonr); - SERIALIZE_SCALAR(fonw); - SERIALIZE_SCALAR(valid); -} - - -void -PTE::unserialize(Checkpoint *cp, const std::string §ion) -{ - UNSERIALIZE_SCALAR(tag); - UNSERIALIZE_SCALAR(ppn); - UNSERIALIZE_SCALAR(xre); - UNSERIALIZE_SCALAR(xwe); - UNSERIALIZE_SCALAR(asn); - UNSERIALIZE_SCALAR(asma); - UNSERIALIZE_SCALAR(fonr); - UNSERIALIZE_SCALAR(fonw); - UNSERIALIZE_SCALAR(valid); -} - -#endif //FULL_SYSTEM diff --git a/arch/mips/isa_traits.hh b/arch/mips/isa_traits.hh deleted file mode 100644 index 1dfa0dc7a..000000000 --- a/arch/mips/isa_traits.hh +++ /dev/null @@ -1,546 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __ARCH_MIPS_ISA_TRAITS_HH__ -#define __ARCH_MIPS_ISA_TRAITS_HH__ - -//#include "arch/mips/misc_regfile.hh" -#include "base/misc.hh" -#include "config/full_system.hh" -#include "sim/host.hh" -#include "sim/faults.hh" - -#include <vector> - -class FastCPU; -class FullCPU; -class Checkpoint; - -namespace LittleEndianGuest {}; -using namespace LittleEndianGuest; - -#define TARGET_MIPS - -class StaticInst; -class StaticInstPtr; - -namespace MIPS34K { -int DTB_ASN_ASN(uint64_t reg); -int ITB_ASN_ASN(uint64_t reg); -}; - -namespace MipsISA -{ - typedef uint32_t MachInst; -// typedef uint64_t Addr; - typedef uint8_t RegIndex; - - enum { - MemoryEnd = 0xffffffffffffffffULL, - - NumIntRegs = 32, - NumFloatRegs = 32, - NumMiscRegs = 258, //account for hi,lo regs - - MaxRegsOfAnyType = 32, - // Static instruction parameters - MaxInstSrcRegs = 3, - MaxInstDestRegs = 2, - - // semantically meaningful register indices - ZeroReg = 0, // architecturally meaningful - // the rest of these depend on the ABI - StackPointerReg = 30, - GlobalPointerReg = 29, - ProcedureValueReg = 27, - ReturnAddressReg = 26, - ReturnValueReg = 0, - FramePointerReg = 15, - ArgumentReg0 = 16, - ArgumentReg1 = 17, - ArgumentReg2 = 18, - ArgumentReg3 = 19, - ArgumentReg4 = 20, - ArgumentReg5 = 21, - - LogVMPageSize = 13, // 8K bytes - VMPageSize = (1 << LogVMPageSize), - - BranchPredAddrShiftAmt = 2, // instructions are 4-byte aligned - - WordBytes = 4, - HalfwordBytes = 2, - ByteBytes = 1, - DepNA = 0, - }; - - // These enumerate all the registers for dependence tracking. - enum DependenceTags { - // 0..31 are the integer regs 0..31 - // 32..63 are the FP regs 0..31, i.e. use (reg + FP_Base_DepTag) - FP_Base_DepTag = 32, - Ctrl_Base_DepTag = 64, - Fpcr_DepTag = 64, // floating point control register - Uniq_DepTag = 65, - IPR_Base_DepTag = 66, - MiscReg_DepTag = 67 - }; - - typedef uint64_t IntReg; - typedef IntReg IntRegFile[NumIntRegs]; - - // floating point register file entry type - typedef union { - uint64_t q; - double d; - } FloatReg; - - typedef union { - uint64_t q[NumFloatRegs]; // integer qword view - double d[NumFloatRegs]; // double-precision floating point view - } FloatRegFile; - - // cop-0/cop-1 system control register file - typedef uint64_t MiscReg; -//typedef MiscReg MiscRegFile[NumMiscRegs]; - class MiscRegFile { - public: - MiscReg - protected: - uint64_t fpcr; // floating point condition codes - uint64_t uniq; // process-unique register - bool lock_flag; // lock flag for LL/SC - Addr lock_addr; // lock address for LL/SC - - MiscReg miscRegFile[NumMiscRegs]; - - public: - //These functions should be removed once the simplescalar cpu model - //has been replaced. - int getInstAsid(); - int getDataAsid(); - - MiscReg readReg(int misc_reg) - { return miscRegFile[misc_reg]; } - - MiscReg readRegWithEffect(int misc_reg, Fault &fault, ExecContext *xc) - { return miscRegFile[misc_reg];} - - Fault setReg(int misc_reg, const MiscReg &val) - { miscRegFile[misc_reg] = val; return NoFault; } - - Fault setRegWithEffect(int misc_reg, const MiscReg &val, - ExecContext *xc) - { miscRegFile[misc_reg] = val; return NoFault; } - -#if FULL_SYSTEM - void clearIprs() { }; - - protected: - InternalProcReg ipr[NumInternalProcRegs]; // Internal processor regs - - private: - MiscReg readIpr(int idx, Fault &fault, ExecContext *xc) { } - - Fault setIpr(int idx, uint64_t val, ExecContext *xc) { } -#endif - friend class RegFile; - }; - - enum MiscRegTags { - //Coprocessor 0 Registers - //Reference MIPS32 Arch. for Programmers, Vol. III, Ch.8 - //(Register Number-Register Select) Summary of Register - //------------------------------------------------------ - Index = 0, //0-0 Index into the TLB array - - MVPControl = 1, //0-1 Per-processor register containing global - //MIPS® MT configuration data - - MVPConf0 = 2, //0-2 Per-processor register containing global - //MIPS® MT configuration data - - MVPConf1 = 3, //0-3 Per-processor register containing global - //MIPS® MT configuration data - - Random = 8, //1-0 Randomly generated index into the TLB array - - VPEControl = 9, //1-1 Per-VPE register containing relatively volatile - //thread configuration data - - VPEConf0 = 10, //1-2 Per-VPE multi-thread configuration - //information - - - VPEConf1 = 11, //1-2 Per-VPE multi-thread configuration - //information - - YQMask = 12, //Per-VPE register defining which YIELD - //qualifier bits may be used without generating - //an exception - - VPESchedule = 13, - VPEScheFBack = 14, - VPEOpt = 15, - EntryLo0 = 16, // Bank 3: 16 - 23 - TCStatus = 17, - TCBind = 18, - TCRestart = 19, - TCHalt = 20, - TCContext = 21, - TCSchedule = 22, - TCScheFBack = 23, - - EntryLo1 = 24,// Bank 4: 24 - 31 - - Context = 32, // Bank 5: 32 - 39 - ContextConfig = 33, - - //PageMask = 40, //Bank 6: 40 - 47 - PageGrain = 41, - - Wired = 48, //Bank 7:48 - 55 - SRSConf0 = 49, - SRSConf1 = 50, - SRSConf2 = 51, - SRSConf3 = 52, - SRSConf4 = 53, - BadVAddr = 54, - - HWRena = 56,//Bank 8:56 - 63 - - Count = 64, //Bank 9:64 - 71 - - EntryHi = 72,//Bank 10:72 - 79 - - Compare = 80,//Bank 11:80 - 87 - - Status = 88,//Bank 12:88 - 96 //12-0 Processor status and control - IntCtl = 89, //12-1 Interrupt system status and control - SRSCtl = 90, //12-2 Shadow register set status and control - SRSMap = 91, //12-3 Shadow set IPL mapping - - Cause = 97,//97-104 //13-0 Cause of last general exception - - EPC = 105,//105-112 //14-0 Program counter at last exception - - PRId = 113//113-120, //15-0 Processor identification and revision - EBase = 114, //15-1 Exception vector base register - - Config = 121,//Bank 16: 121-128 - Config1 = 122, - Config2 = 123, - Config3 = 124, - Config6 = 127, - Config7 = 128, - - - LLAddr = 129,//Bank 17: 129-136 - - WatchLo0 = 137,//Bank 18: 137-144 - WatchLo1 = 138, - WatchLo2 = 139, - WatchLo3 = 140, - WatchLo4 = 141, - WatchLo5 = 142, - WatchLo6 = 143, - WatchLo7 = 144, - - WatchHi0 = 145,//Bank 19: 145-152 - WatchHi1 = 146, - WatchHi2 = 147, - WatchHi3 = 148, - WatchHi4 = 149, - WatchHi5 = 150, - WatchHi6 = 151, - WatchHi7 = 152, - - XCContext64 = 153,//Bank 20: 153-160 - - //Bank 21: 161-168 - - //Bank 22: 169-176 - - Debug = 177, //Bank 23: 177-184 - TraceControl1 = 178, - TraceControl2 = 179, - UserTraceData = 180, - TraceBPC = 181, - - DEPC = 185,//Bank 24: 185-192 - - PerfCnt0 = 193,//Bank 25: 193 - 200 - PerfCnt1 = 194, - PerfCnt2 = 195, - PerfCnt3 = 196, - PerfCnt4 = 197, - PerfCnt5 = 198, - PerfCnt6 = 199, - PerfCnt7 = 200, - - ErrCtl = 201, //Bank 26: 201 - 208 - - CacheErr0 = 209, //Bank 27: 209 - 216 - CacheErr1 = 210, - CacheErr2 = 211, - CacheErr3 = 212, - - TagLo0 = 217,//Bank 28: 217 - 224 - DataLo1 = 218, - TagLo2 = 219, - DataLo3 = 220, - TagLo4 = 221, - DataLo5 = 222, - TagLo6 = 223, - DataLo7 = 234, - - TagHi0 = 233,//Bank 29: 233 - 240 - DataHi1 = 234, - TagHi2 = 235, - DataHi3 = 236, - TagHi4 = 237, - DataHi5 = 238, - TagHi6 = 239, - DataHi7 = 240, - - - ErrorEPC = 249,//Bank 30: 241 - 248 - - DESAVE = 257,//Bank 31: 249-256 - - //More Misc. Regs - Hi, - Lo, - FCSR, - FPCR, - - //Alpha Regs, but here now, for - //compiling sake - UNIQ, - LockAddr, - LockFlag - }; - -extern const Addr PageShift; -extern const Addr PageBytes; -extern const Addr PageMask; -extern const Addr PageOffset; - -#if FULL_SYSTEM - - typedef uint64_t InternalProcReg; - -#include "arch/mips/isa_fullsys_traits.hh" - -#else - enum { - NumInternalProcRegs = 0 - }; -#endif - - enum { - TotalNumRegs = - NumIntRegs + NumFloatRegs + NumMiscRegs + NumInternalProcRegs - }; - - enum { - TotalDataRegs = NumIntRegs + NumFloatRegs - }; - - typedef union { - IntReg intreg; - FloatReg fpreg; - MiscReg ctrlreg; - } AnyReg; - - struct RegFile { - IntRegFile intRegFile; // (signed) integer register file - FloatRegFile floatRegFile; // floating point register file - MiscRegFile miscRegs; // control register file - - - Addr pc; // program counter - Addr npc; // next-cycle program counter - Addr nnpc; // next-next-cycle program counter - // used to implement branch delay slot - // not real register - - MiscReg hi; // MIPS HI Register - MiscReg lo; // MIPS LO Register - - -#if FULL_SYSTEM - IntReg palregs[NumIntRegs]; // PAL shadow registers - InternalProcReg ipr[NumInternalProcRegs]; // internal processor regs - int intrflag; // interrupt flag - bool pal_shadow; // using pal_shadow registers - inline int instAsid() { return MIPS34K::ITB_ASN_ASN(ipr[IPR_ITB_ASN]); } - inline int dataAsid() { return MIPS34K::DTB_ASN_ASN(ipr[IPR_DTB_ASN]); } -#endif // FULL_SYSTEM - - //void initCP0Regs(); - void serialize(std::ostream &os); - void unserialize(Checkpoint *cp, const std::string §ion); - - void createCP0Regs(); - void coldReset(); - }; - - StaticInstPtr decodeInst(MachInst); - - // return a no-op instruction... used for instruction fetch faults - extern const MachInst NoopMachInst; - - enum annotes { - ANNOTE_NONE = 0, - // An impossible number for instruction annotations - ITOUCH_ANNOTE = 0xffffffff, - }; - - void getMiscRegIdx(int reg_name,int &idx, int &sel); - - - static inline bool isCallerSaveIntegerRegister(unsigned int reg) { - panic("register classification not implemented"); - return (reg >= 1 && reg <= 8 || reg >= 22 && reg <= 25 || reg == 27); - } - - static inline bool isCalleeSaveIntegerRegister(unsigned int reg) { - panic("register classification not implemented"); - return (reg >= 9 && reg <= 15); - } - - static inline bool isCallerSaveFloatRegister(unsigned int reg) { - panic("register classification not implemented"); - return false; - } - - static inline bool isCalleeSaveFloatRegister(unsigned int reg) { - panic("register classification not implemented"); - return false; - } - - static inline Addr alignAddress(const Addr &addr, - unsigned int nbytes) { - return (addr & ~(nbytes - 1)); - } - - // Instruction address compression hooks - static inline Addr realPCToFetchPC(const Addr &addr) { - return addr; - } - - static inline Addr fetchPCToRealPC(const Addr &addr) { - return addr; - } - - // the size of "fetched" instructions (not necessarily the size - // of real instructions for PISA) - static inline size_t fetchInstSize() { - return sizeof(MachInst); - } - - static inline MachInst makeRegisterCopy(int dest, int src) { - panic("makeRegisterCopy not implemented"); - return 0; - } - - // Machine operations - - void saveMachineReg(AnyReg &savereg, const RegFile ®_file, - int regnum); - - void restoreMachineReg(RegFile ®s, const AnyReg ®, - int regnum); - -#if 0 - static void serializeSpecialRegs(const Serializable::Proxy &proxy, - const RegFile ®s); - - static void unserializeSpecialRegs(const IniFile *db, - const std::string &category, - ConfigNode *node, - RegFile ®s); -#endif - - /** - * Function to insure ISA semantics about 0 registers. - * @param xc The execution context. - */ - template <class XC> - void zeroRegisters(XC *xc); - - const Addr MaxAddr = (Addr)-1; -}; - -#if !FULL_SYSTEM -class SyscallReturn { - public: - template <class T> - SyscallReturn(T v, bool s) - { - retval = (uint64_t)v; - success = s; - } - - template <class T> - SyscallReturn(T v) - { - success = (v >= 0); - retval = (uint64_t)v; - } - - ~SyscallReturn() {} - - SyscallReturn& operator=(const SyscallReturn& s) { - retval = s.retval; - success = s.success; - return *this; - } - - bool successful() { return success; } - uint64_t value() { return retval; } - - - private: - uint64_t retval; - bool success; -}; - -#endif - - -#if FULL_SYSTEM -//typedef TheISA::InternalProcReg InternalProcReg; -//const int NumInternalProcRegs = TheISA::NumInternalProcRegs; -//const int NumInterruptLevels = TheISA::NumInterruptLevels; - -#include "arch/mips/mips34k.hh" -#endif - -#endif // __ARCH_MIPS_ISA_TRAITS_HH__ diff --git a/arch/mips/linux_process.cc b/arch/mips/linux_process.cc deleted file mode 100644 index 1d4f62350..000000000 --- a/arch/mips/linux_process.cc +++ /dev/null @@ -1,588 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "arch/mips/common_syscall_emul.hh" -#include "arch/mips/linux_process.hh" -#include "arch/mips/isa_traits.hh" - -#include "base/trace.hh" -#include "cpu/exec_context.hh" -#include "kern/linux/linux.hh" -#include "mem/functional/functional.hh" - -#include "sim/process.hh" -#include "sim/syscall_emul.hh" - -using namespace std; -using namespace MipsISA; - -/// Target uname() handler. -static SyscallReturn -unameFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - TypedBufferArg<Linux::utsname> name(xc->getSyscallArg(0)); - - strcpy(name->sysname, "Linux"); - strcpy(name->nodename, "m5.eecs.umich.edu"); - strcpy(name->release, "2.4.20"); - strcpy(name->version, "#1 Mon Aug 18 11:32:15 EDT 2003"); - strcpy(name->machine, "mips"); - - name.copyOut(xc->mem); - return 0; -} - -/// Target osf_getsysyinfo() handler. Even though this call is -/// borrowed from Tru64, the subcases that get used appear to be -/// different in practice from those used by Tru64 processes. -static SyscallReturn -osf_getsysinfoFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - unsigned op = xc->getSyscallArg(0); - // unsigned nbytes = xc->getSyscallArg(2); - - switch (op) { - - case 45: { // GSI_IEEE_FP_CONTROL - TypedBufferArg<uint64_t> fpcr(xc->getSyscallArg(1)); - // I don't think this exactly matches the HW FPCR - *fpcr = 0; - fpcr.copyOut(xc->mem); - return 0; - } - - default: - cerr << "osf_getsysinfo: unknown op " << op << endl; - abort(); - break; - } - - return 1; -} - -/// Target osf_setsysinfo() handler. -static SyscallReturn -osf_setsysinfoFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - unsigned op = xc->getSyscallArg(0); - // unsigned nbytes = xc->getSyscallArg(2); - - switch (op) { - - case 14: { // SSI_IEEE_FP_CONTROL - TypedBufferArg<uint64_t> fpcr(xc->getSyscallArg(1)); - // I don't think this exactly matches the HW FPCR - fpcr.copyIn(xc->mem); - DPRINTFR(SyscallVerbose, "osf_setsysinfo(SSI_IEEE_FP_CONTROL): " - " setting FPCR to 0x%x\n", gtoh(*(uint64_t*)fpcr)); - return 0; - } - - default: - cerr << "osf_setsysinfo: unknown op " << op << endl; - abort(); - break; - } - - return 1; -} - - -SyscallDesc MipsLinuxProcess::syscallDescs[] = { - /* 0 */ SyscallDesc("osf_syscall", unimplementedFunc), - /* 1 */ SyscallDesc("exit", exitFunc), - /* 2 */ SyscallDesc("fork", unimplementedFunc), - /* 3 */ SyscallDesc("read", readFunc), - /* 4 */ SyscallDesc("write", writeFunc), - /* 5 */ SyscallDesc("osf_old_open", unimplementedFunc), - /* 6 */ SyscallDesc("close", closeFunc), - /* 7 */ SyscallDesc("osf_wait4", unimplementedFunc), - /* 8 */ SyscallDesc("osf_old_creat", unimplementedFunc), - /* 9 */ SyscallDesc("link", unimplementedFunc), - /* 10 */ SyscallDesc("unlink", unlinkFunc), - /* 11 */ SyscallDesc("osf_execve", unimplementedFunc), - /* 12 */ SyscallDesc("chdir", unimplementedFunc), - /* 13 */ SyscallDesc("fchdir", unimplementedFunc), - /* 14 */ SyscallDesc("mknod", unimplementedFunc), - /* 15 */ SyscallDesc("chmod", chmodFunc<Linux>), - /* 16 */ SyscallDesc("chown", chownFunc), - /* 17 */ SyscallDesc("brk", obreakFunc), - /* 18 */ SyscallDesc("osf_getfsstat", unimplementedFunc), - /* 19 */ SyscallDesc("lseek", lseekFunc), - /* 20 */ SyscallDesc("getxpid", getpidFunc), - /* 21 */ SyscallDesc("osf_mount", unimplementedFunc), - /* 22 */ SyscallDesc("umount", unimplementedFunc), - /* 23 */ SyscallDesc("setuid", setuidFunc), - /* 24 */ SyscallDesc("getxuid", getuidFunc), - /* 25 */ SyscallDesc("exec_with_loader", unimplementedFunc), - /* 26 */ SyscallDesc("osf_ptrace", unimplementedFunc), - /* 27 */ SyscallDesc("osf_nrecvmsg", unimplementedFunc), - /* 28 */ SyscallDesc("osf_nsendmsg", unimplementedFunc), - /* 29 */ SyscallDesc("osf_nrecvfrom", unimplementedFunc), - /* 30 */ SyscallDesc("osf_naccept", unimplementedFunc), - /* 31 */ SyscallDesc("osf_ngetpeername", unimplementedFunc), - /* 32 */ SyscallDesc("osf_ngetsockname", unimplementedFunc), - /* 33 */ SyscallDesc("access", unimplementedFunc), - /* 34 */ SyscallDesc("osf_chflags", unimplementedFunc), - /* 35 */ SyscallDesc("osf_fchflags", unimplementedFunc), - /* 36 */ SyscallDesc("sync", unimplementedFunc), - /* 37 */ SyscallDesc("kill", unimplementedFunc), - /* 38 */ SyscallDesc("osf_old_stat", unimplementedFunc), - /* 39 */ SyscallDesc("setpgid", unimplementedFunc), - /* 40 */ SyscallDesc("osf_old_lstat", unimplementedFunc), - /* 41 */ SyscallDesc("dup", unimplementedFunc), - /* 42 */ SyscallDesc("pipe", unimplementedFunc), - /* 43 */ SyscallDesc("osf_set_program_attributes", unimplementedFunc), - /* 44 */ SyscallDesc("osf_profil", unimplementedFunc), - /* 45 */ SyscallDesc("open", openFunc<Linux>), - /* 46 */ SyscallDesc("osf_old_sigaction", unimplementedFunc), - /* 47 */ SyscallDesc("getxgid", getgidFunc), - /* 48 */ SyscallDesc("osf_sigprocmask", ignoreFunc), - /* 49 */ SyscallDesc("osf_getlogin", unimplementedFunc), - /* 50 */ SyscallDesc("osf_setlogin", unimplementedFunc), - /* 51 */ SyscallDesc("acct", unimplementedFunc), - /* 52 */ SyscallDesc("sigpending", unimplementedFunc), - /* 53 */ SyscallDesc("osf_classcntl", unimplementedFunc), - /* 54 */ SyscallDesc("ioctl", ioctlFunc<Linux>), - /* 55 */ SyscallDesc("osf_reboot", unimplementedFunc), - /* 56 */ SyscallDesc("osf_revoke", unimplementedFunc), - /* 57 */ SyscallDesc("symlink", unimplementedFunc), - /* 58 */ SyscallDesc("readlink", unimplementedFunc), - /* 59 */ SyscallDesc("execve", unimplementedFunc), - /* 60 */ SyscallDesc("umask", unimplementedFunc), - /* 61 */ SyscallDesc("chroot", unimplementedFunc), - /* 62 */ SyscallDesc("osf_old_fstat", unimplementedFunc), - /* 63 */ SyscallDesc("getpgrp", unimplementedFunc), - /* 64 */ SyscallDesc("getpagesize", getpagesizeFunc), - /* 65 */ SyscallDesc("osf_mremap", unimplementedFunc), - /* 66 */ SyscallDesc("vfork", unimplementedFunc), - /* 67 */ SyscallDesc("stat", statFunc<Linux>), - /* 68 */ SyscallDesc("lstat", lstatFunc<Linux>), - /* 69 */ SyscallDesc("osf_sbrk", unimplementedFunc), - /* 70 */ SyscallDesc("osf_sstk", unimplementedFunc), - /* 71 */ SyscallDesc("mmap", mmapFunc<Linux>), - /* 72 */ SyscallDesc("osf_old_vadvise", unimplementedFunc), - /* 73 */ SyscallDesc("munmap", munmapFunc), - /* 74 */ SyscallDesc("mprotect", ignoreFunc), - /* 75 */ SyscallDesc("madvise", unimplementedFunc), - /* 76 */ SyscallDesc("vhangup", unimplementedFunc), - /* 77 */ SyscallDesc("osf_kmodcall", unimplementedFunc), - /* 78 */ SyscallDesc("osf_mincore", unimplementedFunc), - /* 79 */ SyscallDesc("getgroups", unimplementedFunc), - /* 80 */ SyscallDesc("setgroups", unimplementedFunc), - /* 81 */ SyscallDesc("osf_old_getpgrp", unimplementedFunc), - /* 82 */ SyscallDesc("setpgrp", unimplementedFunc), - /* 83 */ SyscallDesc("osf_setitimer", unimplementedFunc), - /* 84 */ SyscallDesc("osf_old_wait", unimplementedFunc), - /* 85 */ SyscallDesc("osf_table", unimplementedFunc), - /* 86 */ SyscallDesc("osf_getitimer", unimplementedFunc), - /* 87 */ SyscallDesc("gethostname", gethostnameFunc), - /* 88 */ SyscallDesc("sethostname", unimplementedFunc), - /* 89 */ SyscallDesc("getdtablesize", unimplementedFunc), - /* 90 */ SyscallDesc("dup2", unimplementedFunc), - /* 91 */ SyscallDesc("fstat", fstatFunc<Linux>), - /* 92 */ SyscallDesc("fcntl", fcntlFunc), - /* 93 */ SyscallDesc("osf_select", unimplementedFunc), - /* 94 */ SyscallDesc("poll", unimplementedFunc), - /* 95 */ SyscallDesc("fsync", unimplementedFunc), - /* 96 */ SyscallDesc("setpriority", unimplementedFunc), - /* 97 */ SyscallDesc("socket", unimplementedFunc), - /* 98 */ SyscallDesc("connect", unimplementedFunc), - /* 99 */ SyscallDesc("accept", unimplementedFunc), - /* 100 */ SyscallDesc("getpriority", unimplementedFunc), - /* 101 */ SyscallDesc("send", unimplementedFunc), - /* 102 */ SyscallDesc("recv", unimplementedFunc), - /* 103 */ SyscallDesc("sigreturn", unimplementedFunc), - /* 104 */ SyscallDesc("bind", unimplementedFunc), - /* 105 */ SyscallDesc("setsockopt", unimplementedFunc), - /* 106 */ SyscallDesc("listen", unimplementedFunc), - /* 107 */ SyscallDesc("osf_plock", unimplementedFunc), - /* 108 */ SyscallDesc("osf_old_sigvec", unimplementedFunc), - /* 109 */ SyscallDesc("osf_old_sigblock", unimplementedFunc), - /* 110 */ SyscallDesc("osf_old_sigsetmask", unimplementedFunc), - /* 111 */ SyscallDesc("sigsuspend", unimplementedFunc), - /* 112 */ SyscallDesc("osf_sigstack", ignoreFunc), - /* 113 */ SyscallDesc("recvmsg", unimplementedFunc), - /* 114 */ SyscallDesc("sendmsg", unimplementedFunc), - /* 115 */ SyscallDesc("osf_old_vtrace", unimplementedFunc), - /* 116 */ SyscallDesc("osf_gettimeofday", unimplementedFunc), - /* 117 */ SyscallDesc("osf_getrusage", unimplementedFunc), - /* 118 */ SyscallDesc("getsockopt", unimplementedFunc), - /* 119 */ SyscallDesc("numa_syscalls", unimplementedFunc), - /* 120 */ SyscallDesc("readv", unimplementedFunc), - /* 121 */ SyscallDesc("writev", writevFunc<Linux>), - /* 122 */ SyscallDesc("osf_settimeofday", unimplementedFunc), - /* 123 */ SyscallDesc("fchown", fchownFunc), - /* 124 */ SyscallDesc("fchmod", fchmodFunc<Linux>), - /* 125 */ SyscallDesc("recvfrom", unimplementedFunc), - /* 126 */ SyscallDesc("setreuid", unimplementedFunc), - /* 127 */ SyscallDesc("setregid", unimplementedFunc), - /* 128 */ SyscallDesc("rename", renameFunc), - /* 129 */ SyscallDesc("truncate", unimplementedFunc), - /* 130 */ SyscallDesc("ftruncate", unimplementedFunc), - /* 131 */ SyscallDesc("flock", unimplementedFunc), - /* 132 */ SyscallDesc("setgid", unimplementedFunc), - /* 133 */ SyscallDesc("sendto", unimplementedFunc), - /* 134 */ SyscallDesc("shutdown", unimplementedFunc), - /* 135 */ SyscallDesc("socketpair", unimplementedFunc), - /* 136 */ SyscallDesc("mkdir", unimplementedFunc), - /* 137 */ SyscallDesc("rmdir", unimplementedFunc), - /* 138 */ SyscallDesc("osf_utimes", unimplementedFunc), - /* 139 */ SyscallDesc("osf_old_sigreturn", unimplementedFunc), - /* 140 */ SyscallDesc("osf_adjtime", unimplementedFunc), - /* 141 */ SyscallDesc("getpeername", unimplementedFunc), - /* 142 */ SyscallDesc("osf_gethostid", unimplementedFunc), - /* 143 */ SyscallDesc("osf_sethostid", unimplementedFunc), - /* 144 */ SyscallDesc("getrlimit", getrlimitFunc<Linux>), - /* 145 */ SyscallDesc("setrlimit", ignoreFunc), - /* 146 */ SyscallDesc("osf_old_killpg", unimplementedFunc), - /* 147 */ SyscallDesc("setsid", unimplementedFunc), - /* 148 */ SyscallDesc("quotactl", unimplementedFunc), - /* 149 */ SyscallDesc("osf_oldquota", unimplementedFunc), - /* 150 */ SyscallDesc("getsockname", unimplementedFunc), - /* 151 */ SyscallDesc("osf_pread", unimplementedFunc), - /* 152 */ SyscallDesc("osf_pwrite", unimplementedFunc), - /* 153 */ SyscallDesc("osf_pid_block", unimplementedFunc), - /* 154 */ SyscallDesc("osf_pid_unblock", unimplementedFunc), - /* 155 */ SyscallDesc("osf_signal_urti", unimplementedFunc), - /* 156 */ SyscallDesc("sigaction", ignoreFunc), - /* 157 */ SyscallDesc("osf_sigwaitprim", unimplementedFunc), - /* 158 */ SyscallDesc("osf_nfssvc", unimplementedFunc), - /* 159 */ SyscallDesc("osf_getdirentries", unimplementedFunc), - /* 160 */ SyscallDesc("osf_statfs", unimplementedFunc), - /* 161 */ SyscallDesc("osf_fstatfs", unimplementedFunc), - /* 162 */ SyscallDesc("unknown #162", unimplementedFunc), - /* 163 */ SyscallDesc("osf_async_daemon", unimplementedFunc), - /* 164 */ SyscallDesc("osf_getfh", unimplementedFunc), - /* 165 */ SyscallDesc("osf_getdomainname", unimplementedFunc), - /* 166 */ SyscallDesc("setdomainname", unimplementedFunc), - /* 167 */ SyscallDesc("unknown #167", unimplementedFunc), - /* 168 */ SyscallDesc("unknown #168", unimplementedFunc), - /* 169 */ SyscallDesc("osf_exportfs", unimplementedFunc), - /* 170 */ SyscallDesc("unknown #170", unimplementedFunc), - /* 171 */ SyscallDesc("unknown #171", unimplementedFunc), - /* 172 */ SyscallDesc("unknown #172", unimplementedFunc), - /* 173 */ SyscallDesc("unknown #173", unimplementedFunc), - /* 174 */ SyscallDesc("unknown #174", unimplementedFunc), - /* 175 */ SyscallDesc("unknown #175", unimplementedFunc), - /* 176 */ SyscallDesc("unknown #176", unimplementedFunc), - /* 177 */ SyscallDesc("unknown #177", unimplementedFunc), - /* 178 */ SyscallDesc("unknown #178", unimplementedFunc), - /* 179 */ SyscallDesc("unknown #179", unimplementedFunc), - /* 180 */ SyscallDesc("unknown #180", unimplementedFunc), - /* 181 */ SyscallDesc("osf_alt_plock", unimplementedFunc), - /* 182 */ SyscallDesc("unknown #182", unimplementedFunc), - /* 183 */ SyscallDesc("unknown #183", unimplementedFunc), - /* 184 */ SyscallDesc("osf_getmnt", unimplementedFunc), - /* 185 */ SyscallDesc("unknown #185", unimplementedFunc), - /* 186 */ SyscallDesc("unknown #186", unimplementedFunc), - /* 187 */ SyscallDesc("osf_alt_sigpending", unimplementedFunc), - /* 188 */ SyscallDesc("osf_alt_setsid", unimplementedFunc), - /* 189 */ SyscallDesc("unknown #189", unimplementedFunc), - /* 190 */ SyscallDesc("unknown #190", unimplementedFunc), - /* 191 */ SyscallDesc("unknown #191", unimplementedFunc), - /* 192 */ SyscallDesc("unknown #192", unimplementedFunc), - /* 193 */ SyscallDesc("unknown #193", unimplementedFunc), - /* 194 */ SyscallDesc("unknown #194", unimplementedFunc), - /* 195 */ SyscallDesc("unknown #195", unimplementedFunc), - /* 196 */ SyscallDesc("unknown #196", unimplementedFunc), - /* 197 */ SyscallDesc("unknown #197", unimplementedFunc), - /* 198 */ SyscallDesc("unknown #198", unimplementedFunc), - /* 199 */ SyscallDesc("osf_swapon", unimplementedFunc), - /* 200 */ SyscallDesc("msgctl", unimplementedFunc), - /* 201 */ SyscallDesc("msgget", unimplementedFunc), - /* 202 */ SyscallDesc("msgrcv", unimplementedFunc), - /* 203 */ SyscallDesc("msgsnd", unimplementedFunc), - /* 204 */ SyscallDesc("semctl", unimplementedFunc), - /* 205 */ SyscallDesc("semget", unimplementedFunc), - /* 206 */ SyscallDesc("semop", unimplementedFunc), - /* 207 */ SyscallDesc("osf_utsname", unimplementedFunc), - /* 208 */ SyscallDesc("lchown", unimplementedFunc), - /* 209 */ SyscallDesc("osf_shmat", unimplementedFunc), - /* 210 */ SyscallDesc("shmctl", unimplementedFunc), - /* 211 */ SyscallDesc("shmdt", unimplementedFunc), - /* 212 */ SyscallDesc("shmget", unimplementedFunc), - /* 213 */ SyscallDesc("osf_mvalid", unimplementedFunc), - /* 214 */ SyscallDesc("osf_getaddressconf", unimplementedFunc), - /* 215 */ SyscallDesc("osf_msleep", unimplementedFunc), - /* 216 */ SyscallDesc("osf_mwakeup", unimplementedFunc), - /* 217 */ SyscallDesc("msync", unimplementedFunc), - /* 218 */ SyscallDesc("osf_signal", unimplementedFunc), - /* 219 */ SyscallDesc("osf_utc_gettime", unimplementedFunc), - /* 220 */ SyscallDesc("osf_utc_adjtime", unimplementedFunc), - /* 221 */ SyscallDesc("unknown #221", unimplementedFunc), - /* 222 */ SyscallDesc("osf_security", unimplementedFunc), - /* 223 */ SyscallDesc("osf_kloadcall", unimplementedFunc), - /* 224 */ SyscallDesc("unknown #224", unimplementedFunc), - /* 225 */ SyscallDesc("unknown #225", unimplementedFunc), - /* 226 */ SyscallDesc("unknown #226", unimplementedFunc), - /* 227 */ SyscallDesc("unknown #227", unimplementedFunc), - /* 228 */ SyscallDesc("unknown #228", unimplementedFunc), - /* 229 */ SyscallDesc("unknown #229", unimplementedFunc), - /* 230 */ SyscallDesc("unknown #230", unimplementedFunc), - /* 231 */ SyscallDesc("unknown #231", unimplementedFunc), - /* 232 */ SyscallDesc("unknown #232", unimplementedFunc), - /* 233 */ SyscallDesc("getpgid", unimplementedFunc), - /* 234 */ SyscallDesc("getsid", unimplementedFunc), - /* 235 */ SyscallDesc("sigaltstack", ignoreFunc), - /* 236 */ SyscallDesc("osf_waitid", unimplementedFunc), - /* 237 */ SyscallDesc("osf_priocntlset", unimplementedFunc), - /* 238 */ SyscallDesc("osf_sigsendset", unimplementedFunc), - /* 239 */ SyscallDesc("osf_set_speculative", unimplementedFunc), - /* 240 */ SyscallDesc("osf_msfs_syscall", unimplementedFunc), - /* 241 */ SyscallDesc("osf_sysinfo", unimplementedFunc), - /* 242 */ SyscallDesc("osf_uadmin", unimplementedFunc), - /* 243 */ SyscallDesc("osf_fuser", unimplementedFunc), - /* 244 */ SyscallDesc("osf_proplist_syscall", unimplementedFunc), - /* 245 */ SyscallDesc("osf_ntp_adjtime", unimplementedFunc), - /* 246 */ SyscallDesc("osf_ntp_gettime", unimplementedFunc), - /* 247 */ SyscallDesc("osf_pathconf", unimplementedFunc), - /* 248 */ SyscallDesc("osf_fpathconf", unimplementedFunc), - /* 249 */ SyscallDesc("unknown #249", unimplementedFunc), - /* 250 */ SyscallDesc("osf_uswitch", unimplementedFunc), - /* 251 */ SyscallDesc("osf_usleep_thread", unimplementedFunc), - /* 252 */ SyscallDesc("osf_audcntl", unimplementedFunc), - /* 253 */ SyscallDesc("osf_audgen", unimplementedFunc), - /* 254 */ SyscallDesc("sysfs", unimplementedFunc), - /* 255 */ SyscallDesc("osf_subsys_info", unimplementedFunc), - /* 256 */ SyscallDesc("osf_getsysinfo", osf_getsysinfoFunc), - /* 257 */ SyscallDesc("osf_setsysinfo", osf_setsysinfoFunc), - /* 258 */ SyscallDesc("osf_afs_syscall", unimplementedFunc), - /* 259 */ SyscallDesc("osf_swapctl", unimplementedFunc), - /* 260 */ SyscallDesc("osf_memcntl", unimplementedFunc), - /* 261 */ SyscallDesc("osf_fdatasync", unimplementedFunc), - /* 262 */ SyscallDesc("unknown #262", unimplementedFunc), - /* 263 */ SyscallDesc("unknown #263", unimplementedFunc), - /* 264 */ SyscallDesc("unknown #264", unimplementedFunc), - /* 265 */ SyscallDesc("unknown #265", unimplementedFunc), - /* 266 */ SyscallDesc("unknown #266", unimplementedFunc), - /* 267 */ SyscallDesc("unknown #267", unimplementedFunc), - /* 268 */ SyscallDesc("unknown #268", unimplementedFunc), - /* 269 */ SyscallDesc("unknown #269", unimplementedFunc), - /* 270 */ SyscallDesc("unknown #270", unimplementedFunc), - /* 271 */ SyscallDesc("unknown #271", unimplementedFunc), - /* 272 */ SyscallDesc("unknown #272", unimplementedFunc), - /* 273 */ SyscallDesc("unknown #273", unimplementedFunc), - /* 274 */ SyscallDesc("unknown #274", unimplementedFunc), - /* 275 */ SyscallDesc("unknown #275", unimplementedFunc), - /* 276 */ SyscallDesc("unknown #276", unimplementedFunc), - /* 277 */ SyscallDesc("unknown #277", unimplementedFunc), - /* 278 */ SyscallDesc("unknown #278", unimplementedFunc), - /* 279 */ SyscallDesc("unknown #279", unimplementedFunc), - /* 280 */ SyscallDesc("unknown #280", unimplementedFunc), - /* 281 */ SyscallDesc("unknown #281", unimplementedFunc), - /* 282 */ SyscallDesc("unknown #282", unimplementedFunc), - /* 283 */ SyscallDesc("unknown #283", unimplementedFunc), - /* 284 */ SyscallDesc("unknown #284", unimplementedFunc), - /* 285 */ SyscallDesc("unknown #285", unimplementedFunc), - /* 286 */ SyscallDesc("unknown #286", unimplementedFunc), - /* 287 */ SyscallDesc("unknown #287", unimplementedFunc), - /* 288 */ SyscallDesc("unknown #288", unimplementedFunc), - /* 289 */ SyscallDesc("unknown #289", unimplementedFunc), - /* 290 */ SyscallDesc("unknown #290", unimplementedFunc), - /* 291 */ SyscallDesc("unknown #291", unimplementedFunc), - /* 292 */ SyscallDesc("unknown #292", unimplementedFunc), - /* 293 */ SyscallDesc("unknown #293", unimplementedFunc), - /* 294 */ SyscallDesc("unknown #294", unimplementedFunc), - /* 295 */ SyscallDesc("unknown #295", unimplementedFunc), - /* 296 */ SyscallDesc("unknown #296", unimplementedFunc), - /* 297 */ SyscallDesc("unknown #297", unimplementedFunc), - /* 298 */ SyscallDesc("unknown #298", unimplementedFunc), - /* 299 */ SyscallDesc("unknown #299", unimplementedFunc), -/* - * Linux-specific system calls begin at 300 - */ - /* 300 */ SyscallDesc("bdflush", unimplementedFunc), - /* 301 */ SyscallDesc("sethae", unimplementedFunc), - /* 302 */ SyscallDesc("mount", unimplementedFunc), - /* 303 */ SyscallDesc("old_adjtimex", unimplementedFunc), - /* 304 */ SyscallDesc("swapoff", unimplementedFunc), - /* 305 */ SyscallDesc("getdents", unimplementedFunc), - /* 306 */ SyscallDesc("create_module", unimplementedFunc), - /* 307 */ SyscallDesc("init_module", unimplementedFunc), - /* 308 */ SyscallDesc("delete_module", unimplementedFunc), - /* 309 */ SyscallDesc("get_kernel_syms", unimplementedFunc), - /* 310 */ SyscallDesc("syslog", unimplementedFunc), - /* 311 */ SyscallDesc("reboot", unimplementedFunc), - /* 312 */ SyscallDesc("clone", unimplementedFunc), - /* 313 */ SyscallDesc("uselib", unimplementedFunc), - /* 314 */ SyscallDesc("mlock", unimplementedFunc), - /* 315 */ SyscallDesc("munlock", unimplementedFunc), - /* 316 */ SyscallDesc("mlockall", unimplementedFunc), - /* 317 */ SyscallDesc("munlockall", unimplementedFunc), - /* 318 */ SyscallDesc("sysinfo", unimplementedFunc), - /* 319 */ SyscallDesc("_sysctl", unimplementedFunc), - /* 320 */ SyscallDesc("was sys_idle", unimplementedFunc), - /* 321 */ SyscallDesc("oldumount", unimplementedFunc), - /* 322 */ SyscallDesc("swapon", unimplementedFunc), - /* 323 */ SyscallDesc("times", ignoreFunc), - /* 324 */ SyscallDesc("personality", unimplementedFunc), - /* 325 */ SyscallDesc("setfsuid", unimplementedFunc), - /* 326 */ SyscallDesc("setfsgid", unimplementedFunc), - /* 327 */ SyscallDesc("ustat", unimplementedFunc), - /* 328 */ SyscallDesc("statfs", unimplementedFunc), - /* 329 */ SyscallDesc("fstatfs", unimplementedFunc), - /* 330 */ SyscallDesc("sched_setparam", unimplementedFunc), - /* 331 */ SyscallDesc("sched_getparam", unimplementedFunc), - /* 332 */ SyscallDesc("sched_setscheduler", unimplementedFunc), - /* 333 */ SyscallDesc("sched_getscheduler", unimplementedFunc), - /* 334 */ SyscallDesc("sched_yield", unimplementedFunc), - /* 335 */ SyscallDesc("sched_get_priority_max", unimplementedFunc), - /* 336 */ SyscallDesc("sched_get_priority_min", unimplementedFunc), - /* 337 */ SyscallDesc("sched_rr_get_interval", unimplementedFunc), - /* 338 */ SyscallDesc("afs_syscall", unimplementedFunc), - /* 339 */ SyscallDesc("uname", unameFunc), - /* 340 */ SyscallDesc("nanosleep", unimplementedFunc), - /* 341 */ SyscallDesc("mremap", unimplementedFunc), - /* 342 */ SyscallDesc("nfsservctl", unimplementedFunc), - /* 343 */ SyscallDesc("setresuid", unimplementedFunc), - /* 344 */ SyscallDesc("getresuid", unimplementedFunc), - /* 345 */ SyscallDesc("pciconfig_read", unimplementedFunc), - /* 346 */ SyscallDesc("pciconfig_write", unimplementedFunc), - /* 347 */ SyscallDesc("query_module", unimplementedFunc), - /* 348 */ SyscallDesc("prctl", unimplementedFunc), - /* 349 */ SyscallDesc("pread", unimplementedFunc), - /* 350 */ SyscallDesc("pwrite", unimplementedFunc), - /* 351 */ SyscallDesc("rt_sigreturn", unimplementedFunc), - /* 352 */ SyscallDesc("rt_sigaction", ignoreFunc), - /* 353 */ SyscallDesc("rt_sigprocmask", unimplementedFunc), - /* 354 */ SyscallDesc("rt_sigpending", unimplementedFunc), - /* 355 */ SyscallDesc("rt_sigtimedwait", unimplementedFunc), - /* 356 */ SyscallDesc("rt_sigqueueinfo", unimplementedFunc), - /* 357 */ SyscallDesc("rt_sigsuspend", unimplementedFunc), - /* 358 */ SyscallDesc("select", unimplementedFunc), - /* 359 */ SyscallDesc("gettimeofday", gettimeofdayFunc<Linux>), - /* 360 */ SyscallDesc("settimeofday", unimplementedFunc), - /* 361 */ SyscallDesc("getitimer", unimplementedFunc), - /* 362 */ SyscallDesc("setitimer", unimplementedFunc), - /* 363 */ SyscallDesc("utimes", utimesFunc<Linux>), - /* 364 */ SyscallDesc("getrusage", getrusageFunc<Linux>), - /* 365 */ SyscallDesc("wait4", unimplementedFunc), - /* 366 */ SyscallDesc("adjtimex", unimplementedFunc), - /* 367 */ SyscallDesc("getcwd", unimplementedFunc), - /* 368 */ SyscallDesc("capget", unimplementedFunc), - /* 369 */ SyscallDesc("capset", unimplementedFunc), - /* 370 */ SyscallDesc("sendfile", unimplementedFunc), - /* 371 */ SyscallDesc("setresgid", unimplementedFunc), - /* 372 */ SyscallDesc("getresgid", unimplementedFunc), - /* 373 */ SyscallDesc("dipc", unimplementedFunc), - /* 374 */ SyscallDesc("pivot_root", unimplementedFunc), - /* 375 */ SyscallDesc("mincore", unimplementedFunc), - /* 376 */ SyscallDesc("pciconfig_iobase", unimplementedFunc), - /* 377 */ SyscallDesc("getdents64", unimplementedFunc), - /* 378 */ SyscallDesc("gettid", unimplementedFunc), - /* 379 */ SyscallDesc("readahead", unimplementedFunc), - /* 380 */ SyscallDesc("security", unimplementedFunc), - /* 381 */ SyscallDesc("tkill", unimplementedFunc), - /* 382 */ SyscallDesc("setxattr", unimplementedFunc), - /* 383 */ SyscallDesc("lsetxattr", unimplementedFunc), - /* 384 */ SyscallDesc("fsetxattr", unimplementedFunc), - /* 385 */ SyscallDesc("getxattr", unimplementedFunc), - /* 386 */ SyscallDesc("lgetxattr", unimplementedFunc), - /* 387 */ SyscallDesc("fgetxattr", unimplementedFunc), - /* 388 */ SyscallDesc("listxattr", unimplementedFunc), - /* 389 */ SyscallDesc("llistxattr", unimplementedFunc), - /* 390 */ SyscallDesc("flistxattr", unimplementedFunc), - /* 391 */ SyscallDesc("removexattr", unimplementedFunc), - /* 392 */ SyscallDesc("lremovexattr", unimplementedFunc), - /* 393 */ SyscallDesc("fremovexattr", unimplementedFunc), - /* 394 */ SyscallDesc("futex", unimplementedFunc), - /* 395 */ SyscallDesc("sched_setaffinity", unimplementedFunc), - /* 396 */ SyscallDesc("sched_getaffinity", unimplementedFunc), - /* 397 */ SyscallDesc("tuxcall", unimplementedFunc), - /* 398 */ SyscallDesc("io_setup", unimplementedFunc), - /* 399 */ SyscallDesc("io_destroy", unimplementedFunc), - /* 400 */ SyscallDesc("io_getevents", unimplementedFunc), - /* 401 */ SyscallDesc("io_submit", unimplementedFunc), - /* 402 */ SyscallDesc("io_cancel", unimplementedFunc), - /* 403 */ SyscallDesc("unknown #403", unimplementedFunc), - /* 404 */ SyscallDesc("unknown #404", unimplementedFunc), - /* 405 */ SyscallDesc("exit_group", exitFunc), // exit all threads... - /* 406 */ SyscallDesc("lookup_dcookie", unimplementedFunc), - /* 407 */ SyscallDesc("sys_epoll_create", unimplementedFunc), - /* 408 */ SyscallDesc("sys_epoll_ctl", unimplementedFunc), - /* 409 */ SyscallDesc("sys_epoll_wait", unimplementedFunc), - /* 410 */ SyscallDesc("remap_file_pages", unimplementedFunc), - /* 411 */ SyscallDesc("set_tid_address", unimplementedFunc), - /* 412 */ SyscallDesc("restart_syscall", unimplementedFunc), - /* 413 */ SyscallDesc("fadvise64", unimplementedFunc), - /* 414 */ SyscallDesc("timer_create", unimplementedFunc), - /* 415 */ SyscallDesc("timer_settime", unimplementedFunc), - /* 416 */ SyscallDesc("timer_gettime", unimplementedFunc), - /* 417 */ SyscallDesc("timer_getoverrun", unimplementedFunc), - /* 418 */ SyscallDesc("timer_delete", unimplementedFunc), - /* 419 */ SyscallDesc("clock_settime", unimplementedFunc), - /* 420 */ SyscallDesc("clock_gettime", unimplementedFunc), - /* 421 */ SyscallDesc("clock_getres", unimplementedFunc), - /* 422 */ SyscallDesc("clock_nanosleep", unimplementedFunc), - /* 423 */ SyscallDesc("semtimedop", unimplementedFunc), - /* 424 */ SyscallDesc("tgkill", unimplementedFunc), - /* 425 */ SyscallDesc("stat64", unimplementedFunc), - /* 426 */ SyscallDesc("lstat64", lstat64Func<Linux>), - /* 427 */ SyscallDesc("fstat64", fstat64Func<Linux>), - /* 428 */ SyscallDesc("vserver", unimplementedFunc), - /* 429 */ SyscallDesc("mbind", unimplementedFunc), - /* 430 */ SyscallDesc("get_mempolicy", unimplementedFunc), - /* 431 */ SyscallDesc("set_mempolicy", unimplementedFunc), - /* 432 */ SyscallDesc("mq_open", unimplementedFunc), - /* 433 */ SyscallDesc("mq_unlink", unimplementedFunc), - /* 434 */ SyscallDesc("mq_timedsend", unimplementedFunc), - /* 435 */ SyscallDesc("mq_timedreceive", unimplementedFunc), - /* 436 */ SyscallDesc("mq_notify", unimplementedFunc), - /* 437 */ SyscallDesc("mq_getsetattr", unimplementedFunc), - /* 438 */ SyscallDesc("waitid", unimplementedFunc), - /* 439 */ SyscallDesc("add_key", unimplementedFunc), - /* 440 */ SyscallDesc("request_key", unimplementedFunc), - /* 441 */ SyscallDesc("keyctl", unimplementedFunc) -}; - -MipsLinuxProcess::MipsLinuxProcess(const std::string &name, - ObjectFile *objFile, - int stdin_fd, - int stdout_fd, - int stderr_fd, - std::vector<std::string> &argv, - std::vector<std::string> &envp) - : LiveProcess(name, objFile, stdin_fd, stdout_fd, stderr_fd, argv, envp), - Num_Syscall_Descs(sizeof(syscallDescs) / sizeof(SyscallDesc)) -{ - init_regs->intRegFile[0] = 0; -} - - - -SyscallDesc* -MipsLinuxProcess::getDesc(int callnum) -{ - if (callnum < 0 || callnum > Num_Syscall_Descs) - return NULL; - return &syscallDescs[callnum]; -} diff --git a/arch/mips/linux_process.hh b/arch/mips/linux_process.hh deleted file mode 100644 index 5408a6c44..000000000 --- a/arch/mips/linux_process.hh +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2003-2004 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __MIPS_LINUX_PROCESS_HH__ -#define __MIPS_LINUX_PROCESS_HH__ - -#include "sim/process.hh" - - -/// A process with emulated Mips/Linux syscalls. -class MipsLinuxProcess : public LiveProcess -{ - public: - /// Constructor. - MipsLinuxProcess(const std::string &name, - ObjectFile *objFile, - int stdin_fd, int stdout_fd, int stderr_fd, - std::vector<std::string> &argv, - std::vector<std::string> &envp); - - virtual SyscallDesc* getDesc(int callnum); - - /// The target system's hostname. - static const char *hostname; - - /// Array of syscall descriptors, indexed by call number. - static SyscallDesc syscallDescs[]; - - const int Num_Syscall_Descs; -}; - - -#endif // __MIPS_LINUX_PROCESS_HH__ diff --git a/arch/mips/process.cc b/arch/mips/process.cc deleted file mode 100644 index 6de44fe9f..000000000 --- a/arch/mips/process.cc +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2003-2004 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "arch/mips/process.hh" - -namespace MipsISA -{ - -LiveProcess * -createProcess(const string &nm, ObjectFile * objFile, - int stdin_fd, int stdout_fd, int stderr_fd, - vector<string> &argv, vector<string> &envp) -{ - LiveProcess * process = NULL; - if (objFile->getArch() != ObjectFile::MIPS) - fatal("Object file does not match architecture."); - switch (objFile->getOpSys()) { - case ObjectFile::Linux: - process = new MipsLinuxProcess(nm, objFile, - stdin_fd, stdout_fd, stderr_fd, - argv, envp); - break; - - default: - fatal("Unknown/unsupported operating system."); - } - return process; -} - -} // namespace MipsISA - diff --git a/arch/mips/process.hh b/arch/mips/process.hh deleted file mode 100644 index ab4323107..000000000 --- a/arch/mips/process.hh +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2003-2004 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __MIPS_PROCESS_HH__ -#define __MIPS_PROCESS_HH__ - -#include "arch/mips/linux_process.hh" -#include "base/loader/object_file.hh" - -namespace MipsISA -{ - -LiveProcess * -createProcess(const string &nm, ObjectFile * objFile, - int stdin_fd, int stdout_fd, int stderr_fd, - vector<string> &argv, vector<string> &envp); - -} // namespace MipsISA - -#endif // __MIPS_PROCESS_HH__ diff --git a/arch/sparc/SConscript b/arch/sparc/SConscript deleted file mode 100644 index edff5821e..000000000 --- a/arch/sparc/SConscript +++ /dev/null @@ -1,82 +0,0 @@ -# -*- mode:python -*- - -# Copyright (c) 2004-2005 The Regents of The University of Michigan -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer; -# redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution; -# neither the name of the copyright holders nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -import os -import sys -from os.path import isdir - -# Import build environment variable from SConstruct. -Import('env') - -################################################### -# -# Define needed sources. -# -################################################### - -# Base sources used by all configurations. -base_sources = Split(''' - faults.cc - isa_traits.cc - ''') - -# Full-system sources -full_system_sources = Split(''' - tlb.cc - arguments.cc - ev5.cc - osfpal.cc - stacktrace.cc - vtophys.cc - ''') - -# Syscall emulation (non-full-system) sources -syscall_emulation_sources = Split(''' - common_syscall_emul.cc - linux_process.cc - process.cc - ''') - -sources = base_sources - -if env['FULL_SYSTEM']: - sources += full_system_sources -else: - sources += syscall_emulation_sources - -# Convert file names to SCons File objects. This takes care of the -# path relative to the top of the directory tree. -sources = [File(s) for s in sources] - -# Add in files generated by the ISA description. -isa_desc_files = env.ISADesc('isa/main.isa') -# Only non-header files need to be compiled. -isa_desc_sources = [f for f in isa_desc_files if not f.path.endswith('.hh')] -sources += isa_desc_sources - -Return('sources') diff --git a/arch/sparc/faults.cc b/arch/sparc/faults.cc deleted file mode 100644 index b48fc600b..000000000 --- a/arch/sparc/faults.cc +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "arch/sparc/faults.hh" -#include "cpu/exec_context.hh" -#include "cpu/base.hh" -#include "base/trace.hh" - -namespace SparcISA -{ - -FaultName InternalProcessorError::_name = "intprocerr"; -TrapType InternalProcessorError::_trapType = 0x029; -FaultPriority InternalProcessorError::_priority = 4; -FaultStat InternalProcessorError::_count; - -FaultName MemAddressNotAligned::_name = "unalign"; -TrapType MemAddressNotAligned::_trapType = 0x034; -FaultPriority MemAddressNotAligned::_priority = 10; -FaultStat MemAddressNotAligned::_count; - -FaultName PowerOnReset::_name = "pow_reset"; -TrapType PowerOnReset::_trapType = 0x001; -FaultPriority PowerOnReset::_priority = 0; -FaultStat PowerOnReset::_count; - -FaultName WatchDogReset::_name = "watch_dog_reset"; -TrapType WatchDogReset::_trapType = 0x002; -FaultPriority WatchDogReset::_priority = 1; -FaultStat WatchDogReset::_count; - -FaultName ExternallyInitiatedReset::_name = "extern_reset"; -TrapType ExternallyInitiatedReset::_trapType = 0x003; -FaultPriority ExternallyInitiatedReset::_priority = 1; -FaultStat ExternallyInitiatedReset::_count; - -FaultName SoftwareInitiatedReset::_name = "software_reset"; -TrapType SoftwareInitiatedReset::_trapType = 0x004; -FaultPriority SoftwareInitiatedReset::_priority = 1; -FaultStat SoftwareInitiatedReset::_count; - -FaultName REDStateException::_name = "red_counte"; -TrapType REDStateException::_trapType = 0x005; -FaultPriority REDStateException::_priority = 1; -FaultStat REDStateException::_count; - -FaultName InstructionAccessException::_name = "inst_access"; -TrapType InstructionAccessException::_trapType = 0x008; -FaultPriority InstructionAccessException::_priority = 5; -FaultStat InstructionAccessException::_count; - -FaultName InstructionAccessMMUMiss::_name = "inst_mmu"; -TrapType InstructionAccessMMUMiss::_trapType = 0x009; -FaultPriority InstructionAccessMMUMiss::_priority = 2; -FaultStat InstructionAccessMMUMiss::_count; - -FaultName InstructionAccessError::_name = "inst_error"; -TrapType InstructionAccessError::_trapType = 0x00A; -FaultPriority InstructionAccessError::_priority = 3; -FaultStat InstructionAccessError::_count; - -FaultName IllegalInstruction::_name = "illegal_inst"; -TrapType IllegalInstruction::_trapType = 0x010; -FaultPriority IllegalInstruction::_priority = 7; -FaultStat IllegalInstruction::_count; - -FaultName PrivelegedOpcode::_name = "priv_opcode"; -TrapType PrivelegedOpcode::_trapType = 0x011; -FaultPriority PrivelegedOpcode::_priority = 6; -FaultStat PrivelegedOpcode::_count; - -FaultName UnimplementedLDD::_name = "unimp_ldd"; -TrapType UnimplementedLDD::_trapType = 0x012; -FaultPriority UnimplementedLDD::_priority = 6; -FaultStat UnimplementedLDD::_count; - -FaultName UnimplementedSTD::_name = "unimp_std"; -TrapType UnimplementedSTD::_trapType = 0x013; -FaultPriority UnimplementedSTD::_priority = 6; -FaultStat UnimplementedSTD::_count; - -FaultName FpDisabled::_name = "fp_disabled"; -TrapType FpDisabled::_trapType = 0x020; -FaultPriority FpDisabled::_priority = 8; -FaultStat FpDisabled::_count; - -FaultName FpExceptionIEEE754::_name = "fp_754"; -TrapType FpExceptionIEEE754::_trapType = 0x021; -FaultPriority FpExceptionIEEE754::_priority = 11; -FaultStat FpExceptionIEEE754::_count; - -FaultName FpExceptionOther::_name = "fp_other"; -TrapType FpExceptionOther::_trapType = 0x022; -FaultPriority FpExceptionOther::_priority = 11; -FaultStat FpExceptionOther::_count; - -FaultName TagOverflow::_name = "tag_overflow"; -TrapType TagOverflow::_trapType = 0x023; -FaultPriority TagOverflow::_priority = 14; -FaultStat TagOverflow::_count; - -FaultName DivisionByZero::_name = "div_by_zero"; -TrapType DivisionByZero::_trapType = 0x028; -FaultPriority DivisionByZero::_priority = 15; -FaultStat DivisionByZero::_count; - -FaultName DataAccessException::_name = "data_access"; -TrapType DataAccessException::_trapType = 0x030; -FaultPriority DataAccessException::_priority = 12; -FaultStat DataAccessException::_count; - -FaultName DataAccessMMUMiss::_name = "data_mmu"; -TrapType DataAccessMMUMiss::_trapType = 0x031; -FaultPriority DataAccessMMUMiss::_priority = 12; -FaultStat DataAccessMMUMiss::_count; - -FaultName DataAccessError::_name = "data_error"; -TrapType DataAccessError::_trapType = 0x032; -FaultPriority DataAccessError::_priority = 12; -FaultStat DataAccessError::_count; - -FaultName DataAccessProtection::_name = "data_protection"; -TrapType DataAccessProtection::_trapType = 0x033; -FaultPriority DataAccessProtection::_priority = 12; -FaultStat DataAccessProtection::_count; - -FaultName LDDFMemAddressNotAligned::_name = "unalign_lddf"; -TrapType LDDFMemAddressNotAligned::_trapType = 0x035; -FaultPriority LDDFMemAddressNotAligned::_priority = 10; -FaultStat LDDFMemAddressNotAligned::_count; - -FaultName STDFMemAddressNotAligned::_name = "unalign_stdf"; -TrapType STDFMemAddressNotAligned::_trapType = 0x036; -FaultPriority STDFMemAddressNotAligned::_priority = 10; -FaultStat STDFMemAddressNotAligned::_count; - -FaultName PrivelegedAction::_name = "priv_action"; -TrapType PrivelegedAction::_trapType = 0x037; -FaultPriority PrivelegedAction::_priority = 11; -FaultStat PrivelegedAction::_count; - -FaultName LDQFMemAddressNotAligned::_name = "unalign_ldqf"; -TrapType LDQFMemAddressNotAligned::_trapType = 0x038; -FaultPriority LDQFMemAddressNotAligned::_priority = 10; -FaultStat LDQFMemAddressNotAligned::_count; - -FaultName STQFMemAddressNotAligned::_name = "unalign_stqf"; -TrapType STQFMemAddressNotAligned::_trapType = 0x039; -FaultPriority STQFMemAddressNotAligned::_priority = 10; -FaultStat STQFMemAddressNotAligned::_count; - -FaultName AsyncDataError::_name = "async_data"; -TrapType AsyncDataError::_trapType = 0x040; -FaultPriority AsyncDataError::_priority = 2; -FaultStat AsyncDataError::_count; - -//The enumerated faults - -FaultName CleanWindow::_name = "clean_win"; -TrapType CleanWindow::_baseTrapType = 0x024; -FaultPriority CleanWindow::_priority = 10; -FaultStat CleanWindow::_count; - -FaultName InterruptLevelN::_name = "interrupt_n"; -TrapType InterruptLevelN::_baseTrapType = 0x041; -FaultStat InterruptLevelN::_count; - -FaultName SpillNNormal::_name = "spill_n_normal"; -TrapType SpillNNormal::_baseTrapType = 0x080; -FaultPriority SpillNNormal::_priority = 9; -FaultStat SpillNNormal::_count; - -FaultName SpillNOther::_name = "spill_n_other"; -TrapType SpillNOther::_baseTrapType = 0x0A0; -FaultPriority SpillNOther::_priority = 9; -FaultStat SpillNOther::_count; - -FaultName FillNNormal::_name = "fill_n_normal"; -TrapType FillNNormal::_baseTrapType = 0x0C0; -FaultPriority FillNNormal::_priority = 9; -FaultStat FillNNormal::_count; - -FaultName FillNOther::_name = "fill_n_other"; -TrapType FillNOther::_baseTrapType = 0x0E0; -FaultPriority FillNOther::_priority = 9; -FaultStat FillNOther::_count; - -FaultName TrapInstruction::_name = "trap_inst_n"; -TrapType TrapInstruction::_baseTrapType = 0x100; -FaultPriority TrapInstruction::_priority = 16; -FaultStat TrapInstruction::_count; - - - -#if FULL_SYSTEM - -void SparcFault::invoke(ExecContext * xc) -{ - FaultBase::invoke(xc); - countStat()++; - - //Use the SPARC trap state machine - /*// exception restart address - if (setRestartAddress() || !xc->inPalMode()) - xc->setMiscReg(AlphaISA::IPR_EXC_ADDR, xc->regs.pc); - - if (skipFaultingInstruction()) { - // traps... skip faulting instruction. - xc->setMiscReg(AlphaISA::IPR_EXC_ADDR, - xc->readMiscReg(AlphaISA::IPR_EXC_ADDR) + 4); - } - - if (!xc->inPalMode()) - AlphaISA::swap_palshadow(&(xc->regs), true); - - xc->regs.pc = xc->readMiscReg(AlphaISA::IPR_PAL_BASE) + vect(); - xc->regs.npc = xc->regs.pc + sizeof(MachInst);*/ -} - -#endif - -} // namespace SparcISA - diff --git a/arch/sparc/faults.hh b/arch/sparc/faults.hh deleted file mode 100644 index 318b1ad5a..000000000 --- a/arch/sparc/faults.hh +++ /dev/null @@ -1,587 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __ALPHA_FAULTS_HH__ -#define __ALPHA_FAULTS_HH__ - -#include "sim/faults.hh" - -// The design of the "name" and "vect" functions is in sim/faults.hh - -namespace SparcISA -{ - -typedef const uint32_t TrapType; -typedef const uint32_t FaultPriority; - -class SparcFault : public FaultBase -{ - public: -#if FULL_SYSTEM - void invoke(ExecContext * xc); -#endif - virtual TrapType trapType() = 0; - virtual FaultPriority priority() = 0; - virtual FaultStat & countStat() = 0; -}; - -class InternalProcessorError : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} - bool isMachineCheckFault() {return true;} -}; - -class MemAddressNotAligned : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} - bool isAlignmentFault() {return true;} -}; - -static inline Fault genMachineCheckFault() -{ - return new InternalProcessorError; -} - -static inline Fault genAlignmentFault() -{ - return new MemAddressNotAligned; -} - -class PowerOnReset : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class WatchDogReset : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class ExternallyInitiatedReset : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class SoftwareInitiatedReset : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class REDStateException : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class InstructionAccessException : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class InstructionAccessMMUMiss : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class InstructionAccessError : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class IllegalInstruction : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class PrivelegedOpcode : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class UnimplementedLDD : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class UnimplementedSTD : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class FpDisabled : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class FpExceptionIEEE754 : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class FpExceptionOther : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class TagOverflow : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class DivisionByZero : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class DataAccessException : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class DataAccessMMUMiss : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class DataAccessError : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class DataAccessProtection : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class LDDFMemAddressNotAligned : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class STDFMemAddressNotAligned : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class PrivelegedAction : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class LDQFMemAddressNotAligned : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class STQFMemAddressNotAligned : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class AsyncDataError : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class EnumeratedFault : public SparcFault -{ - protected: - uint32_t _n; - virtual TrapType baseTrapType() = 0; - public: - EnumeratedFault(uint32_t n) : SparcFault() {_n = n;} - TrapType trapType() {return baseTrapType() + _n;} -}; - -class CleanWindow : public EnumeratedFault -{ - private: - static FaultName _name; - static TrapType _baseTrapType; - static FaultPriority _priority; - static FaultStat _count; - TrapType baseTrapType() {return _baseTrapType;} - public: - CleanWindow(uint32_t n) : EnumeratedFault(n) {;} - FaultName name() {return _name;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class InterruptLevelN : public EnumeratedFault -{ - private: - static FaultName _name; - static TrapType _baseTrapType; - static FaultStat _count; - TrapType baseTrapType() {return _baseTrapType;} - public: - InterruptLevelN(uint32_t n) : EnumeratedFault(n) {;} - FaultName name() {return _name;} - FaultPriority priority() {return 32 - _n;} - FaultStat & countStat() {return _count;} -}; - -class SpillNNormal : public EnumeratedFault -{ - private: - static FaultName _name; - static TrapType _baseTrapType; - static FaultPriority _priority; - static FaultStat _count; - TrapType baseTrapType() {return _baseTrapType;} - public: - SpillNNormal(uint32_t n) : EnumeratedFault(n) {;} - FaultName name() {return _name;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class SpillNOther : public EnumeratedFault -{ - private: - static FaultName _name; - static TrapType _baseTrapType; - static FaultPriority _priority; - static FaultStat _count; - TrapType baseTrapType() {return _baseTrapType;} - public: - SpillNOther(uint32_t n) : EnumeratedFault(n) {;} - FaultName name() {return _name;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class FillNNormal : public EnumeratedFault -{ - private: - static FaultName _name; - static TrapType _baseTrapType; - static FaultPriority _priority; - static FaultStat _count; - TrapType baseTrapType() {return _baseTrapType;} - public: - FillNNormal(uint32_t n) : EnumeratedFault(n) {;} - FaultName name() {return _name;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class FillNOther : public EnumeratedFault -{ - private: - static FaultName _name; - static TrapType _baseTrapType; - static FaultPriority _priority; - static FaultStat _count; - TrapType baseTrapType() {return _baseTrapType;} - public: - FillNOther(uint32_t n) : EnumeratedFault(n) {;} - FaultName name() {return _name;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class TrapInstruction : public EnumeratedFault -{ - private: - static FaultName _name; - static TrapType _baseTrapType; - static FaultPriority _priority; - static FaultStat _count; - TrapType baseTrapType() {return _baseTrapType;} - public: - TrapInstruction(uint32_t n) : EnumeratedFault(n) {;} - FaultName name() {return _name;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -} // SparcISA namespace - -#endif // __FAULTS_HH__ diff --git a/arch/sparc/isa/base.isa b/arch/sparc/isa/base.isa deleted file mode 100644 index 992504369..000000000 --- a/arch/sparc/isa/base.isa +++ /dev/null @@ -1,129 +0,0 @@ -//////////////////////////////////////////////////////////////////// -// -// Base class for sparc instructions, and some support functions -// - -output header {{ - - struct condCodes - { - uint8_t c:1; - uint8_t v:1; - uint8_t z:1; - uint8_t n:1; - } - - enum condTest - { - Always=0x8, - Never=0x0, - NotEqual=0x9, - Equal=0x1, - Greater=0xA, - LessOrEqual=0x2, - GreaterOrEqual=0xB, - Less=0x3, - GreaterUnsigned=0xC, - LessOrEqualUnsigned=0x4, - CarryClear=0xD, - CarrySet=0x5, - Positive=0xE, - Negative=0x6, - OverflowClear=0xF, - OverflowSet=0x7 - } - - /** - * Base class for all SPARC static instructions. - */ - class SparcStaticInst : public StaticInst - { - protected: - // Constructor. - SparcStaticInst(const char *mnem, - MachInst _machInst, OpClass __opClass) - : StaticInst(mnem, _machInst, __opClass) - { - } - - std::string generateDisassembly(Addr pc, - const SymbolTable *symtab) const; - }; - - bool passesCondition(condCodes codes, condTest condition); -}}; - -output decoder {{ - - std::string SparcStaticInst::generateDisassembly(Addr pc, - const SymbolTable *symtab) const - { - std::stringstream ss; - - ccprintf(ss, "%-10s ", mnemonic); - - // just print the first two source regs... if there's - // a third one, it's a read-modify-write dest (Rc), - // e.g. for CMOVxx - if(_numSrcRegs > 0) - { - printReg(ss, _srcRegIdx[0]); - } - if(_numSrcRegs > 1) - { - ss << ","; - printReg(ss, _srcRegIdx[1]); - } - - // just print the first dest... if there's a second one, - // it's generally implicit - if(_numDestRegs > 0) - { - if(_numSrcRegs > 0) - ss << ","; - printReg(ss, _destRegIdx[0]); - } - - return ss.str(); - } - - bool passesCondition(condCodes codes, condTest condition) - { - switch(condition) - { - case Always: - return true; - case Never: - return false; - case NotEqual: - return !codes.z; - case Equal: - return codes.z; - case Greater: - return !(codes.z | (codes.n ^ codes.v)); - case LessOrEqual: - return codes.z | (codes.n ^ codes.v); - case GreaterOrEqual: - return !(codes.n ^ codes.v); - case Less: - return (codes.n ^ codes.v); - case GreaterUnsigned: - return !(codes.c | codes.z); - case LessOrEqualUnsigned: - return (codes.c | codes.z); - case CarryClear: - return !codes.c; - case CarrySet: - return codes.c; - case Positive: - return !codes.n; - case Negative: - return codes.n; - case OverflowClear: - return !codes.v; - case OverflowSet: - return codes.v; - } - } -}}; - diff --git a/arch/sparc/isa/bitfields.isa b/arch/sparc/isa/bitfields.isa deleted file mode 100644 index b0ac57575..000000000 --- a/arch/sparc/isa/bitfields.isa +++ /dev/null @@ -1,50 +0,0 @@ -//////////////////////////////////////////////////////////////////// -// -// Bitfield definitions. -// - -// Bitfields are shared liberally between instruction formats, so they are -// simply defined alphabetically - -def bitfield A <29>; -def bitfield CC02 <20>; -def bitfield CC03 <25>; -def bitfield CC04 <11>; -def bitfield CC12 <21>; -def bitfield CC13 <26>; -def bitfield CC14 <12>; -def bitfield CC2 <18>; -def bitfield CMASK <6:4>; -def bitfield COND2 <28:25>; -def bitfield COND4 <17:14>; -def bitfield D16HI <21:20>; -def bitfield D16LO <13:0>; -def bitfield DISP19 <18:0>; -def bitfield DISP22 <21:0>; -def bitfield DISP30 <29:0>; -def bitfield FCN <29:26>; -def bitfield I <13>; -def bitfield IMM_ASI <12:5>; -def bitfield IMM22 <21:0>; -def bitfield MMASK <3:0>; -def bitfield OP <31:30>; -def bitfield OP2 <24:22>; -def bitfield OP3 <24:19>; -def bitfield OPF <13:5>; -def bitfield OPF_CC <13:11>; -def bitfield OPF_LOW5 <9:5>; -def bitfield OPF_LOW6 <10:5>; -def bitfield P <19>; -def bitfield RCOND2 <27:25>; -def bitfield RCOND3 <12:10>; -def bitfield RCOND4 <12:10>; -def bitfield RD <29:25>; -def bitfield RS1 <18:14>; -def bitfield RS2 <4:0>; -def bitfield SHCNT32 <4:0>; -def bitfield SHCNT64 <5:0>; -def bitfield SIMM10 <9:0>; -def bitfield SIMM11 <10:0>; -def bitfield SIMM13 <12:0>; -def bitfield SW_TRAP <6:0>; -def bitfield X <12>; diff --git a/arch/sparc/isa/decoder.isa b/arch/sparc/isa/decoder.isa deleted file mode 100644 index eb458211b..000000000 --- a/arch/sparc/isa/decoder.isa +++ /dev/null @@ -1,662 +0,0 @@ -//////////////////////////////////////////////////////////////////// -// -// The actual decoder specification -// - -decode OP default Trap::unknown({{IllegalInstruction}}) { - - 0x0: decode OP2 { - 0x0: Trap::illtrap({{illegal_instruction}}); //ILLTRAP - 0x1: Branch::bpcc({{ - switch((CC12 << 1) | CC02) - { - case 1: - case 3: - fault = new IllegalInstruction; - case 0: - if(passesCondition(xc->regs.MiscRegs.ccrFields.icc, COND2)) - ;//branchHere - break; - case 2: - if(passesCondition(xc->regs.MiscRegs.ccrFields.xcc, COND2)) - ;//branchHere - break; - } - }});//BPcc - 0x2: Branch::bicc({{ - if(passesCondition(xc->regs.MiscRegs.ccrFields.icc, COND2)) - ;//branchHere - }});//Bicc - 0x3: Branch::bpr({{ - switch(RCOND) - { - case 0: - case 4: - fault = new IllegalInstruction; - case 1: - if(Rs1 == 0) - ;//branchHere - break; - case 2: - if(Rs1 <= 0) - ;//branchHere - break; - case 3: - if(Rs1 < 0) - ;//branchHere - break; - case 5: - if(Rs1 != 0) - ;//branchHere - break; - case 6: - if(Rs1 > 0) - ;//branchHere - break; - case 7: - if(Rs1 >= 0) - ;//branchHere - break; - } - }}); //BPr - //SETHI (or NOP if rd == 0 and imm == 0) - 0x4: IntegerOp::sethi({{Rd = (IMM22 << 10) & 0xFFFFFC00;}}); - 0x5: Trap::fbpfcc({{throw fp_disabled;}}); //FBPfcc - 0x6: Trap::fbfcc({{throw fp_disabled;}}); //FBfcc - } - 0x1: Branch::call({{ - //branch here - Rd = xc->pc; - }}); - 0x2: decode OP3 { - format IntegerOp { - 0x00: add({{ - int64_t val2 = (I ? SIMM13.sdw : Rs2.sdw); - Rd = Rs1.sdw + val2; - }});//ADD - 0x01: and({{ - uint64_t val2 = (I ? SIMM13.sdw : Rs2.udw); - Rd = Rs1.udw & val2; - }});//AND - 0x02: or({{ - uint64_t val2 = (I ? SIMM13.sdw : Rs2.udw); - Rd = Rs1.udw | val2; - }});//OR - 0x03: xor({{ - uint64_t val2 = (I ? SIMM13.sdw : Rs2.udw); - Rd = Rs1.udw ^ val2; - }});//XOR - 0x04: sub({{ - int64_t val2 = ~((uint64_t)(I ? SIMM13.sdw : Rs2.udw))+1; - Rd = Rs1.sdw + val2; - }});//SUB - 0x05: andn({{ - uint64_t val2 = (I ? SIMM13.sdw : Rs2.udw); - Rd = Rs1.udw & ~val2; - }});//ANDN - 0x06: orn({{ - uint64_t val2 = (I ? SIMM13.sdw : Rs2.udw); - Rd = Rs1.udw | ~val2; - }});//ORN - 0x07: xnor({{ - uint64_t val2 = (I ? SIMM13.sdw : Rs2.udw); - Rd = ~(Rs1.udw ^ val2); - }});//XNOR - 0x08: addc({{ - int64_t val2 = (I ? SIMM13.sdw : Rs2.sdw); - int64_t carryin = xc->regs.MiscRegs.ccrfields.iccfields.c; - Rd = Rs1.sdw + val2 + carryin; - }});//ADDC - 0x09: mulx({{ - int64_t val2 = (I ? SIMM13.sdw : Rs2); - Rd = Rs1 * val2; - }});//MULX - 0x0A: umul({{ - uint64_t resTemp, val2 = (I ? SIMM13.sdw : Rs2.udw); - Rd = resTemp = Rs1.udw<31:0> * val2<31:0>; - xc->regs.MiscRegs.yFields.value = resTemp<63:32>; - }});//UMUL - 0x0B: smul({{ - int64_t resTemp, val2 = (I ? SIMM13.sdw : Rs2.sdw); - rd.sdw = resTemp = Rs1.sdw<31:0> * val2<31:0>; - xc->regs.MiscRegs.yFields.value = resTemp<63:32>; - }});//SMUL - 0x0C: subc({{ - int64_t val2 = ~((int64_t)(I ? SIMM13.sdw : Rs2.sdw))+1; - int64_t carryin = xc->regs.MiscRegs.ccrfields.iccfields.c; - Rd.sdw = Rs1.sdw + val2 + carryin; - }});//SUBC - 0x0D: udivx({{ - uint64_t val2 = (I ? SIMM13.sdw : Rs2.udw); - if(val2 == 0) throw division_by_zero; - Rd.udw = Rs1.udw / val2; - }});//UDIVX - 0x0E: udiv({{ - uint32_t resTemp, val2 = (I ? SIMM13.sw : Rs2.udw<31:0>); - if(val2 == 0) - fault = new DivisionByZero; - resTemp = (uint64_t)((xc->regs.MiscRegs.yFields.value << 32) - | Rs1.udw<31:0>) / val2; - int32_t overflow = (resTemp<63:32> != 0); - if(overflow) - rd.udw = resTemp = 0xFFFFFFFF; - else - rd.udw = resTemp; - }}); //UDIV - 0x0F: sdiv({{ - int32_t resTemp, val2 = (I ? SIMM13.sw : Rs2.sdw<31:0>); - if(val2 == 0) - fault = new DivisionByZero; - - Rd.sdw = (int64_t)((xc->regs.MiscRegs.yFields.value << 32) | - Rs1.sdw<31:0>) / val2; - resTemp = Rd.sdw; - int32_t overflow = (resTemp<63:31> != 0); - int32_t underflow = - (resTemp<63:> && resTemp<62:31> != 0xFFFFFFFF); - if(overflow) - rd.udw = resTemp = 0x7FFFFFFF; - else if(underflow) - rd.udw = resTemp = 0xFFFFFFFF80000000; - else - rd.udw = resTemp; - }});//SDIV - } - format IntegerOpCc { - 0x10: addcc({{ - int64_t resTemp, val2 = (I ? SIMM13.sdw : Rs2); - Rd = resTemp = Rs1 + val2;}}, - {{((Rs1 & 0xFFFFFFFF + val2 & 0xFFFFFFFF) >> 31)}}, - {{Rs1<31:> == val2<31:> && val2<31:> != resTemp<31:>}}, - {{((Rs1 >> 1) + (val2 >> 1) + (Rs1 & val2 & 0x1))<63:>}}, - {{Rs1<63:> == val2<63:> && val2<63:> != resTemp<63:>}} - );//ADDcc - 0x11: andcc({{ - int64_t val2 = (I ? SIMM13.sdw : Rs2); - Rd = Rs1 & val2;}}, - {{0}},{{0}},{{0}},{{0}});//ANDcc - 0x12: orcc({{ - int64_t val2 = (I ? SIMM13.sdw : Rs2); - Rd = Rs1 | val2;}}, - {{0}},{{0}},{{0}},{{0}});//ORcc - 0x13: xorcc({{ - int64_t val2 = (I ? SIMM13.sdw : Rs2); - Rd = Rs1 ^ val2;}}, - {{0}},{{0}},{{0}},{{0}});//XORcc - 0x14: subcc({{ - int64_t resTemp, val2 = (int64_t)(I ? SIMM13.sdw : Rs2); - Rd = resTemp = Rs1 - val2;}}, - {{((Rs1 & 0xFFFFFFFF + (~val2) & 0xFFFFFFFF + 1) >> 31)}}, - {{Rs1<31:> != val2<31:> && Rs1<31:> != resTemp<31:>}}, - {{((Rs1 >> 1) + (~val2) >> 1) + - ((Rs1 | ~val2) & 0x1))<63:>}}, - {{Rs1<63:> != val2<63:> && Rs1<63:> != resTemp<63:>}} - );//SUBcc - 0x15: andncc({{ - int64_t val2 = (I ? SIMM13.sdw : Rs2); - Rd = Rs1 & ~val2;}}, - {{0}},{{0}},{{0}},{{0}});//ANDNcc - 0x16: orncc({{ - int64_t val2 = (I ? SIMM13.sdw : Rs2); - Rd = Rs1 | ~val2;}}, - {{0}},{{0}},{{0}},{{0}});//ORNcc - 0x17: xnorcc({{ - int64_t val2 = (I ? SIMM13.sdw : Rs2); - Rd = ~(Rs1 ^ val2);}}, - {{0}},{{0}},{{0}},{{0}});//XNORcc - 0x18: addccc({{ - int64_t resTemp, val2 = (I ? SIMM13.sdw : Rs2); - int64_t carryin = xc->regs.MiscRegs.ccrfields.iccfields.c; - Rd = resTemp = Rs1 + val2 + carryin;}}, - {{((Rs1 & 0xFFFFFFFF + val2 & 0xFFFFFFFF) >> 31 - + carryin)}}, - {{Rs1<31:> == val2<31:> && val2<31:> != resTemp<31:>}}, - {{((Rs1 >> 1) + (val2 >> 1) + - ((Rs1 & val2) | (carryin & (Rs1 | val2)) & 0x1))<63:>}}, - {{Rs1<63:> == val2<63:> && val2<63:> != resTemp<63:>}} - );//ADDCcc - 0x1A: umulcc({{ - uint64_t resTemp, val2 = (I ? SIMM13.sdw : Rs2); - Rd = resTemp = Rs1.udw<31:0> * val2<31:0>; - xc->regs.MiscRegs.yFields.value = resTemp<63:32>;}}, - {{0}},{{0}},{{0}},{{0}});//UMULcc - 0x1B: smulcc({{ - int64_t resTemp, val2 = (I ? SIMM13.sdw : Rs2); - Rd = resTemp = Rs1.sdw<31:0> * val2<31:0>; - xc->regs.MiscRegs.yFields.value = resTemp<63:32>;}} - ,{{0}},{{0}},{{0}},{{0}});//SMULcc - 0x1C: subccc({{ - int64_t resTemp, val2 = (int64_t)(I ? SIMM13.sdw : Rs2); - int64_t carryin = xc->regs.MiscRegs.ccrfields.iccfields.c; - Rd = resTemp = Rs1 + ~(val2 + carryin) + 1;}}, - {{((Rs1 & 0xFFFFFFFF + (~(val2 + carryin)) & 0xFFFFFFFF + 1) >> 31)}}, - {{Rs1<31:> != val2<31:> && Rs1<31:> != resTemp<31:>}}, - {{((Rs1 >> 1) + (~(val2 + carryin)) >> 1) + ((Rs1 | ~(val2+carryin)) & 0x1))<63:>}}, - {{Rs1<63:> != val2<63:> && Rs1<63:> != resTemp<63:>}} - );//SUBCcc - 0x1D: udivxcc({{ - uint64_t val2 = (I ? SIMM13.sdw : Rs2.udw); - if(val2 == 0) throw division_by_zero; - Rd.udw = Rs1.udw / val2;}} - ,{{0}},{{0}},{{0}},{{0}});//UDIVXcc - 0x1E: udivcc({{ - uint32_t resTemp, val2 = (I ? SIMM13.sw : Rs2.udw<31:0>); - if(val2 == 0) throw division_by_zero; - resTemp = (uint64_t)((xc->regs.MiscRegs.yFields.value << 32) | Rs1.udw<31:0>) / val2; - int32_t overflow = (resTemp<63:32> != 0); - if(overflow) rd.udw = resTemp = 0xFFFFFFFF; - else rd.udw = resTemp;}}, - {{0}}, - {{overflow}}, - {{0}}, - {{0}} - );//UDIVcc - 0x1F: sdivcc({{ - int32_t resTemp, val2 = (I ? SIMM13.sw : Rs2.sdw<31:0>); - if(val2 == 0) throw division_by_zero; - Rd.sdw = resTemp = (int64_t)((xc->regs.MiscRegs.yFields.value << 32) | Rs1.sdw<31:0>) / val2; - int32_t overflow = (resTemp<63:31> != 0); - int32_t underflow = (resTemp<63:> && resTemp<62:31> != 0xFFFFFFFF); - if(overflow) rd.udw = resTemp = 0x7FFFFFFF; - else if(underflow) rd.udw = resTemp = 0xFFFFFFFF80000000; - else rd.udw = resTemp;}}, - {{0}}, - {{overflow || underflow}}, - {{0}}, - {{0}} - );//SDIVcc - 0x20: taddcc({{ - int64_t resTemp, val2 = (I ? SIMM13.sdw : Rs2); - Rd = resTemp = Rs1 + val2; - int32_t overflow = Rs1<1:0> || val2<1:0> || (Rs1<31:> == val2<31:> && val2<31:> != resTemp<31:>);}}, - {{((Rs1 & 0xFFFFFFFF + val2 & 0xFFFFFFFF) >> 31)}}, - {{overflow}}, - {{((Rs1 >> 1) + (val2 >> 1) + (Rs1 & val2 & 0x1))<63:>}}, - {{Rs1<63:> == val2<63:> && val2<63:> != resTemp<63:>}} - );//TADDcc - 0x21: tsubcc({{ - int64_t resTemp, val2 = (I ? SIMM13.sdw : Rs2); - Rd = resTemp = Rs1 + val2; - int32_t overflow = Rs1<1:0> || val2<1:0> || (Rs1<31:> == val2<31:> && val2<31:> != resTemp<31:>);}}, - {{(Rs1 & 0xFFFFFFFF + val2 & 0xFFFFFFFF) >> 31)}}, - {{overflow}}, - {{((Rs1 >> 1) + (val2 >> 1) + (Rs1 & val2 & 0x1))<63:>}}, - {{Rs1<63:> == val2<63:> && val2<63:> != resTemp<63:>}} - );//TSUBcc - 0x22: taddcctv({{ - int64_t resTemp, val2 = (I ? SIMM13.sdw : Rs2); - Rd = resTemp = Rs1 + val2; - int32_t overflow = Rs1<1:0> || val2<1:0> || (Rs1<31:> == val2<31:> && val2<31:> != resTemp<31:>); - if(overflow) throw tag_overflow;}}, - {{((Rs1 & 0xFFFFFFFF + val2 & 0xFFFFFFFF) >> 31)}}, - {{overflow}}, - {{((Rs1 >> 1) + (val2 >> 1) + (Rs1 & val2 & 0x1))<63:>}}, - {{Rs1<63:> == val2<63:> && val2<63:> != resTemp<63:>}} - );//TADDccTV - 0x23: tsubcctv({{ - int64_t resTemp, val2 = (I ? SIMM13.sdw : Rs2); - Rd = resTemp = Rs1 + val2; - int32_t overflow = Rs1<1:0> || val2<1:0> || (Rs1<31:> == val2<31:> && val2<31:> != resTemp<31:>); - if(overflow) throw tag_overflow;}}, - {{((Rs1 & 0xFFFFFFFF + val2 & 0xFFFFFFFF) >> 31)}}, - {{overflow}}, - {{((Rs1 >> 1) + (val2 >> 1) + (Rs1 & val2 & 0x1))<63:>}}, - {{Rs1<63:> == val2<63:> && val2<63:> != resTemp<63:>}} - );//TSUBccTV - 0x24: mulscc({{ - int64_t resTemp, multiplicand = (I ? SIMM13.sdw : Rs2); - int32_t multiplier = Rs1<31:0>; - int32_t savedLSB = Rs1<0:>; - multiplier = multipler<31:1> | - ((xc->regs.MiscRegs.ccrFields.iccFields.n - ^ xc->regs.MiscRegs.ccrFields.iccFields.v) << 32); - if(!xc->regs.MiscRegs.yFields.value<0:>) - multiplicand = 0; - Rd = resTemp = multiplicand + multiplier; - xc->regs.MiscRegs.yFields.value = xc->regs.MiscRegs.yFields.value<31:1> | (savedLSB << 31);}}, - {{((multiplicand & 0xFFFFFFFF + multiplier & 0xFFFFFFFF) >> 31)}}, - {{multiplicand<31:> == multiplier<31:> && multiplier<31:> != resTemp<31:>}}, - {{((multiplicand >> 1) + (multiplier >> 1) + (multiplicand & multiplier & 0x1))<63:>}}, - {{multiplicand<63:> == multiplier<63:> && multiplier<63:> != resTemp<63:>}} - );//MULScc - } - format IntegerOp - { - 0x25: decode X { - 0x0: sll({{Rd = Rs1 << (I ? SHCNT32 : Rs2<4:0>);}}); //SLL - 0x1: sllx({{Rd = Rs1 << (I ? SHCNT64 : Rs2<5:0>);}}); //SLLX - } - 0x26: decode X { - 0x0: srl({{Rd = Rs1.udw<31:0> >> (I ? SHCNT32 : Rs2<4:0>);}}); //SRL - 0x1: srlx({{Rd = Rs1.udw >> (I ? SHCNT64 : Rs2<5:0>);}});//SRLX - } - 0x27: decode X { - 0x0: sra({{Rd = Rs1.sdw<31:0> >> (I ? SHCNT32 : Rs2<4:0>);}}); //SRA - 0x1: srax({{Rd = Rs1.sdw >> (I ? SHCNT64 : Rs2<5:0>);}});//SRAX - } - 0x28: decode RS1 { - 0x0: rdy({{Rd = xc->regs.MiscRegs.yFields.value;}}); //RDY - 0x2: rdccr({{Rd = xc->regs.MiscRegs.ccr;}}); //RDCCR - 0x3: rdasi({{Rd = xc->regs.MiscRegs.asi;}}); //RDASI - 0x4: rdtick({{ - if(xc->regs.MiscRegs.pstateFields.priv == 0 && - xc->regs.MiscRegs.tickFields.npt == 1) - throw privileged_action; - Rd = xc->regs.MiscRegs.tick; - }});//RDTICK - 0x5: rdpc({{Rd = xc->regs.pc;}}); //RDPC - 0x6: rdfprs({{Rd = xc->regs.MiscRegs.fprs;}}); //RDFPRS - 0xF: decode I { - 0x0: Noop::membar({{//Membar isn't needed yet}}); //MEMBAR - 0x1: Noop::stbar({{//Stbar isn/'t needed yet}}); //STBAR - } - } - - 0x2A: decode RS1 { - 0x0: rdprtpc({{checkPriv Rd = xc->regs.MiscRegs.tpc[xc->regs.MiscRegs.tl];}}); - 0x1: rdprtnpc({{checkPriv Rd = xc->regs.MiscRegs.tnpc[xc->regs.MiscRegs.tl];}}); - 0x2: rdprtstate({{checkPriv Rd = xc->regs.MiscRegs.tstate[xc->regs.MiscRegs.tl];}}); - 0x3: rdprtt({{checkPriv Rd = xc->regs.MiscRegs.tt[xc->regs.MiscRegs.tl];}}); - 0x4: rdprtick({{checkPriv Rd = xc->regs.MiscRegs.tick;}}); - 0x5: rdprtba({{checkPriv Rd = xc->regs.MiscRegs.tba;}}); - 0x6: rdprpstate({{checkPriv Rd = xc->regs.MiscRegs.pstate;}}); - 0x7: rdprtl({{checkPriv Rd = xc->regs.MiscRegs.tl;}}); - 0x8: rdprpil({{checkPriv Rd = xc->regs.MiscRegs.pil;}}); - 0x9: rdprcwp({{checkPriv Rd = xc->regs.MiscRegs.cwp;}}); - 0xA: rdprcansave({{checkPriv Rd = xc->regs.MiscRegs.cansave;}}); - 0xB: rdprcanrestore({{checkPriv Rd = xc->regs.MiscRegs.canrestore;}}); - 0xC: rdprcleanwin({{checkPriv Rd = xc->regs.MiscRegs.cleanwin;}}); - 0xD: rdprotherwin({{checkPriv Rd = xc->regs.MiscRegs.otherwin;}}); - 0xE: rdprwstate({{checkPriv Rd = xc->regs.MiscRegs.wstate;}}); - 0xF: rdprfq({{throw illegal_instruction;}}); //The floating point queue isn't implemented right now. - } - 0x2B: BasicOperate::flushw({{\\window toilet}}); //FLUSHW - 0x2C: movcc({{ - ccBank = (CC24 << 2) | (CC14 << 1) | (CC04 << 0); - switch(ccBank) - { - case 0: case 1: case 2: case 3: - throw fp_disabled; - break; - case 5: case 7: - throw illegal_instruction; - break; - case 4: - if(passesCondition(xc->regs.MiscRegs.ccrFields.icc, COND4)) - Rd = (I ? SIMM11.sdw : RS2); - break; - case 6: - if(passesCondition(xc->regs.MiscRegs.ccrFields.xcc, COND4)) - Rd = (I ? SIMM11.sdw : RS2); - break; - } - }});//MOVcc - 0x2D: sdivx({{ - int64_t val2 = (I ? SIMM13.sdw : Rs2.sdw); - if(val2 == 0) throw division_by_zero; - Rd.sdw = Rs1.sdw / val2; - }});//SDIVX - 0x2E: decode RS1 { - 0x0: IntegerOp::popc({{ - int64_t count = 0, val2 = (I ? SIMM13.sdw : Rs2.sdw); - uint8_t oneBits[] = {0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4} - for(unsigned int x = 0; x < 16; x++) - { - count += oneBits[val2 & 0xF]; - val2 >> 4; - } - }});//POPC - } - 0x2F: movr({{ - uint64_t val2 = (I ? SIMM10.sdw : Rs2.sdw); - switch(RCOND) - { - case 0: case 4: - throw illegal_instruction; - break; - case 1: - if(Rs1 == 0) Rd = val2; - break; - case 2: - if(Rs1 <= 0) Rd = val2; - break; - case 3: - if(Rs1 = 0) Rd = val2; - break; - case 5: - if(Rs1 != 0) Rd = val2; - break; - case 6: - if(Rs1 > 0) Rd = val2; - break; - case 7: - if(Rs1 >= 0) Rd = val2; - break; - } - }});//MOVR - 0x30: decode RD { - 0x0: wry({{ - uint64_t val2 = (I ? SIMM13.sdw : Rs2.sdw); - xc->regs.MiscRegs.y = Rs1 ^ val2; - }});//WRY - 0x2: wrccr({{ - uint64_t val2 = (I ? SIMM13.sdw : Rs2.sdw); - xc->regs.MiscRegs.ccr = Rs1 ^ val2; - }});//WRCCR - 0x3: wrasi({{ - uint64_t val2 = (I ? SIMM13.sdw : Rs2.sdw); - xc->regs.MiscRegs.asi = Rs1 ^ val2; - }});//WRASI - 0x6: wrfprs({{ - uint64_t val2 = (I ? SIMM13.sdw : Rs2.sdw); - xc->regs.MiscRegs.asi = Rs1 ^ val2; - }});//WRFPRS - 0xF: Trap::sir({{software_initiated_reset}}); //SIR - } - 0x31: decode FCN { - 0x0: BasicOperate::saved({{\\Boogy Boogy}}); //SAVED - 0x1: BasicOperate::restored({{\\Boogy Boogy}}); //RESTORED - } - 0x32: decode RD { - 0x0: wrprtpc({{checkPriv - uint64_t val2 = (I ? SIMM13.sdw : Rs2.sdw); - xc->regs.MiscRegs.tpc[xc->regs.MiscRegs.tl] = Rs1 ^ val2; - }}); - 0x1: wrprtnpc({{checkPriv - uint64_t val2 = (I ? SIMM13.sdw : Rs2.sdw); - xc->regs.MiscRegs.tnpc[xc->regs.MiscRegs.tl] = Rs1 ^ val2; - }}); - 0x2: wrprtstate({{checkPriv - uint64_t val2 = (I ? SIMM13.sdw : Rs2.sdw); - xc->regs.MiscRegs.tstate[xc->regs.MiscRegs.tl] = Rs1 ^ val2; - }}); - 0x3: wrprtt({{checkPriv - uint64_t val2 = (I ? SIMM13.sdw : Rs2.sdw); - xc->regs.MiscRegs.tt[xc->regs.MiscRegs.tl] = Rs1 ^ val2; - }}); - 0x4: wrprtick({{checkPriv - uint64_t val2 = (I ? SIMM13.sdw : Rs2.sdw); - xc->regs.MiscRegs.tick = Rs1 ^ val2; - }}); - 0x5: wrprtba({{checkPriv - uint64_t val2 = (I ? SIMM13.sdw : Rs2.sdw); - xc->regs.MiscRegs.tba = Rs1 ^ val2; - }}); - 0x6: wrprpstate({{checkPriv - uint64_t val2 = (I ? SIMM13.sdw : Rs2.sdw); - xc->regs.MiscRegs.pstate = Rs1 ^ val2; - }}); - 0x7: wrprtl({{checkPriv - uint64_t val2 = (I ? SIMM13.sdw : Rs2.sdw); - xc->regs.MiscRegs.tl = Rs1 ^ val2; - }}); - 0x8: wrprpil({{checkPriv - uint64_t val2 = (I ? SIMM13.sdw : Rs2.sdw); - xc->regs.MiscRegs.pil = Rs1 ^ val2; - }}); - 0x9: wrprcwp({{checkPriv - uint64_t val2 = (I ? SIMM13.sdw : Rs2.sdw); - xc->regs.MiscRegs.cwp = Rs1 ^ val2; - }}); - 0xA: wrprcansave({{checkPriv - uint64_t val2 = (I ? SIMM13.sdw : Rs2.sdw); - xc->regs.MiscRegs.cansave = Rs1 ^ val2; - }}); - 0xB: wrprcanrestore({{checkPriv - uint64_t val2 = (I ? SIMM13.sdw : Rs2.sdw); - xc->regs.MiscRegs.canrestore = Rs1 ^ val2; - }}); - 0xC: wrprcleanwin({{checkPriv - uint64_t val2 = (I ? SIMM13.sdw : Rs2.sdw); - xc->regs.MiscRegs.cleanwin = Rs1 ^ val2; - }}); - 0xD: wrprotherwin({{checkPriv - uint64_t val2 = (I ? SIMM13.sdw : Rs2.sdw); - xc->regs.MiscRegs.otherwin = Rs1 ^ val2; - }}); - 0xE: wrprwstate({{checkPriv - uint64_t val2 = (I ? SIMM13.sdw : Rs2.sdw); - xc->regs.MiscRegs.wstate = Rs1 ^ val2; - }}); - } - - 0x34: Trap::fpop1({{Throw fp_disabled;}}); //FPOP1 - 0x35: Trap::fpop2({{Throw fp_disabled;}}); //FPOP2 - - - 0x38: Branch::jmpl({{//Stuff}}); //JMPL - 0x39: Branch::return({{//Other Stuff}}); //RETURN - 0x3A: Trap::tcc({{ - switch((CC14 << 1) | (CC04 << 0)) - { - case 1: case 3: - throw illegal_instruction; - case 0: - if(passesCondition(xc->regs.MiscRegs.ccrFields.icc, machInst<25:28>)) - throw trap_instruction; - break; - case 2: - if(passesCondition(xc->regs.MiscRegs.ccrFields.xcc, machInst<25:28>)) - throw trap_instruction; - break; - } - }}); //Tcc - 0x3B: BasicOperate::flush({{//Lala}}); //FLUSH - 0x3C: BasicOperate::save({{//leprechauns); //SAVE - 0x3D: BasicOperate::restore({{//Eat my short int}}); //RESTORE - 0x3E: decode FCN { - 0x1: BasicOperate::done({{//Done thing}}); //DONE - 0x2: BasicOperate::retry({{//Retry thing}}); //RETRY - } - } - } - 0x3: decode OP3 { - format Mem { - 0x00: lduw({{Rd.uw = Mem.uw;}}); //LDUW - 0x01: ldub({{Rd.ub = Mem.ub;}}); //LDUB - 0x02: lduh({{Rd.uhw = Mem.uhw;}}); //LDUH - 0x03: ldd({{ - uint64_t val = Mem.udw; - setIntReg(RD & (~1), val<31:0>); - setIntReg(RD | 1, val<63:32>); - }});//LDD - 0x04: stw({{Mem.sw = Rd.sw;}}); //STW - 0x05: stb({{Mem.sb = Rd.sb;}}); //STB - 0x06: sth({{Mem.shw = Rd.shw;}}); //STH - 0x07: std({{ - Mem.udw = readIntReg(RD & (~1))<31:0> | (readIntReg(RD | 1)<31:0> << 32); - }});//STD - 0x08: ldsw({{Rd.sw = Mem.sw;}}); //LDSW - 0x09: ldsb({{Rd.sb = Mem.sb;}}); //LDSB - 0x0A: ldsh({{Rd.shw = Mem.shw;}}); //LDSH - 0x0B: ldx({{Rd.udw = Mem.udw;}}); //LDX - - 0x0D: ldstub({{ - Rd.ub = Mem.ub; - Mem.ub = 0xFF; - }}); //LDSTUB - 0x0E: stx({{Rd.udw = Mem.udw;}}); //STX - 0x0F: swap({{ - uint32_t temp = Rd.uw; - Rd.uw = Mem.uw; - Mem.uw = temp; - }}); //SWAP - 0x10: lduwa({{Rd.uw = Mem.uw;}}); //LDUWA - 0x11: lduba({{Rd.ub = Mem.ub;}}); //LDUBA - 0x12: lduha({{Rd.uhw = Mem.uhw;}}); //LDUHA - 0x13: ldda({{ - uint64_t val = Mem.udw; - setIntReg(RD & (~1), val<31:0>); - setIntReg(RD | 1, val<63:32>); - }}); //LDDA - 0x14: stwa({{Mem.uw = Rd.uw;}}); //STWA - 0x15: stba({{Mem.ub = Rd.ub;}}); //STBA - 0x16: stha({{Mem.uhw = Rd.uhw;}}); //STHA - 0x17: stda({{ - Mem.udw = readIntReg(RD & (~1))<31:0> | (readIntReg(RD | 1)<31:0> << 32); - }}); //STDA - 0x18: ldswa({{Rd.sw = Mem.sw;}}); //LDSWA - 0x19: ldsba({{Rd.sb = Mem.sb;}}); //LDSBA - 0x1A: ldsha({{Rd.shw = Mem.shw;}}); //LDSHA - 0x1B: ldxa({{Rd.sdw = Mem.sdw;}}); //LDXA - - 0x1D: ldstuba({{ - Rd.ub = Mem.ub; - Mem.ub = 0xFF; - }}); //LDSTUBA - 0x1E: stxa({{Mem.sdw = Rd.sdw}}); //STXA - 0x1F: swapa({{ - uint32_t temp = Rd.uw; - Rd.uw = Mem.uw; - Mem.uw = temp; - }}); //SWAPA - 0x20: Trap::ldf({{throw fp_disabled;}}); //LDF - 0x21: decode X { - 0x0: Trap::ldfsr({{throw fp_disabled;}}); //LDFSR - 0x1: Trap::ldxfsr({{throw fp_disabled;}}); //LDXFSR - } - 0x22: Trap::ldqf({{throw fp_disabled;}}); //LDQF - 0x23: Trap::lddf({{throw fp_disabled;}}); //LDDF - 0x24: Trap::stf({{throw fp_disabled;}}); //STF - 0x25: decode X { - 0x0: Trap::stfsr({{throw fp_disabled;}}); //STFSR - 0x1: Trap::stxfsr({{throw fp_disabled;}}); //STXFSR - } - 0x26: Trap::stqf({{throw fp_disabled;}}); //STQF - 0x27: Trap::stdf({{throw fp_disabled;}}); //STDF - - - - - - 0x2D: Noop::prefetch({{ }}); //PREFETCH - - - 0x30: Trap::ldfa({{throw fp_disabled;}}); //LDFA - - 0x32: Trap::ldqfa({{throw fp_disabled;}}); //LDQFA - 0x33: Trap::lddfa({{throw fp_disabled;}}); //LDDFA - 0x34: Trap::stfa({{throw fp_disabled;}}); //STFA - 0x35: Trap::stqfa({{throw fp_disabled;}}); //STQFA - 0x36: Trap::stdfa({{throw fp_disabled;}}); //STDFA - - - - - - 0x3C: Cas::casa( - {{uint64_t val = Mem.uw; - if(Rs2.uw == val) - Mem.uw = Rd.uw; - Rd.uw = val; - }}); //CASA - 0x3D: Noop::prefetcha({{ }}); //PREFETCHA - 0x3E: Cas::casxa( - {{uint64_t val = Mem.udw; - if(Rs2 == val) - Mem.udw = Rd; - Rd = val; - }}); //CASXA - } - } -} diff --git a/arch/sparc/isa/formats.isa b/arch/sparc/isa/formats.isa deleted file mode 100644 index 547f8be48..000000000 --- a/arch/sparc/isa/formats.isa +++ /dev/null @@ -1,19 +0,0 @@ -//Include the basic format -//Templates from this format are used later -##include "m5/arch/sparc/isa/formats/basic.isa" - -//Include the integerOp and integerOpCc format -##include "m5/arch/sparc/isa/formats/integerop.isa" - -//Include the mem format -##include "m5/arch/sparc/isa/formats/mem.isa" - -//Include the trap format -##include "m5/arch/sparc/isa/formats/trap.isa" - -//Include the branch format -##include "m5/arch/sparc/isa/formats/branch.isa" - -//Include the noop format -##include "m5/arch/sparc/isa/formats/noop.isa" - diff --git a/arch/sparc/isa/formats/basic.isa b/arch/sparc/isa/formats/basic.isa deleted file mode 100644 index 73df7617d..000000000 --- a/arch/sparc/isa/formats/basic.isa +++ /dev/null @@ -1,68 +0,0 @@ - -// Declarations for execute() methods. -def template BasicExecDeclare {{ - Fault execute(%(CPU_exec_context)s *, Trace::InstRecord *) const; -}}; - -// Basic instruction class declaration template. -def template BasicDeclare {{ - /** - * Static instruction class for "%(mnemonic)s". - */ - class %(class_name)s : public %(base_class)s - { - public: - // Constructor. - %(class_name)s(MachInst machInst); - %(BasicExecDeclare)s - }; -}}; - -// Basic instruction class constructor template. -def template BasicConstructor {{ - inline %(class_name)s::%(class_name)s(MachInst machInst) - : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s) - { - %(constructor)s; - } -}}; - -// Basic instruction class execute method template. -def template BasicExecute {{ - Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Fault fault = NoFault; - - %(fp_enable_check)s; - %(op_decl)s; - %(op_rd)s; - %(code)s; - - if(fault == NoFault) - { - %(op_wb)s; - } - return fault; - } -}}; - -// Basic decode template. -def template BasicDecode {{ - return new %(class_name)s(machInst); -}}; - -// Basic decode template, passing mnemonic in as string arg to constructor. -def template BasicDecodeWithMnemonic {{ - return new %(class_name)s("%(mnemonic)s", machInst); -}}; - -// The most basic instruction format... used only for a few misc. insts -def format BasicOperate(code, *flags) {{ - iop = InstObjParams(name, Name, 'SparcStaticInst', - CodeBlock(code), flags) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = BasicDecode.subst(iop) - exec_output = BasicExecute.subst(iop) -}}; diff --git a/arch/sparc/isa/formats/branch.isa b/arch/sparc/isa/formats/branch.isa deleted file mode 100644 index 80101de1b..000000000 --- a/arch/sparc/isa/formats/branch.isa +++ /dev/null @@ -1,62 +0,0 @@ -//////////////////////////////////////////////////////////////////// -// -// Branch instructions -// - -output header {{ - /** - * Base class for integer operations. - */ - class Branch : public SparcStaticInst - { - protected: - // Constructor - Branch(const char *mnem, MachInst _machInst, OpClass __opClass) : - SparcStaticInst(mnem, _machInst, __opClass) - { - } - - std::string generateDisassembly(Addr pc, - const SymbolTable *symtab) const; - }; -}}; - -output decoder {{ - std::string Branch::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { - return "Branch instruction\n"; - } -}}; - -def template BranchExecute {{ - Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - //Attempt to execute the instruction - Fault fault = NoFault; - checkPriv; - - %(op_decl)s; - %(op_rd)s; - %(code)s; - - if(fault == NoFault) - { - //Write the resulting state to the execution context - %(op_wb)s; - } - - return fault; - } -}}; - -// Primary format for integer operate instructions: -def format Branch(code, *opt_flags) {{ - orig_code = code - cblk = CodeBlock(code) - iop = InstObjParams(name, Name, 'SparcStaticInst', cblk, opt_flags) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = BasicDecodeWithMnemonic.subst(iop) - exec_output = BranchExecute.subst(iop) -}}; diff --git a/arch/sparc/isa/formats/integerop.isa b/arch/sparc/isa/formats/integerop.isa deleted file mode 100644 index 5a9e09896..000000000 --- a/arch/sparc/isa/formats/integerop.isa +++ /dev/null @@ -1,112 +0,0 @@ -//////////////////////////////////////////////////////////////////// -// -// Integer operate instructions -// - -output header {{ - /** - * Base class for integer operations. - */ - class IntegerOp : public SparcStaticInst - { - protected: - // Constructor - IntegerOp(const char *mnem, MachInst _machInst, OpClass __opClass) : - SparcStaticInst(mnem, _machInst, __opClass) - { - } - - std::string generateDisassembly(Addr pc, - const SymbolTable *symtab) const; - }; -}}; - -output decoder {{ - std::string IntegerOp::generateDisassembly(Addr pc, - const SymbolTable *symtab) const - { - return "Integer instruction\n"; - } -}}; - -def template IntegerExecute {{ - Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, Trace::InstRecord *traceData) const - { - //These are set to constants when the execute method - //is generated - bool useCc = ; - bool checkPriv = ; - - //Attempt to execute the instruction - try - { - checkPriv; - - %(op_decl)s; - %(op_rd)s; - %(code)s; - } - //If we have an exception for some reason, - //deal with it - catch(SparcException except) - { - //Deal with exception - return No_Fault; - } - - //Write the resulting state to the execution context - %(op_wb)s; - if(useCc) - { - xc->regs.miscRegFile.ccrFields.iccFields.n = Rd & (1 << 63); - xc->regs.miscRegFile.ccrFields.iccFields.z = (Rd == 0); - xc->regs.miscRegFile.ccrFields.iccFields.v = ivValue; - xc->regs.miscRegFile.ccrFields.iccFields.c = icValue; - xc->regs.miscRegFile.ccrFields.xccFields.n = Rd & (1 << 31); - xc->regs.miscRegFile.ccrFields.xccFields.z = ((Rd & 0xFFFFFFFF) == 0); - xc->regs.miscRegFile.ccrFields.xccFields.v = xvValue; - xc->regs.miscRegFile.ccrFields.xccFields.c = xcValue; - } - return No_Fault; - } -}}; - -// Primary format for integer operate instructions: -def format IntegerOp(code, *opt_flags) {{ - orig_code = code - cblk = CodeBlock(code) - checkPriv = (code.find('checkPriv') != -1) - code.replace('checkPriv', '') - if checkPriv: - code.replace('checkPriv;', 'if(!xc->regs.miscRegFile.pstateFields.priv) throw privileged_opcode;') - else: - code.replace('checkPriv;', '') - for (marker, value) in (('ivValue', '0'), ('icValue', '0'), - ('xvValue', '0'), ('xcValue', '0')): - code.replace(marker, value) - iop = InstObjParams(name, Name, 'SparcStaticInst', cblk, opt_flags) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = BasicDecodeWithMnemonic.subst(iop) - exec_output = IntegerExecute.subst(iop) -}}; - -// Primary format for integer operate instructions: -def format IntegerOpCc(code, icValue, ivValue, xcValue, xvValue, *opt_flags) {{ - orig_code = code - cblk = CodeBlock(code) - checkPriv = (code.find('checkPriv') != -1) - code.replace('checkPriv', '') - if checkPriv: - code.replace('checkPriv;', 'if(!xc->regs.miscRegFile.pstateFields.priv) throw privileged_opcode;') - else: - code.replace('checkPriv;', '') - for (marker, value) in (('ivValue', ivValue), ('icValue', icValue), - ('xvValue', xvValue), ('xcValue', xcValue)): - code.replace(marker, value) - iop = InstObjParams(name, Name, 'SparcStaticInst', cblk, opt_flags) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = BasicDecodeWithMnemonic.subst(iop) - exec_output = IntegerExecute.subst(iop) -}}; diff --git a/arch/sparc/isa/formats/mem.isa b/arch/sparc/isa/formats/mem.isa deleted file mode 100644 index d72de47d0..000000000 --- a/arch/sparc/isa/formats/mem.isa +++ /dev/null @@ -1,73 +0,0 @@ -//////////////////////////////////////////////////////////////////// -// -// Mem instructions -// - -output header {{ - /** - * Base class for integer operations. - */ - class Mem : public SparcStaticInst - { - protected: - - // Constructor - Mem(const char *mnem, MachInst _machInst, OpClass __opClass) : - SparcStaticInst(mnem, _machInst, __opClass) - { - } - - std::string generateDisassembly(Addr pc, - const SymbolTable *symtab) const; - }; -}}; - -output decoder {{ - std::string Mem::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { - return "Memory instruction\n"; - } -}}; - -def template MemExecute {{ - Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Fault fault = NoFault; - %(op_decl)s; - %(op_rd)s; - ea_code - %(code)s; - - if(fault == NoFault) - { - //Write the resulting state to the execution context - %(op_wb)s; - } - - return fault; - } -}}; - -// Primary format for integer operate instructions: -def format Mem(code, *opt_flags) {{ - orig_code = code - cblk = CodeBlock(code) - iop = InstObjParams(name, Name, 'SparcStaticInst', cblk, opt_flags) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = BasicDecodeWithMnemonic.subst(iop) - exec_output = MemExecute.subst(iop) - exec_output.replace('ea_code', 'EA = I ? (R1 + SIMM13) : R1 + R2;'); -}}; - -def format Cas(code, *opt_flags) {{ - orig_code = code - cblk = CodeBlock(code) - iop = InstObjParams(name, Name, 'SparcStaticInst', cblk, opt_flags) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = BasicDecodeWithMnemonic.subst(iop) - exec_output = MemExecute.subst(iop) - exec_output.replace('ea_code', 'EA = R1;'); -}}; diff --git a/arch/sparc/isa/formats/noop.isa b/arch/sparc/isa/formats/noop.isa deleted file mode 100644 index fa4047f06..000000000 --- a/arch/sparc/isa/formats/noop.isa +++ /dev/null @@ -1,50 +0,0 @@ -//////////////////////////////////////////////////////////////////// -// -// Noop instruction -// - -output header {{ - /** - * Noop class. - */ - class Noop : public SparcStaticInst - { - protected: - // Constructor - Noop(const char *mnem, MachInst _machInst, OpClass __opClass) : - SparcStaticInst(mnem, _machInst, __opClass) - { - } - - std::string generateDisassembly(Addr pc, - const SymbolTable *symtab) const; - }; -}}; - -output decoder {{ - std::string Noop::generateDisassembly(Addr pc, - const SymbolTable *symtab) const - { - return "Noop\n"; - } -}}; - -def template NoopExecute {{ - Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - //Nothing to see here, move along - return NoFault; - } -}}; - -// Primary format for integer operate instructions: -def format Noop(code, *opt_flags) {{ - orig_code = code - cblk = CodeBlock(code) - iop = InstObjParams(name, Name, 'SparcStaticInst', cblk, opt_flags) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = BasicDecodeWithMnemonic.subst(iop) - exec_output = NoopExecute.subst(iop) -}}; diff --git a/arch/sparc/isa/formats/trap.isa b/arch/sparc/isa/formats/trap.isa deleted file mode 100644 index ff3aadf72..000000000 --- a/arch/sparc/isa/formats/trap.isa +++ /dev/null @@ -1,51 +0,0 @@ -//////////////////////////////////////////////////////////////////// -// -// Trap instructions -// - -output header {{ - /** - * Base class for integer operations. - */ - class Trap : public SparcStaticInst - { - protected: - - // Constructor - Trap(const char *mnem, MachInst _machInst, OpClass __opClass) : - SparcStaticInst(mnem, _machInst, __opClass) - { - } - - std::string generateDisassembly(Addr pc, - const SymbolTable *symtab) const; - }; -}}; - -output decoder {{ - std::string Trap::generateDisassembly(Addr pc, - const SymbolTable *symtab) const - { - return "Trap instruction\n"; - } -}}; - -def template TrapExecute {{ - Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - //TODO: set up a software fault and return it. - return NoFault; - } -}}; - -// Primary format for integer operate instructions: -def format Trap(code, *opt_flags) {{ - orig_code = code - cblk = CodeBlock(code) - iop = InstObjParams(name, Name, 'SparcStaticInst', cblk, opt_flags) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = BasicDecodeWithMnemonic.subst(iop) - exec_output = TrapExecute.subst(iop) -}}; diff --git a/arch/sparc/isa/includes.isa b/arch/sparc/isa/includes.isa deleted file mode 100644 index a99018b49..000000000 --- a/arch/sparc/isa/includes.isa +++ /dev/null @@ -1,43 +0,0 @@ -//////////////////////////////////////////////////////////////////// -// -// Output include file directives. -// - -output header {{ -#include <sstream> -#include <iostream> -#include <iomanip> - -#include "cpu/static_inst.hh" -#include "arch/sparc/faults.hh" -#include "mem/mem_req.hh" // some constructors use MemReq flags -#include "arch/sparc/isa_traits.hh" -}}; - -output decoder {{ -#include "base/cprintf.hh" -#include "base/loader/symtab.hh" -#include "cpu/exec_context.hh" // for Jump::branchTarget() - -#include <math.h> -#if defined(linux) -#include <fenv.h> -#endif - -using namespace SparcISA; -}}; - -output exec {{ -#include <math.h> -#if defined(linux) -#include <fenv.h> -#endif - -#ifdef FULL_SYSTEM -//#include "arch/alpha/pseudo_inst.hh" -#endif -#include "cpu/base.hh" -#include "cpu/exetrace.hh" -#include "sim/sim_exit.hh" -}}; - diff --git a/arch/sparc/isa/main.isa b/arch/sparc/isa/main.isa deleted file mode 100644 index ab0290d58..000000000 --- a/arch/sparc/isa/main.isa +++ /dev/null @@ -1,52 +0,0 @@ -// -*- mode:c++ -*- - -// Copyright (c) 2003-2005 The Regents of The University of Michigan -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer; -// redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution; -// neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -##include "m5/arch/sparc/isa/includes.isa" - -//////////////////////////////////////////////////////////////////// -// -// Namespace statement. Everything below this line will be in the -// SparcISAInst namespace. -// - -namespace SparcISA; - -//Include the bitfield definitions -##include "m5/arch/sparc/isa/bitfields.isa" - -//Include the operand_types and operand definitions -##include "m5/arch/sparc/isa/operands.isa" - -//Include the base class for sparc instructions, and some support code -##include "m5/arch/sparc/isa/base.isa" - -//Include the definitions for the instruction formats -##include "m5/arch/sparc/isa/formats.isa" - -//Include the decoder definition -##include "m5/arch/sparc/isa/decoder.isa" diff --git a/arch/sparc/isa/operands.isa b/arch/sparc/isa/operands.isa deleted file mode 100644 index 64f5abd08..000000000 --- a/arch/sparc/isa/operands.isa +++ /dev/null @@ -1,31 +0,0 @@ -def operand_types {{ - 'sb' : ('signed int', 8), - 'ub' : ('unsigned int', 8), - 'shw' : ('signed int', 16), - 'uhw' : ('unsigned int', 16), - 'sw' : ('signed int', 32), - 'uw' : ('unsigned int', 32), - 'sdw' : ('signed int', 64), - 'udw' : ('unsigned int', 64), - 'sf' : ('float', 32), - 'df' : ('float', 64), - 'qf' : ('float', 128) -}}; - -def operands {{ - # Int regs default to unsigned, but code should not count on this. - # For clarity, descriptions that depend on unsigned behavior should - # explicitly specify '.uq'. - 'Rd': ('IntReg', 'udw', 'RD', 'IsInteger', 1), - 'Rs1': ('IntReg', 'udw', 'RS1', 'IsInteger', 2), - 'Rs2': ('IntReg', 'udw', 'RS2', 'IsInteger', 3), - #'Fa': ('FloatReg', 'df', 'FA', 'IsFloating', 1), - #'Fb': ('FloatReg', 'df', 'FB', 'IsFloating', 2), - #'Fc': ('FloatReg', 'df', 'FC', 'IsFloating', 3), - 'Mem': ('Mem', 'udw', None, ('IsMemRef', 'IsLoad', 'IsStore'), 4), - #'NPC': ('NPC', 'uq', None, ( None, None, 'IsControl' ), 4), - #'Runiq': ('ControlReg', 'uq', 'Uniq', None, 1), - #'FPCR': ('ControlReg', 'uq', 'Fpcr', None, 1), - 'R0': ('IntReg', 'udw', '0', None, 1), - 'R16': ('IntReg', 'udw', '16', None, 1) -}}; diff --git a/arch/sparc/isa_traits.hh b/arch/sparc/isa_traits.hh deleted file mode 100644 index bd3c35beb..000000000 --- a/arch/sparc/isa_traits.hh +++ /dev/null @@ -1,527 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __ARCH_SPARC_ISA_TRAITS_HH__ -#define __ARCH_SPARC_ISA_TRAITS_HH__ - -#include "arch/sparc/faults.hh" -#include "base/misc.hh" -#include "config/full_system.hh" -#include "sim/host.hh" - -//This makes sure the big endian versions of certain functions are used. -namespace BigEndianGuest {} -using namespace BigEndianGuest; - -class ExecContext; -class FastCPU; -//class FullCPU; -class Checkpoint; - -#define TARGET_SPARC - -class StaticInst; -class StaticInstPtr; - -//namespace EV5 -//{ -// int DTB_ASN_ASN(uint64_t reg); -// int ITB_ASN_ASN(uint64_t reg); -//} - -namespace SparcISA -{ - typedef uint32_t MachInst; - typedef uint64_t ExtMachInst; - typedef uint8_t RegIndex; - - const int NumFloatRegs = 32; - const int NumMiscRegs = 32; - - const int // Maximum trap level - const int MaxTL = 4; - const int - const int // semantically meaningful register indices - const int ZeroReg = 0; // architecturally meaningful - const int // the rest of these depend on the ABI - const int StackPointerReg = 14; - const int ReturnAddressReg = 31; // post call, precall is 15 - const int ReturnValueReg = 8; // Post return, 24 is pre-return. - const int FramePointerReg = 30; - const int ArgumentReg0 = 8; - const int ArgumentReg1 = 9; - const int ArgumentReg2 = 10; - const int ArgumentReg3 = 11; - const int ArgumentReg4 = 12; - const int ArgumentReg5 = 13; - // Some OS syscall sue a second register (o1) to return a second value - const int SyscallPseudoReturnReg = ArgumentReg1; - - - //8K. This value is implmentation specific; and should probably - //be somewhere else. - const int LogVMPageSize = 13; - const int VMPageSize = (1 << LogVMPageSize); - - - - - - - - - - - - - - - - - - - - - - - - typedef uint64_t IntReg; - - class IntRegFile - { - private: - //For right now, let's pretend the register file is static - IntReg regs[32]; - public: - IntReg & operator [] (RegIndex index) - { - //Don't allow indexes outside of the 32 registers - index &= 0x1F; - return regs[index]; - } - }; - - void serialize(std::ostream & os); - - void unserialize(Checkpoint *cp, const std::string §ion); - - typedef float float32_t; - typedef double float64_t; - //FIXME This actually usually refers to a 10 byte float, rather than a - //16 byte float as required. This data type may have to be emulated. - typedef long double float128_t; - - class FloatRegFile - { - private: - //By using the largest data type, we ensure everything - //is aligned correctly in memory - union - { - float128_t rawRegs[16]; - uint64_t regDump[32]; - }; - class QuadRegs - { - private: - FloatRegFile * parent; - public: - QuadRegs(FloatRegFile * p) : parent(p) {;} - float128_t & operator [] (RegIndex index) - { - //Quad floats are index by the single - //precision register the start on, - //and only 16 should be accessed - index = (index >> 2) & 0xF; - return parent->rawRegs[index]; - } - }; - class DoubleRegs - { - private: - FloatRegFile * parent; - public: - DoubleRegs(FloatRegFile * p) : parent(p) {;} - float64_t & operator [] (RegIndex index) - { - //Double floats are index by the single - //precision register the start on, - //and only 32 should be accessed - index = (index >> 1) & 0x1F; - return ((float64_t *)parent->rawRegs)[index]; - } - }; - class SingleRegs - { - private: - FloatRegFile * parent; - public: - SingleRegs(FloatRegFile * p) : parent(p) {;} - float32_t & operator [] (RegIndex index) - { - //Only 32 single floats should be accessed - index &= 0x1F; - return ((float32_t *)parent->rawRegs)[index]; - } - }; - public: - void serialize(std::ostream & os); - - void unserialize(Checkpoint * cp, std::string & section); - - QuadRegs quadRegs; - DoubleRegs doubleRegs; - SingleRegs singleRegs; - FloatRegFile() : quadRegs(this), doubleRegs(this), singleRegs(this) - {;} - }; - - // control register file contents - typedef uint64_t MiscReg; - // The control registers, broken out into fields - class MiscRegFile - { - private: - union - { - uint16_t pstate; // Process State Register - struct - { - uint16_t ag:1; // Alternate Globals - uint16_t ie:1; // Interrupt enable - uint16_t priv:1; // Privelege mode - uint16_t am:1; // Address mask - uint16_t pef:1; // PSTATE enable floating-point - uint16_t red:1; // RED (reset, error, debug) state - uint16_t mm:2; // Memory Model - uint16_t tle:1; // Trap little-endian - uint16_t cle:1; // Current little-endian - } pstateFields; - }; - uint64_t tba; // Trap Base Address - union - { - uint64_t y; // Y (used in obsolete multiplication) - struct - { - uint64_t value:32; // The actual value stored in y - uint64_t :32; // reserved bits - } yFields; - }; - uint8_t pil; // Process Interrupt Register - uint8_t cwp; // Current Window Pointer - uint16_t tt[MaxTL]; // Trap Type (Type of trap which occured - // on the previous level) - union - { - uint8_t ccr; // Condition Code Register - struct - { - union - { - uint8_t icc:4; // 32-bit condition codes - struct - { - uint8_t c:1; // Carry - uint8_t v:1; // Overflow - uint8_t z:1; // Zero - uint8_t n:1; // Negative - } iccFields; - }; - union - { - uint8_t xcc:4; // 64-bit condition codes - struct - { - uint8_t c:1; // Carry - uint8_t v:1; // Overflow - uint8_t z:1; // Zero - uint8_t n:1; // Negative - } xccFields; - }; - } ccrFields; - }; - uint8_t asi; // Address Space Identifier - uint8_t tl; // Trap Level - uint64_t tpc[MaxTL]; // Trap Program Counter (value from - // previous trap level) - uint64_t tnpc[MaxTL]; // Trap Next Program Counter (value from - // previous trap level) - union - { - uint64_t tstate[MaxTL]; // Trap State - struct - { - //Values are from previous trap level - uint64_t cwp:5; // Current Window Pointer - uint64_t :2; // Reserved bits - uint64_t pstate:10; // Process State - uint64_t :6; // Reserved bits - uint64_t asi:8; // Address Space Identifier - uint64_t ccr:8; // Condition Code Register - } tstateFields[MaxTL]; - }; - union - { - uint64_t tick; // Hardware clock-tick counter - struct - { - uint64_t counter:63; // Clock-tick count - uint64_t npt:1; // Non-priveleged trap - } tickFields; - }; - uint8_t cansave; // Savable windows - uint8_t canrestore; // Restorable windows - uint8_t otherwin; // Other windows - uint8_t cleanwin; // Clean windows - union - { - uint8_t wstate; // Window State - struct - { - uint8_t normal:3; // Bits TT<4:2> are set to on a normal - // register window trap - uint8_t other:3; // Bits TT<4:2> are set to on an "otherwin" - // register window trap - } wstateFields; - }; - union - { - uint64_t ver; // Version - struct - { - uint64_t maxwin:5; // Max CWP value - uint64_t :2; // Reserved bits - uint64_t maxtl:8; // Maximum trap level - uint64_t :8; // Reserved bits - uint64_t mask:8; // Processor mask set revision number - uint64_t impl:16; // Implementation identification number - uint64_t manuf:16; // Manufacturer code - } verFields; - }; - union - { - uint64_t fsr; // Floating-Point State Register - struct - { - union - { - uint64_t cexc:5; // Current excpetion - struct - { - uint64_t nxc:1; // Inexact - uint64_t dzc:1; // Divide by zero - uint64_t ufc:1; // Underflow - uint64_t ofc:1; // Overflow - uint64_t nvc:1; // Invalid operand - } cexecFields; - }; - union - { - uint64_t aexc:5; // Accrued exception - struct - { - uint64_t nxc:1; // Inexact - uint64_t dzc:1; // Divide by zero - uint64_t ufc:1; // Underflow - uint64_t ofc:1; // Overflow - uint64_t nvc:1; // Invalid operand - } aexecFields; - }; - uint64_t fcc0:2; // Floating-Point condtion codes - uint64_t :1; // Reserved bits - uint64_t qne:1; // Deferred trap queue not empty - // with no queue, it should read 0 - uint64_t ftt:3; // Floating-Point trap type - uint64_t ver:3; // Version (of the FPU) - uint64_t :2; // Reserved bits - uint64_t ns:1; // Nonstandard floating point - union - { - uint64_t tem:5; // Trap Enable Mask - struct - { - uint64_t nxm:1; // Inexact - uint64_t dzm:1; // Divide by zero - uint64_t ufm:1; // Underflow - uint64_t ofm:1; // Overflow - uint64_t nvm:1; // Invalid operand - } temFields; - }; - uint64_t :2; // Reserved bits - uint64_t rd:2; // Rounding direction - uint64_t fcc1:2; // Floating-Point condition codes - uint64_t fcc2:2; // Floating-Point condition codes - uint64_t fcc3:2; // Floating-Point condition codes - uint64_t :26; // Reserved bits - } fsrFields; - }; - union - { - uint8_t fprs; // Floating-Point Register State - struct - { - uint8_t dl:1; // Dirty lower - uint8_t du:1; // Dirty upper - uint8_t fef:1; // FPRS enable floating-Point - } fprsFields; - }; - - public: - MiscReg readReg(int misc_reg); - - MiscReg readRegWithEffect(int misc_reg, Fault &fault, ExecContext *xc); - - Fault setReg(int misc_reg, const MiscReg &val); - - Fault setRegWithEffect(int misc_reg, const MiscReg &val, - ExecContext *xc); - - void serialize(std::ostream & os); - - void unserialize(Checkpoint * cp, std::string & section); - }; - - typedef union - { - float32_t singReg; - float64_t doubReg; - float128_t quadReg; - } FloatReg; - - typedef union - { - IntReg intreg; - FloatReg fpreg; - MiscReg ctrlreg; - } AnyReg; - - struct RegFile - { - IntRegFile intRegFile; // (signed) integer register file - FloatRegFile floatRegFile; // floating point register file - MiscRegFile miscRegFile; // control register file - - Addr pc; // Program Counter - Addr npc; // Next Program Counter - Addr nnpc; - - void serialize(std::ostream &os); - void unserialize(Checkpoint *cp, const std::string §ion); - }; - - StaticInstPtr decodeInst(MachInst); - - // return a no-op instruction... used for instruction fetch faults - extern const MachInst NoopMachInst; - - // Instruction address compression hooks - inline Addr realPCToFetchPC(const Addr &addr) - { - return addr; - } - - inline Addr fetchPCToRealPC(const Addr &addr) - { - return addr; - } - - // the size of "fetched" instructions (not necessarily the size - // of real instructions for PISA) - inline size_t fetchInstSize() - { - return sizeof(MachInst); - } - - /** - * Function to insure ISA semantics about 0 registers. - * @param xc The execution context. - */ - template <class XC> - - static inline setSyscallReturn(SyscallReturn return_value, RegFile *regs) - { - // check for error condition. SPARC syscall convention is to - // indicate success/failure in reg the carry bit of the ccr - // and put the return value itself in the standard return value reg (). - if (return_value.successful()) { - // no error - regs->miscRegFile.ccrFields.iccFields.c = 0; - regs->intRegFile[ReturnValueReg] = return_value.value(); - } else { - // got an error, return details - regs->miscRegFile.ccrFields.iccFields.c = 1; - regs->intRegFile[ReturnValueReg] = -return_value.value(); - } - } -}; - -#if !FULL_SYSTEM -class SyscallReturn -{ - public: - template <class T> - SyscallReturn(T v, bool s) - { - retval = (uint64_t)v; - success = s; - } - - template <class T> - SyscallReturn(T v) - { - success = (v >= 0); - retval = (uint64_t)v; - } - - ~SyscallReturn() {} - - SyscallReturn& operator=(const SyscallReturn& s) - { - retval = s.retval; - success = s.success; - return *this; - } - - bool successful() { return success; } - uint64_t value() { return retval; } - - private: - uint64_t retval; - bool success; -}; - -#endif - - -#if FULL_SYSTEM - -#include "arch/alpha/ev5.hh" -#endif - -#endif // __ARCH_SPARC_ISA_TRAITS_HH__ diff --git a/arch/sparc/linux/process.cc b/arch/sparc/linux/process.cc deleted file mode 100644 index fa2a7b9f5..000000000 --- a/arch/sparc/linux/process.cc +++ /dev/null @@ -1,374 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "arch/sparc/common_syscall_emul.hh" -#include "arch/sparc/linux/process.hh" -#include "arch/sparc/isa_traits.hh" - -#include "base/trace.hh" -#include "cpu/exec_context.hh" -#include "kern/linux/linux.hh" -#include "mem/functional/functional.hh" - -#include "sim/process.hh" -#include "sim/syscall_emul.hh" - -using namespace std; -using namespace SparcISA; - - -/// Target uname() handler. -static SyscallReturn -unameFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - TypedBufferArg<Linux::utsname> name(xc->getSyscallArg(0)); - - strcpy(name->sysname, "Linux"); - strcpy(name->nodename, "m5.eecs.umich.edu"); - strcpy(name->release, "2.4.20"); - strcpy(name->version, "#1 Mon Aug 18 11:32:15 EDT 2003"); - strcpy(name->machine, "sparc"); - - name.copyOut(xc->mem); - return 0; -} - -SyscallDesc SparcLinuxProcess::syscallDescs[] = { - /* 0 */ SyscallDesc("restart_syscall", unimplementedFunc); - /* 1 */ SyscallDesc("exit", exitFunc); - /* 2 */ SyscallDesc("fork", unimplementedFunc); - /* 3 */ SyscallDesc("read", readFunc); - /* 4 */ SyscallDesc("write", writeFunc); - /* 5 */ SyscallDesc("open", openFunc<Linux>); - /* 6 */ SyscallDesc("close", closeFinc); - /* 7 */ SyscallDesc("wait4", unimplementedFunc); - /* 8 */ SyscallDesc("creat", unimplementedFunc); - /* 9 */ SyscallDesc("link", unimplementedFunc); - /* 10 */ SyscallDesc("unlink", unlinkFunc); - /* 11 */ SyscallDesc("execv", unimplementedFunc); - /* 12 */ SyscallDesc("chdir", unimplementedFunc); - /* 13 */ SyscallDesc("chown", chownFunc); - /* 14 */ SyscallDesc("mknod", unimplementedFunc); - /* 15 */ SyscallDesc("chmod", chmodFunc<Linux>); - /* 16 */ SyscallDesc("lchown", unimplementedFunc); - /* 17 */ SyscallDesc("brk", obreakFunc); - /* 18 */ SyscallDesc("perfctr", unimplementedFunc); - /* 19 */ SyscallDesc("lseek", lseekFunc); - /* 20 */ SyscallDesc("getpid", getpidFunc); - /* 21 */ SyscallDesc("capget", unimplementedFunc); - /* 22 */ SyscallDesc("capset", unimplementedFunc); - /* 23 */ SyscallDesc("setuid", setuidFunc); - /* 24 */ SyscallDesc("getuid", getuidFunc); - /* 25 */ SyscallDesc("time", unimplementedFunc); - /* 26 */ SyscallDesc("ptrace", unimplementedFunc); - /* 27 */ SyscallDesc("alarm", unimplementedFunc); - /* 28 */ SyscallDesc("sigaltstack", unimplementedFunc); - /* 29 */ SyscallDesc("pause", unimplementedFunc); - /* 30 */ SyscallDesc("utime", unimplementedFunc); - /* 31 */ SyscallDesc("lchown32", unimplementedFunc); - /* 32 */ SyscallDesc("fchown32", unimplementedFunc); - /* 33 */ SyscallDesc("access", unimplementedFunc); - /* 34 */ SyscallDesc("nice", unimplementedFunc); - /* 35 */ SyscallDesc("chown32", unimplementedFunc); - /* 36 */ SyscallDesc("sync", unimplementedFunc); - /* 37 */ SyscallDesc("kill", unimplementedFunc); - /* 38 */ SyscallDesc("stat", unimplementedFunc); - /* 39 */ SyscallDesc("sendfile", unimplementedFunc); - /* 40 */ SyscallDesc("lstat", unimplementedFunc); - /* 41 */ SyscallDesc("dup", unimplementedFunc); - /* 42 */ SyscallDesc("pipe", pipePseudoFunc); - /* 43 */ SyscallDesc("times", unimplementedFunc); - /* 44 */ SyscallDesc("getuid32", unimplementedFunc); - /* 45 */ SyscallDesc("umount2", unimplementedFunc); - /* 46 */ SyscallDesc("setgid", unimplementedFunc); - /* 47 */ SyscallDesc("getgid", getgidFunc); - /* 48 */ SyscallDesc("signal", unimplementedFunc); - /* 49 */ SyscallDesc("geteuid", geteuidFunc); - /* 50 */ SyscallDesc("getegid", getegidFunc); - /* 51 */ SyscallDesc("acct", unimplementedFunc); - /* 52 */ SyscallDesc("memory_ordering", unimplementedFunc); - /* 53 */ SyscallDesc("getgid32", unimplementedFunc); - /* 54 */ SyscallDesc("ioctl", unimplementedFunc); - /* 55 */ SyscallDesc("reboot", unimplementedFunc); - /* 56 */ SyscallDesc("mmap2", unimplementedFunc); - /* 57 */ SyscallDesc("symlink", unimplementedFunc); - /* 58 */ SyscallDesc("readlink", unimplementedFunc); - /* 59 */ SyscallDesc("execve", unimplementedFunc); - /* 60 */ SyscallDesc("umask", unimplementedFunc); - /* 61 */ SyscallDesc("chroot", unimplementedFunc); - /* 62 */ SyscallDesc("fstat", unimplementedFunc); - /* 63 */ SyscallDesc("fstat64", unimplementedFunc); - /* 64 */ SyscallDesc("getpagesize", unimplementedFunc); - /* 65 */ SyscallDesc("msync", unimplementedFunc); - /* 66 */ SyscallDesc("vfork", unimplementedFunc); - /* 67 */ SyscallDesc("pread64", unimplementedFunc); - /* 68 */ SyscallDesc("pwrite64", unimplementedFunc); - /* 69 */ SyscallDesc("geteuid32", unimplementedFunc); - /* 70 */ SyscallDesc("getdgid32", unimplementedFunc); - /* 71 */ SyscallDesc("mmap", unimplementedFunc); - /* 72 */ SyscallDesc("setreuid32", unimplementedFunc); - /* 73 */ SyscallDesc("munmap", unimplementedFunc); - /* 74 */ SyscallDesc("mprotect", unimplementedFunc); - /* 75 */ SyscallDesc("madvise", unimplementedFunc); - /* 76 */ SyscallDesc("vhangup", unimplementedFunc); - /* 77 */ SyscallDesc("truncate64", unimplementedFunc); - /* 78 */ SyscallDesc("mincore", unimplementedFunc); - /* 79 */ SyscallDesc("getgroups", unimplementedFunc); - /* 80 */ SyscallDesc("setgroups", unimplementedFunc); - /* 81 */ SyscallDesc("getpgrp", unimplementedFunc); - /* 82 */ SyscallDesc("setgroups32", unimplementedFunc); - /* 83 */ SyscallDesc("setitimer", unimplementedFunc); - /* 84 */ SyscallDesc("ftruncate64", unimplementedFunc); - /* 85 */ SyscallDesc("swapon", unimplementedFunc); - /* 86 */ SyscallDesc("getitimer", unimplementedFunc); - /* 87 */ SyscallDesc("setuid32", unimplementedFunc); - /* 88 */ SyscallDesc("sethostname", unimplementedFunc); - /* 89 */ SyscallDesc("setgid32", unimplementedFunc); - /* 90 */ SyscallDesc("dup2", unimplementedFunc); - /* 91 */ SyscallDesc("setfsuid32", unimplementedFunc); - /* 92 */ SyscallDesc("fcntl", unimplementedFunc); - /* 93 */ SyscallDesc("select", unimplementedFunc); - /* 94 */ SyscallDesc("setfsgid32", unimplementedFunc); - /* 95 */ SyscallDesc("fsync", unimplementedFunc); - /* 96 */ SyscallDesc("setpriority", unimplementedFunc); - /* 97 */ SyscallDesc("socket", unimplementedFunc); - /* 98 */ SyscallDesc("connect", unimplementedFunc); - /* 99 */ SyscallDesc("accept", unimplementedFunc); - /* 100 */ SyscallDesc("getpriority", unimplementedFunc); - /* 101 */ SyscallDesc("rt_sigreturn", unimplementedFunc); - /* 102 */ SyscallDesc("rt_sigaction", unimplementedFunc); - /* 103 */ SyscallDesc("rt_sigprocmask", unimplementedFunc); - /* 104 */ SyscallDesc("rt_sigpending", unimplementedFunc); - /* 105 */ SyscallDesc("rt_sigtimedwait", unimplementedFunc); - /* 106 */ SyscallDesc("rt_sigqueueinfo", unimplementedFunc); - /* 107 */ SyscallDesc("rt_sigsuspend", unimplementedFunc); - /* 108 */ SyscallDesc("setresuid", unimplementedFunc); - /* 109 */ SyscallDesc("getresuid", unimplementedFunc); - /* 110 */ SyscallDesc("setresgid", unimplementedFunc); - /* 111 */ SyscallDesc("getresgid", unimplementedFunc); - /* 112 */ SyscallDesc("setregid32", unimplementedFunc); - /* 113 */ SyscallDesc("recvmsg", unimplementedFunc); - /* 114 */ SyscallDesc("sendmsg", unimplementedFunc); - /* 115 */ SyscallDesc("getgroups32", unimplementedFunc); - /* 116 */ SyscallDesc("gettimeofday", unimplementedFunc); - /* 117 */ SyscallDesc("getrusage", unimplementedFunc); - /* 118 */ SyscallDesc("getsockopt", unimplementedFunc); - /* 119 */ SyscallDesc("getcwd", unimplementedFunc); - /* 120 */ SyscallDesc("readv", unimplementedFunc); - /* 121 */ SyscallDesc("writev", unimplementedFunc); - /* 122 */ SyscallDesc("settimeofday", unimplementedFunc); - /* 123 */ SyscallDesc("fchown", unimplementedFunc); - /* 124 */ SyscallDesc("fchmod", unimplementedFunc); - /* 125 */ SyscallDesc("recvfrom", unimplementedFunc); - /* 126 */ SyscallDesc("setreuid", unimplementedFunc); - /* 127 */ SyscallDesc("setregid", unimplementedFunc); - /* 128 */ SyscallDesc("rename", unimplementedFunc); - /* 129 */ SyscallDesc("truncate", unimplementedFunc); - /* 130 */ SyscallDesc("ftruncate", unimplementedFunc); - /* 131 */ SyscallDesc("flock", unimplementedFunc); - /* 132 */ SyscallDesc("lstat64", unimplementedFunc); - /* 133 */ SyscallDesc("sendto", unimplementedFunc); - /* 134 */ SyscallDesc("shutdown", unimplementedFunc); - /* 135 */ SyscallDesc("socketpair", unimplementedFunc); - /* 136 */ SyscallDesc("mkdir", unimplementedFunc); - /* 137 */ SyscallDesc("rmdir", unimplementedFunc); - /* 138 */ SyscallDesc("utimes", unimplementedFunc); - /* 139 */ SyscallDesc("stat64", unimplementedFunc); - /* 140 */ SyscallDesc("sendfile64", unimplementedFunc); - /* 141 */ SyscallDesc("getpeername", unimplementedFunc); - /* 142 */ SyscallDesc("futex", unimplementedFunc); - /* 143 */ SyscallDesc("gettid", unimplementedFunc); - /* 144 */ SyscallDesc("getrlimit", unimplementedFunc); - /* 145 */ SyscallDesc("setrlimit", unimplementedFunc); - /* 146 */ SyscallDesc("pivot_root", unimplementedFunc); - /* 147 */ SyscallDesc("prctl", unimplementedFunc); - /* 148 */ SyscallDesc("pciconfig_read", unimplementedFunc); - /* 149 */ SyscallDesc("pciconfig_write", unimplementedFunc); - /* 150 */ SyscallDesc("getsockname", unimplementedFunc); - /* 151 */ SyscallDesc("inotify_init", unimplementedFunc); - /* 152 */ SyscallDesc("inotify_add_watch", unimplementedFunc); - /* 153 */ SyscallDesc("poll", unimplementedFunc); - /* 154 */ SyscallDesc("getdents64", unimplementedFunc); - /* 155 */ SyscallDesc("fcntl64", unimplementedFunc); - /* 156 */ SyscallDesc("inotify_rm_watch", unimplementedFunc); - /* 157 */ SyscallDesc("statfs", unimplementedFunc); - /* 158 */ SyscallDesc("fstatfs", unimplementedFunc); - /* 159 */ SyscallDesc("umount", unimplementedFunc); - /* 160 */ SyscallDesc("sched_set_affinity", unimplementedFunc); - /* 161 */ SyscallDesc("sched_get_affinity", unimplementedFunc); - /* 162 */ SyscallDesc("getdomainname", unimplementedFunc); - /* 163 */ SyscallDesc("setdomainname", unimplementedFunc); - /* 164 */ SyscallDesc("utrap_install", unimplementedFunc); - /* 165 */ SyscallDesc("quotactl", unimplementedFunc); - /* 166 */ SyscallDesc("set_tid_address", unimplementedFunc); - /* 167 */ SyscallDesc("mount", unimplementedFunc); - /* 168 */ SyscallDesc("ustat", unimplementedFunc); - /* 169 */ SyscallDesc("setxattr", unimplementedFunc); - /* 170 */ SyscallDesc("lsetxattr", unimplementedFunc); - /* 171 */ SyscallDesc("fsetxattr", unimplementedFunc); - /* 172 */ SyscallDesc("getxattr", unimplementedFunc); - /* 173 */ SyscallDesc("lgetxattr", unimplementedFunc); - /* 174 */ SyscallDesc("getdents", unimplementedFunc); - /* 175 */ SyscallDesc("setsid", unimplementedFunc); - /* 176 */ SyscallDesc("fchdir", unimplementedFunc); - /* 177 */ SyscallDesc("fgetxattr", unimplementedFunc); - /* 178 */ SyscallDesc("listxattr", unimplementedFunc); - /* 179 */ SyscallDesc("llistxattr", unimplementedFunc); - /* 180 */ SyscallDesc("flistxattr", unimplementedFunc); - /* 181 */ SyscallDesc("removexattr", unimplementedFunc); - /* 182 */ SyscallDesc("lremovexattr", unimplementedFunc); - /* 183 */ SyscallDesc("sigpending", unimplementedFunc); - /* 184 */ SyscallDesc("query_module", unimplementedFunc); - /* 185 */ SyscallDesc("setpgid", unimplementedFunc); - /* 186 */ SyscallDesc("fremovexattr", unimplementedFunc); - /* 187 */ SyscallDesc("tkill", unimplementedFunc); - /* 188 */ SyscallDesc("exit_group", unimplementedFunc); - /* 189 */ SyscallDesc("uname", unameFunc); - /* 190 */ SyscallDesc("init_module", unimplementedFunc); - /* 191 */ SyscallDesc("personality", unimplementedFunc); - /* 192 */ SyscallDesc("remap_file_pages", unimplementedFunc); - /* 193 */ SyscallDesc("epoll_create", unimplementedFunc); - /* 194 */ SyscallDesc("epoll_ctl", unimplementedFunc); - /* 195 */ SyscallDesc("epoll_wait", unimplementedFunc); - /* 196 */ SyscallDesc("ioprio_set", unimplementedFunc); - /* 197 */ SyscallDesc("getppid", getppidFunc); - /* 198 */ SyscallDesc("sigaction", unimplementedFunc); - /* 199 */ SyscallDesc("sgetmask", unimplementedFunc); - /* 200 */ SyscallDesc("ssetmask", unimplementedFunc); - /* 201 */ SyscallDesc("sigsuspend", unimplementedFunc); - /* 202 */ SyscallDesc("oldlstat", unimplementedFunc); - /* 203 */ SyscallDesc("uselib", unimplementedFunc); - /* 204 */ SyscallDesc("readdir", unimplementedFunc); - /* 205 */ SyscallDesc("readahead", unimplementedFunc); - /* 206 */ SyscallDesc("socketcall", unimplementedFunc); - /* 207 */ SyscallDesc("syslog", unimplementedFunc); - /* 208 */ SyscallDesc("lookup_dcookie", unimplementedFunc); - /* 209 */ SyscallDesc("fadvise64", unimplementedFunc); - /* 210 */ SyscallDesc("fadvise64_64", unimplementedFunc); - /* 211 */ SyscallDesc("tgkill", unimplementedFunc); - /* 212 */ SyscallDesc("waitpid", unimplementedFunc); - /* 213 */ SyscallDesc("swapoff", unimplementedFunc); - /* 214 */ SyscallDesc("sysinfo", unimplementedFunc); - /* 215 */ SyscallDesc("ipc", unimplementedFunc); - /* 216 */ SyscallDesc("sigreturn", unimplementedFunc); - /* 217 */ SyscallDesc("clone", unimplementedFunc); - /* 218 */ SyscallDesc("ioprio_get", unimplementedFunc); - /* 219 */ SyscallDesc("adjtimex", unimplementedFunc); - /* 220 */ SyscallDesc("sigprocmask", unimplementedFunc); - /* 221 */ SyscallDesc("create_module", unimplementedFunc); - /* 222 */ SyscallDesc("delete_module", unimplementedFunc); - /* 223 */ SyscallDesc("get_kernel_syms", unimplementedFunc); - /* 224 */ SyscallDesc("getpgid", unimplementedFunc); - /* 225 */ SyscallDesc("bdflush", unimplementedFunc); - /* 226 */ SyscallDesc("sysfs", unimplementedFunc); - /* 227 */ SyscallDesc("afs_syscall", unimplementedFunc); - /* 228 */ SyscallDesc("setfsuid", unimplementedFunc); - /* 229 */ SyscallDesc("setfsgid", unimplementedFunc); - /* 230 */ SyscallDesc("_newselect", unimplementedFunc); - /* 231 */ SyscallDesc("time", unimplementedFunc); - /* 232 */ SyscallDesc("oldstat", unimplementedFunc); - /* 233 */ SyscallDesc("stime", unimplementedFunc); - /* 234 */ SyscallDesc("statfs64", unimplementedFunc); - /* 235 */ SyscallDesc("fstatfs64", unimplementedFunc); - /* 236 */ SyscallDesc("_llseek", unimplementedFunc); - /* 237 */ SyscallDesc("mlock", unimplementedFunc); - /* 238 */ SyscallDesc("munlock", unimplementedFunc); - /* 239 */ SyscallDesc("mlockall", unimplementedFunc); - /* 240 */ SyscallDesc("munlockall", unimplementedFunc); - /* 241 */ SyscallDesc("sched_setparam", unimplementedFunc); - /* 242 */ SyscallDesc("sched_getparam", unimplementedFunc); - /* 243 */ SyscallDesc("sched_setscheduler", unimplementedFunc); - /* 244 */ SyscallDesc("sched_getscheduler", unimplementedFunc); - /* 245 */ SyscallDesc("sched_yield", unimplementedFunc); - /* 246 */ SyscallDesc("sched_get_priority_max", unimplimented); - /* 247 */ SyscallDesc("sched_get_priority_min", unimplimented); - /* 248 */ SyscallDesc("sched_rr_get_interval", unimplimented); - /* 249 */ SyscallDesc("nanosleep", unimplementedFunc); - /* 250 */ SyscallDesc("mremap", unimplementedFunc); - /* 251 */ SyscallDesc("_sysctl", unimplementedFunc); - /* 252 */ SyscallDesc("getsid", unimplementedFunc); - /* 253 */ SyscallDesc("fdatasync", unimplementedFunc); - /* 254 */ SyscallDesc("nfsservctl", unimplementedFunc); - /* 255 */ SyscallDesc("aplib", unimplementedFunc); - /* 256 */ SyscallDesc("clock_settime", unimplementedFunc); - /* 257 */ SyscallDesc("clock_gettime", unimplementedFunc); - /* 258 */ SyscallDesc("clock_getres", unimplementedFunc); - /* 259 */ SyscallDesc("clock_nanosleep", unimplementedFunc); - /* 260 */ SyscallDesc("sched_getaffinity", unimplementedFunc); - /* 261 */ SyscallDesc("sched_setaffinity", unimplementedFunc); - /* 262 */ SyscallDesc("timer_settime", unimplementedFunc); - /* 263 */ SyscallDesc("timer_gettime", unimplementedFunc); - /* 264 */ SyscallDesc("timer_getoverrun", unimplementedFunc); - /* 265 */ SyscallDesc("timer_delete", unimplementedFunc); - /* 266 */ SyscallDesc("timer_create", unimplementedFunc); - /* 267 */ SyscallDesc("vserver", unimplementedFunc); - /* 268 */ SyscallDesc("io_setup", unimplementedFunc); - /* 269 */ SyscallDesc("io_destroy", unimplementedFunc); - /* 270 */ SyscallDesc("io_submit", unimplementedFunc); - /* 271 */ SyscallDesc("io_cancel", unimplementedFunc); - /* 272 */ SyscallDesc("io_getevents", unimplementedFunc); - /* 273 */ SyscallDesc("mq_open", unimplementedFunc); - /* 274 */ SyscallDesc("mq_unlink", unimplementedFunc); - /* 275 */ SyscallDesc("mq_timedsend", unimplementedFunc); - /* 276 */ SyscallDesc("mq_timedreceive", unimplementedFunc); - /* 277 */ SyscallDesc("mq_notify", unimplementedFunc); - /* 278 */ SyscallDesc("mq_getsetattr", unimplementedFunc); - /* 279 */ SyscallDesc("waitid", unimplementedFunc); - /* 280 */ SyscallDesc("sys_setaltroot", unimplementedFunc); - /* 281 */ SyscallDesc("add_key", unimplementedFunc); - /* 282 */ SyscallDesc("request_key", unimplementedFunc); - /* 283 */ SyscallDesc("keyctl", unimplementedFunc); -}; - -SparcLinuxProcess::SparcLinuxProcess(const std::string &name, - ObjectFile *objFile, - int stdin_fd, - int stdout_fd, - int stderr_fd, - std::vector<std::string> &argv, - std::vector<std::string> &envp) - : LiveProcess(name, objFile, stdin_fd, stdout_fd, stderr_fd, argv, envp), - Num_Syscall_Descs(sizeof(syscallDescs) / sizeof(SyscallDesc)) -{ - // The sparc syscall table must be <= 283 entries because that is all there - // is space for. - assert(Num_Syscall_Descs <= 283); - - init_regs->intRegFile[0] = 0; -} - - - -SyscallDesc* -AlphaLinuxProcess::getDesc(int callnum) -{ - if (callnum < 0 || callnum > Num_Syscall_Descs) - return NULL; - return &syscallDescs[callnum]; -} diff --git a/arch/sparc/linux/process.hh b/arch/sparc/linux/process.hh deleted file mode 100644 index c41406b4b..000000000 --- a/arch/sparc/linux/process.hh +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2003-2004 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __SPARC_LINUX_PROCESS_HH__ -#define __SPARC_LINUX_PROCESS_HH__ - -#include "sim/process.hh" - - -/// A process with emulated SPARC/Linux syscalls. -class SparcLinuxProcess : public LiveProcess -{ - public: - /// Constructor. - SparcLinuxProcess(const std::string &name, - ObjectFile *objFile, - int stdin_fd, int stdout_fd, int stderr_fd, - std::vector<std::string> &argv, - std::vector<std::string> &envp); - - virtual SyscallDesc* getDesc(int callnum); - - /// The target system's hostname. - static const char *hostname; - - /// Array of syscall descriptors, indexed by call number. - static SyscallDesc syscallDescs[]; - - const int Num_Syscall_Descs; -}; - - -#endif // __ALPHA_LINUX_PROCESS_HH__ diff --git a/arch/sparc/process.cc b/arch/sparc/process.cc deleted file mode 100644 index 53a215379..000000000 --- a/arch/sparc/process.cc +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2003-2004 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "arch/sparc/process.hh" - -namespace SparcISA -{ - -LiveProcess * -createProcess(const string &nm, ObjectFile * objFile, - int stdin_fd, int stdout_fd, int stderr_fd, - vector<string> &argv, vector<string> &envp) -{ - LiveProcess * process = NULL; - if (objFile->getArch() != ObjectFile::SPARC) - fatal("Object file does not match architecture."); - switch (objFile->getOpSys()) { - case ObjectFile::Linux: - process = new SparcLinuxProcess(nm, objFile, - stdin_fd, stdout_fd, stderr_fd, - argv, envp); - break; - - case ObjectFile::Solaris: - default: - fatal("Unknown/unsupported operating system."); - } - return process; -} - -} // namespace SparcISA diff --git a/arch/sparc/process.hh b/arch/sparc/process.hh deleted file mode 100644 index 48041a316..000000000 --- a/arch/sparc/process.hh +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2003-2004 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __SPARC_PROCESS_HH__ -#define __SPARC_PROCESS_HH__ - -#include "arch/sparc/linux/process.hh" -#include "base/loader/object_file.hh" - -namespace SparcISA -{ - -LiveProcess * -createProcess(const string &nm, ObjectFile * objFile, - int stdin_fd, int stdout_fd, int stderr_fd, - vector<string> &argv, vector<string> &envp); - -} // namespace SparcISA - -#endif // __SPARC_PROCESS_HH__ diff --git a/base/cprintf.hh b/base/cprintf.hh deleted file mode 100644 index dcb292434..000000000 --- a/base/cprintf.hh +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (c) 2002-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPRINTF_HH__ -#define __CPRINTF_HH__ - -#include <iostream> -#include <list> -#include <sstream> -#include <string> - -namespace cp { - -#include "base/cprintf_formats.hh" - -class ArgList -{ - private: - class Base - { - public: - virtual ~Base() {} - virtual void process(std::ostream &out, Format &fmt) = 0; - }; - - template <typename T> - class Node : public Base - { - public: - const T &data; - - public: - Node(const T &d) : data(d) {} - virtual void process(std::ostream &out, Format &fmt) { - switch (fmt.format) { - case Format::character: - format_char(out, data, fmt); - break; - - case Format::integer: - format_integer(out, data, fmt); - break; - - case Format::floating: - format_float(out, data, fmt); - break; - - case Format::string: - format_string(out, data, fmt); - break; - - default: - out << "<bad format>"; - break; - } - } - }; - - typedef std::list<Base *> list_t; - - protected: - list_t objects; - std::ostream *stream; - - public: - ArgList() : stream(&std::cout) {} - ~ArgList(); - - template<class T> - void append(const T &data) { - Base *obj = new ArgList::Node<T>(data); - objects.push_back(obj); - } - - template<class T> - void prepend(const T &data) { - Base *obj = new ArgList::Node<T>(data); - objects.push_front(obj); - } - - void dump(const std::string &format); - void dump(std::ostream &strm, const std::string &fmt) - { stream = &strm; dump(fmt); } - - std::string dumpToString(const std::string &format); - - friend ArgList &operator<<(std::ostream &str, ArgList &list); -}; - -template<class T> -inline ArgList & -operator,(ArgList &alist, const T &data) -{ - alist.append(data); - return alist; -} - -class ArgListNull { -}; - -inline ArgList & -operator,(ArgList &alist, ArgListNull) -{ return alist; } - -// -// cprintf(format, args, ...) prints to cout -// (analogous to printf()) -// -inline void -__cprintf(const std::string &format, ArgList &args) -{ args.dump(format); delete &args; } -#define __cprintf__(format, args...) \ - cp::__cprintf(format, (*(new cp::ArgList), args)) -#define cprintf(args...) \ - __cprintf__(args, cp::ArgListNull()) - -// -// ccprintf(stream, format, args, ...) prints to the specified stream -// (analogous to fprintf()) -// -inline void -__ccprintf(std::ostream &stream, const std::string &format, ArgList &args) -{ args.dump(stream, format); delete &args; } -#define __ccprintf__(stream, format, args...) \ - cp::__ccprintf(stream, format, (*(new cp::ArgList), args)) -#define ccprintf(stream, args...) \ - __ccprintf__(stream, args, cp::ArgListNull()) - -// -// csprintf(format, args, ...) returns a string -// (roughly analogous to sprintf()) -// -inline std::string -__csprintf(const std::string &format, ArgList &args) -{ std::string s = args.dumpToString(format); delete &args; return s; } -#define __csprintf__(format, args...) \ - cp::__csprintf(format, (*(new cp::ArgList), args)) -#define csprintf(args...) \ - __csprintf__(args, cp::ArgListNull()) - -template<class T> -inline ArgList & -operator<<(ArgList &list, const T &data) -{ - list.append(data); - return list; -} - -inline ArgList & -operator<<(std::ostream &str, ArgList &list) -{ - list.stream = &str; - return list; -} - -class ArgListTemp -{ - private: - std::string format; - ArgList *args; - - public: - ArgListTemp(const std::string &f) : format(f) { args = new ArgList; } - ~ArgListTemp() { args->dump(format); delete args; } - - operator ArgList *() { return args; } -}; - -#define cformat(format) \ - (*((cp::ArgList *)cp::ArgListTemp(format))) -} - -#endif // __CPRINTF_HH__ diff --git a/base/cprintf_formats.hh b/base/cprintf_formats.hh deleted file mode 100644 index 11b0238ed..000000000 --- a/base/cprintf_formats.hh +++ /dev/null @@ -1,346 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPRINTF_FORMATS_HH__ -#define __CPRINTF_FORMATS_HH__ - -struct Format -{ - bool alternate_form; - bool flush_left; - bool print_sign; - bool blank_space; - bool fill_zero; - bool uppercase; - enum { dec, hex, oct } base; - enum { none, string, integer, character, floating } format; - enum { best, fixed, scientific } float_format; - int precision; - int width; - - Format() { clear(); } - - void clear() - { - alternate_form = false; - flush_left = false; - print_sign = false; - blank_space = false; - fill_zero = false; - uppercase = false; - base = dec; - format = none; - precision = -1; - width = 0; - } -}; - -template <typename T> -inline void -_format_char(std::ostream &out, const T &data, Format &fmt) -{ - using namespace std; - - out << data; -} - -template <typename T> -inline void -_format_integer(std::ostream &out, const T &data, Format &fmt) -{ - using namespace std; - - switch (fmt.base) { - case Format::hex: - out.setf(ios::hex, ios::basefield); - break; - - case Format::oct: - out.setf(ios::oct, ios::basefield); - break; - - case Format::dec: - out.setf(ios::dec, ios::basefield); - break; - } - - if (fmt.alternate_form) { - if (!fmt.fill_zero) - out.setf(ios::showbase); - else { - switch (fmt.base) { - case Format::hex: - out << "0x"; - fmt.width -= 2; - break; - case Format::oct: - out << "0"; - fmt.width -= 1; - break; - case Format::dec: - break; - } - } - } - - if (fmt.fill_zero) - out.fill('0'); - - if (fmt.width > 0) - out.width(fmt.width); - - if (fmt.flush_left && !fmt.fill_zero) - out.setf(ios::left); - - if (fmt.print_sign) - out.setf(ios::showpos); - - if (fmt.uppercase) - out.setf(ios::uppercase); - - out << data; -} - -template <typename T> -inline void -_format_float(std::ostream &out, const T &data, Format &fmt) -{ - using namespace std; - - switch (fmt.float_format) { - case Format::scientific: - if (fmt.precision != -1) { - if (fmt.width > 0) - out.width(fmt.width); - - if (fmt.precision == 0) - fmt.precision = 1; - else - out.setf(ios::scientific); - - out.precision(fmt.precision); - } else - if (fmt.width > 0) - out.width(fmt.width); - - if (fmt.uppercase) - out.setf(ios::uppercase); - break; - - case Format::fixed: - if (fmt.precision != -1) { - if (fmt.width > 0) - out.width(fmt.width); - - out.setf(ios::fixed); - out.precision(fmt.precision); - } else - if (fmt.width > 0) - out.width(fmt.width); - - break; - - default: - if (fmt.precision != -1) - out.precision(fmt.precision); - - if (fmt.width > 0) - out.width(fmt.width); - - break; - } - - out << data; -} - -template <typename T> -inline void -_format_string(std::ostream &out, const T &data, Format &fmt) -{ - using namespace std; - -#if defined(__GNUC__) && (__GNUC__ < 3) || 1 - if (fmt.width > 0) { - std::stringstream foo; - foo << data; - int flen = foo.str().size(); - - if (fmt.width > flen) { - char *spaces = new char[fmt.width - flen + 1]; - memset(spaces, ' ', fmt.width - flen); - spaces[fmt.width - flen] = 0; - - if (fmt.flush_left) - out << foo.str() << spaces; - else - out << spaces << foo.str(); - - delete [] spaces; - } else - out << data; - } else - out << data; -#else - if (fmt.width > 0) - out.width(fmt.width); - if (fmt.flush_left) - out.setf(ios::left); - - out << data; -#endif -} - -///////////////////////////////////////////////////////////////////////////// -// -// The code below controls the actual usage of formats for various types -// - -// -// character formats -// -template <typename T> -inline void -format_char(std::ostream &out, const T &data, Format &fmt) -{ out << "<bad arg type for char format>"; } - -inline void -format_char(std::ostream &out, char data, Format &fmt) -{ _format_char(out, data, fmt); } - -inline void -format_char(std::ostream &out, unsigned char data, Format &fmt) -{ _format_char(out, data, fmt); } - -inline void -format_char(std::ostream &out, signed char data, Format &fmt) -{ _format_char(out, data, fmt); } - -inline void -format_char(std::ostream &out, short data, Format &fmt) -{ _format_char(out, (char)data, fmt); } - -inline void -format_char(std::ostream &out, unsigned short data, Format &fmt) -{ _format_char(out, (char)data, fmt); } - -inline void -format_char(std::ostream &out, int data, Format &fmt) -{ _format_char(out, (char)data, fmt); } - -inline void -format_char(std::ostream &out, unsigned int data, Format &fmt) -{ _format_char(out, (char)data, fmt); } - -inline void -format_char(std::ostream &out, long data, Format &fmt) -{ _format_char(out, (char)data, fmt); } - -inline void -format_char(std::ostream &out, unsigned long data, Format &fmt) -{ _format_char(out, (char)data, fmt); } - -inline void -format_char(std::ostream &out, long long data, Format &fmt) -{ _format_char(out, (char)data, fmt); } - -inline void -format_char(std::ostream &out, unsigned long long data, Format &fmt) -{ _format_char(out, (char)data, fmt); } - -// -// integer formats -// -template <typename T> -inline void -format_integer(std::ostream &out, const T &data, Format &fmt) -{ _format_integer(out, data, fmt); } -inline void -format_integer(std::ostream &out, char data, Format &fmt) -{ _format_integer(out, data, fmt); } -inline void -format_integer(std::ostream &out, unsigned char data, Format &fmt) -{ _format_integer(out, data, fmt); } -inline void -format_integer(std::ostream &out, signed char data, Format &fmt) -{ _format_integer(out, data, fmt); } -#if 0 -inline void -format_integer(std::ostream &out, short data, Format &fmt) -{ _format_integer(out, data, fmt); } -inline void -format_integer(std::ostream &out, unsigned short data, Format &fmt) -{ _format_integer(out, data, fmt); } -inline void -format_integer(std::ostream &out, int data, Format &fmt) -{ _format_integer(out, data, fmt); } -inline void -format_integer(std::ostream &out, unsigned int data, Format &fmt) -{ _format_integer(out, data, fmt); } -inline void -format_integer(std::ostream &out, long data, Format &fmt) -{ _format_integer(out, data, fmt); } -inline void -format_integer(std::ostream &out, unsigned long data, Format &fmt) -{ _format_integer(out, data, fmt); } -inline void -format_integer(std::ostream &out, long long data, Format &fmt) -{ _format_integer(out, data, fmt); } -inline void -format_integer(std::ostream &out, unsigned long long data, Format &fmt) -{ _format_integer(out, data, fmt); } -#endif - -// -// floating point formats -// -template <typename T> -inline void -format_float(std::ostream &out, const T &data, Format &fmt) -{ out << "<bad arg type for float format>"; } - -inline void -format_float(std::ostream &out, float data, Format &fmt) -{ _format_float(out, data, fmt); } - -inline void -format_float(std::ostream &out, double data, Format &fmt) -{ _format_float(out, data, fmt); } - -// -// string formats -// -template <typename T> -inline void -format_string(std::ostream &out, const T &data, Format &fmt) -{ _format_string(out, data, fmt); } - -inline void -format_string(std::ostream &out, const std::stringstream &data, Format &fmt) -{ _format_string(out, data.str(), fmt); } - -#endif // __CPRINTF_FORMATS_HH__ diff --git a/base/crc.cc b/base/crc.cc deleted file mode 100644 index 87963ef14..000000000 --- a/base/crc.cc +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) 1988, 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sstream> -#include <string> - -#include "sim/host.hh" -#include "base/crc.hh" - -#define ETHER_CRC_POLY_LE 0xedb88320 -#define ETHER_CRC_POLY_BE 0x04c11db6 - -#if 0 -/* - * This is for reference. We have a table-driven version - * of the little-endian crc32 generator, which is faster - * than the double-loop. - */ -uint32_t -crc32le(const uint8_t *buf, size_t len) -{ - uint32_t c, crc, carry; - size_t i, j; - - crc = 0xffffffffU; /* initial value */ - - for (i = 0; i < len; i++) { - c = buf[i]; - for (j = 0; j < 8; j++) { - carry = ((crc & 0x01) ? 1 : 0) ^ (c & 0x01); - crc >>= 1; - c >>= 1; - if (carry) - crc = (crc ^ ETHER_CRC_POLY_LE); - } - } - - return (crc); -} -#else -uint32_t -crc32le(const uint8_t *buf, size_t len) -{ - static const uint32_t crctab[] = { - 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, - 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, - 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, - 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c - }; - uint32_t crc; - int i; - - crc = 0xffffffffU; /* initial value */ - - for (i = 0; i < len; i++) { - crc ^= buf[i]; - crc = (crc >> 4) ^ crctab[crc & 0xf]; - crc = (crc >> 4) ^ crctab[crc & 0xf]; - } - - return (crc); -} -#endif - -uint32_t -crc32be(const uint8_t *buf, size_t len) -{ - uint32_t c, crc, carry; - size_t i, j; - - crc = 0xffffffffU; /* initial value */ - - for (i = 0; i < len; i++) { - c = buf[i]; - for (j = 0; j < 8; j++) { - carry = ((crc & 0x80000000U) ? 1 : 0) ^ (c & 0x01); - crc <<= 1; - c >>= 1; - if (carry) - crc = (crc ^ ETHER_CRC_POLY_BE) | carry; - } - } - - return (crc); -} diff --git a/base/hostinfo.cc b/base/hostinfo.cc deleted file mode 100644 index d15e3ddc1..000000000 --- a/base/hostinfo.cc +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <ctype.h> -#include <errno.h> -#include <math.h> -#include <unistd.h> - -#include <cstdio> -#include <cstdlib> -#include <cstring> -#include <string> - -#include "base/misc.hh" -#include "sim/host.hh" - -using namespace std; - -string -__get_hostname() -{ - char host[256]; - if (gethostname(host, sizeof host) == -1) - warn("could not get host name!"); - return host; -} - -string & -hostname() -{ - static string hostname = __get_hostname(); - return hostname; -} - -uint64_t -procInfo(char *filename, char *target) -{ - int done = 0; - char line[80]; - char format[80]; - long usage; - - FILE *fp = fopen(filename, "r"); - - while (fp && !feof(fp) && !done) { - if (fgets(line, 80, fp)) { - if (strncmp(line, target, strlen(target)) == 0) { - snprintf(format, sizeof(format), "%s %%ld", target); - sscanf(line, format, &usage); - - fclose(fp); - return usage ; - } - } - } - - if (fp) - fclose(fp); - - return 0; -} diff --git a/base/inet.cc b/base/inet.cc deleted file mode 100644 index 2e1c4c84b..000000000 --- a/base/inet.cc +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright (c) 2002-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <cstdio> -#include <sstream> -#include <string> - -#include "base/cprintf.hh" -#include "sim/host.hh" -#include "base/inet.hh" - -using namespace std; -namespace Net { - -EthAddr::EthAddr() -{ - memset(data, 0, ETH_ADDR_LEN); -} - -EthAddr::EthAddr(const uint8_t ea[ETH_ADDR_LEN]) -{ - *data = *ea; -} - -EthAddr::EthAddr(const eth_addr &ea) -{ - *data = *ea.data; -} - -EthAddr::EthAddr(const std::string &addr) -{ - parse(addr); -} - -const EthAddr & -EthAddr::operator=(const eth_addr &ea) -{ - *data = *ea.data; - return *this; -} - -const EthAddr & -EthAddr::operator=(const std::string &addr) -{ - parse(addr); - return *this; -} - -void -EthAddr::parse(const std::string &addr) -{ - // the hack below is to make sure that ETH_ADDR_LEN is 6 otherwise - // the sscanf function won't work. - int bytes[ETH_ADDR_LEN == 6 ? ETH_ADDR_LEN : -1]; - if (sscanf(addr.c_str(), "%x:%x:%x:%x:%x:%x", &bytes[0], &bytes[1], - &bytes[2], &bytes[3], &bytes[4], &bytes[5]) != ETH_ADDR_LEN) { - memset(data, 0xff, ETH_ADDR_LEN); - return; - } - - for (int i = 0; i < ETH_ADDR_LEN; ++i) { - if (bytes[i] & ~0xff) { - memset(data, 0xff, ETH_ADDR_LEN); - return; - } - - data[i] = bytes[i]; - } -} - -string -EthAddr::string() const -{ - stringstream stream; - stream << *this; - return stream.str(); -} - -bool -operator==(const EthAddr &left, const EthAddr &right) -{ - return memcmp(left.bytes(), right.bytes(), ETH_ADDR_LEN); -} - -ostream & -operator<<(ostream &stream, const EthAddr &ea) -{ - const uint8_t *a = ea.addr(); - ccprintf(stream, "%x:%x:%x:%x:%x:%x", a[0], a[1], a[2], a[3], a[4], a[5]); - return stream; -} - -uint16_t -cksum(const IpPtr &ptr) -{ - int sum = ip_cksum_add(ptr->bytes(), ptr->hlen(), 0); - return ip_cksum_carry(sum); -} - -uint16_t -__tu_cksum(const IpPtr &ip) -{ - int tcplen = ip->len() - ip->hlen(); - int sum = ip_cksum_add(ip->payload(), tcplen, 0); - sum = ip_cksum_add(&ip->ip_src, 8, sum); // source and destination - sum += htons(ip->ip_p + tcplen); - return ip_cksum_carry(sum); -} - -uint16_t -cksum(const TcpPtr &tcp) -{ return __tu_cksum(IpPtr(tcp.packet())); } - -uint16_t -cksum(const UdpPtr &udp) -{ return __tu_cksum(IpPtr(udp.packet())); } - -bool -IpHdr::options(vector<const IpOpt *> &vec) const -{ - vec.clear(); - - const uint8_t *data = bytes() + sizeof(struct ip_hdr); - int all = hlen() - sizeof(struct ip_hdr); - while (all > 0) { - const IpOpt *opt = (const IpOpt *)data; - int len = opt->len(); - if (all < len) - return false; - - vec.push_back(opt); - all -= len; - data += len; - } - - return true; -} - -bool -TcpHdr::options(vector<const TcpOpt *> &vec) const -{ - vec.clear(); - - const uint8_t *data = bytes() + sizeof(struct tcp_hdr); - int all = off() - sizeof(struct tcp_hdr); - while (all > 0) { - const TcpOpt *opt = (const TcpOpt *)data; - int len = opt->len(); - if (all < len) - return false; - - vec.push_back(opt); - all -= len; - data += len; - } - - return true; -} - -bool -TcpOpt::sack(vector<SackRange> &vec) const -{ - vec.clear(); - - const uint8_t *data = bytes() + sizeof(struct tcp_hdr); - int all = len() - offsetof(tcp_opt, opt_data.sack); - while (all > 0) { - const uint16_t *sack = (const uint16_t *)data; - int len = sizeof(uint16_t) * 2; - if (all < len) { - vec.clear(); - return false; - } - - vec.push_back(RangeIn(ntohs(sack[0]), ntohs(sack[1]))); - all -= len; - data += len; - } - - return false; -} - -/* namespace Net */ } diff --git a/base/inet.hh b/base/inet.hh deleted file mode 100644 index e07e01935..000000000 --- a/base/inet.hh +++ /dev/null @@ -1,407 +0,0 @@ -/* - * Copyright (c) 2002-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __BASE_INET_HH__ -#define __BASE_INET_HH__ - -#include <iosfwd> -#include <string> -#include <utility> -#include <vector> - -#include "base/range.hh" -#include "dev/etherpkt.hh" -#include "sim/host.hh" - -#include "dnet/os.h" -#include "dnet/eth.h" -#include "dnet/ip.h" -#include "dnet/ip6.h" -#include "dnet/addr.h" -#include "dnet/arp.h" -#include "dnet/icmp.h" -#include "dnet/tcp.h" -#include "dnet/udp.h" -#include "dnet/intf.h" -#include "dnet/route.h" -#include "dnet/fw.h" -#include "dnet/blob.h" -#include "dnet/rand.h" - -namespace Net { - -/* - * Ethernet Stuff - */ -struct EthAddr : protected eth_addr -{ - protected: - void parse(const std::string &addr); - - public: - EthAddr(); - EthAddr(const uint8_t ea[ETH_ADDR_LEN]); - EthAddr(const eth_addr &ea); - EthAddr(const std::string &addr); - const EthAddr &operator=(const eth_addr &ea); - const EthAddr &operator=(const std::string &addr); - - int size() const { return sizeof(eth_addr); } - - const uint8_t *bytes() const { return &data[0]; } - uint8_t *bytes() { return &data[0]; } - - const uint8_t *addr() const { return &data[0]; } - bool unicast() const { return data[0] == 0x00; } - bool multicast() const { return data[0] == 0x01; } - bool broadcast() const { return data[0] == 0xff; } - std::string string() const; - - operator uint64_t() const - { - uint64_t reg = 0; - reg |= ((uint64_t)data[0]) << 40; - reg |= ((uint64_t)data[1]) << 32; - reg |= ((uint64_t)data[2]) << 24; - reg |= ((uint64_t)data[3]) << 16; - reg |= ((uint64_t)data[4]) << 8; - reg |= ((uint64_t)data[5]) << 0; - return reg; - } - -}; - -std::ostream &operator<<(std::ostream &stream, const EthAddr &ea); -bool operator==(const EthAddr &left, const EthAddr &right); - -struct EthHdr : public eth_hdr -{ - uint16_t type() const { return ntohs(eth_type); } - const EthAddr &src() const { return *(EthAddr *)ð_src; } - const EthAddr &dst() const { return *(EthAddr *)ð_dst; } - - int size() const { return sizeof(eth_hdr); } - - const uint8_t *bytes() const { return (const uint8_t *)this; } - const uint8_t *payload() const { return bytes() + size(); } - uint8_t *bytes() { return (uint8_t *)this; } - uint8_t *payload() { return bytes() + size(); } -}; - -class EthPtr -{ - protected: - friend class IpPtr; - PacketPtr p; - - public: - EthPtr() {} - EthPtr(const PacketPtr &ptr) : p(ptr) { } - - EthHdr *operator->() { return (EthHdr *)p->data; } - EthHdr &operator*() { return *(EthHdr *)p->data; } - operator EthHdr *() { return (EthHdr *)p->data; } - - const EthHdr *operator->() const { return (const EthHdr *)p->data; } - const EthHdr &operator*() const { return *(const EthHdr *)p->data; } - operator const EthHdr *() const { return (const EthHdr *)p->data; } - - const EthPtr &operator=(const PacketPtr &ptr) { p = ptr; return *this; } - - const PacketPtr packet() const { return p; } - PacketPtr packet() { return p; } - bool operator!() const { return !p; } - operator bool() const { return p; } -}; - -/* - * IP Stuff - */ -struct IpOpt; -struct IpHdr : public ip_hdr -{ - uint8_t version() const { return ip_v; } - uint8_t hlen() const { return ip_hl * 4; } - uint8_t tos() const { return ip_tos; } - uint16_t len() const { return ntohs(ip_len); } - uint16_t id() const { return ntohs(ip_id); } - uint16_t frag_flags() const { return ntohs(ip_off) >> 13; } - uint16_t frag_off() const { return ntohs(ip_off) & 0x1fff; } - uint8_t ttl() const { return ip_ttl; } - uint8_t proto() const { return ip_p; } - uint16_t sum() const { return ip_sum; } - uint32_t src() const { return ntohl(ip_src); } - uint32_t dst() const { return ntohl(ip_dst); } - - void sum(uint16_t sum) { ip_sum = sum; } - - bool options(std::vector<const IpOpt *> &vec) const; - - int size() const { return hlen(); } - const uint8_t *bytes() const { return (const uint8_t *)this; } - const uint8_t *payload() const { return bytes() + size(); } - uint8_t *bytes() { return (uint8_t *)this; } - uint8_t *payload() { return bytes() + size(); } -}; - -class IpPtr -{ - protected: - friend class TcpPtr; - friend class UdpPtr; - PacketPtr p; - - const IpHdr *h() const - { return (const IpHdr *)(p->data + sizeof(eth_hdr)); } - IpHdr *h() { return (IpHdr *)(p->data + sizeof(eth_hdr)); } - - void set(const PacketPtr &ptr) - { - EthHdr *eth = (EthHdr *)ptr->data; - if (eth->type() == ETH_TYPE_IP) - p = ptr; - else - p = 0; - } - - public: - IpPtr() {} - IpPtr(const PacketPtr &ptr) { set(ptr); } - IpPtr(const EthPtr &ptr) { set(ptr.p); } - IpPtr(const IpPtr &ptr) : p(ptr.p) { } - - IpHdr *operator->() { return h(); } - IpHdr &operator*() { return *h(); } - operator IpHdr *() { return h(); } - - const IpHdr *operator->() const { return h(); } - const IpHdr &operator*() const { return *h(); } - operator const IpHdr *() const { return h(); } - - const IpPtr &operator=(const PacketPtr &ptr) { set(ptr); return *this; } - const IpPtr &operator=(const EthPtr &ptr) { set(ptr.p); return *this; } - const IpPtr &operator=(const IpPtr &ptr) { p = ptr.p; return *this; } - - const PacketPtr packet() const { return p; } - PacketPtr packet() { return p; } - bool operator!() const { return !p; } - operator bool() const { return p; } - operator bool() { return p; } -}; - -uint16_t cksum(const IpPtr &ptr); - -struct IpOpt : public ip_opt -{ - uint8_t type() const { return opt_type; } - uint8_t typeNumber() const { return IP_OPT_NUMBER(opt_type); } - uint8_t typeClass() const { return IP_OPT_CLASS(opt_type); } - uint8_t typeCopied() const { return IP_OPT_COPIED(opt_type); } - uint8_t len() const { return IP_OPT_TYPEONLY(type()) ? 1 : opt_len; } - - bool isNumber(int num) const { return typeNumber() == IP_OPT_NUMBER(num); } - bool isClass(int cls) const { return typeClass() == IP_OPT_CLASS(cls); } - bool isCopied(int cpy) const { return typeCopied() == IP_OPT_COPIED(cpy); } - - const uint8_t *data() const { return opt_data.data8; } - void sec(ip_opt_data_sec &sec) const; - void lsrr(ip_opt_data_rr &rr) const; - void ssrr(ip_opt_data_rr &rr) const; - void ts(ip_opt_data_ts &ts) const; - uint16_t satid() const { return ntohs(opt_data.satid); } - uint16_t mtup() const { return ntohs(opt_data.mtu); } - uint16_t mtur() const { return ntohs(opt_data.mtu); } - void tr(ip_opt_data_tr &tr) const; - const uint32_t *addext() const { return &opt_data.addext[0]; } - uint16_t rtralt() const { return ntohs(opt_data.rtralt); } - void sdb(std::vector<uint32_t> &vec) const; -}; - -/* - * TCP Stuff - */ -struct TcpOpt; -struct TcpHdr : public tcp_hdr -{ - uint16_t sport() const { return ntohs(th_sport); } - uint16_t dport() const { return ntohs(th_dport); } - uint32_t seq() const { return ntohl(th_seq); } - uint32_t ack() const { return ntohl(th_ack); } - uint8_t off() const { return th_off; } - uint8_t flags() const { return th_flags & 0x3f; } - uint16_t win() const { return ntohs(th_win); } - uint16_t sum() const { return th_sum; } - uint16_t urp() const { return ntohs(th_urp); } - - void sum(uint16_t sum) { th_sum = sum; } - - bool options(std::vector<const TcpOpt *> &vec) const; - - int size() const { return off(); } - const uint8_t *bytes() const { return (const uint8_t *)this; } - const uint8_t *payload() const { return bytes() + size(); } - uint8_t *bytes() { return (uint8_t *)this; } - uint8_t *payload() { return bytes() + size(); } -}; - -class TcpPtr -{ - protected: - PacketPtr p; - int off; - - const TcpHdr *h() const { return (const TcpHdr *)(p->data + off); } - TcpHdr *h() { return (TcpHdr *)(p->data + off); } - - void set(const PacketPtr &ptr, int offset) { p = ptr; off = offset; } - void set(const IpPtr &ptr) - { - if (ptr->proto() == IP_PROTO_TCP) - set(ptr.p, sizeof(eth_hdr) + ptr->hlen()); - else - set(0, 0); - } - - public: - TcpPtr() {} - TcpPtr(const IpPtr &ptr) { set(ptr); } - TcpPtr(const TcpPtr &ptr) : p(ptr.p), off(ptr.off) {} - - TcpHdr *operator->() { return h(); } - TcpHdr &operator*() { return *h(); } - operator TcpHdr *() { return h(); } - - const TcpHdr *operator->() const { return h(); } - const TcpHdr &operator*() const { return *h(); } - operator const TcpHdr *() const { return h(); } - - const TcpPtr &operator=(const IpPtr &i) { set(i); return *this; } - const TcpPtr &operator=(const TcpPtr &t) { set(t.p, t.off); return *this; } - - const PacketPtr packet() const { return p; } - PacketPtr packet() { return p; } - bool operator!() const { return !p; } - operator bool() const { return p; } - operator bool() { return p; } -}; - -uint16_t cksum(const TcpPtr &ptr); - -typedef Range<uint16_t> SackRange; - -struct TcpOpt : public tcp_opt -{ - uint8_t type() const { return opt_type; } - uint8_t len() const { return TCP_OPT_TYPEONLY(type()) ? 1 : opt_len; } - - bool isopt(int opt) const { return type() == opt; } - - const uint8_t *data() const { return opt_data.data8; } - - uint16_t mss() const { return ntohs(opt_data.mss); } - uint8_t wscale() const { return opt_data.wscale; } - bool sack(std::vector<SackRange> &vec) const; - uint32_t echo() const { return ntohl(opt_data.echo); } - uint32_t tsval() const { return ntohl(opt_data.timestamp[0]); } - uint32_t tsecr() const { return ntohl(opt_data.timestamp[1]); } - uint32_t cc() const { return ntohl(opt_data.cc); } - uint8_t cksum() const{ return opt_data.cksum; } - const uint8_t *md5() const { return opt_data.md5; } - - int size() const { return len(); } - const uint8_t *bytes() const { return (const uint8_t *)this; } - const uint8_t *payload() const { return bytes() + size(); } - uint8_t *bytes() { return (uint8_t *)this; } - uint8_t *payload() { return bytes() + size(); } -}; - -/* - * UDP Stuff - */ -struct UdpHdr : public udp_hdr -{ - uint16_t sport() const { return ntohs(uh_sport); } - uint16_t dport() const { return ntohs(uh_dport); } - uint16_t len() const { return ntohs(uh_ulen); } - uint16_t sum() const { return uh_sum; } - - void sum(uint16_t sum) { uh_sum = sum; } - - int size() const { return sizeof(udp_hdr); } - const uint8_t *bytes() const { return (const uint8_t *)this; } - const uint8_t *payload() const { return bytes() + size(); } - uint8_t *bytes() { return (uint8_t *)this; } - uint8_t *payload() { return bytes() + size(); } -}; - -class UdpPtr -{ - protected: - PacketPtr p; - int off; - - const UdpHdr *h() const { return (const UdpHdr *)(p->data + off); } - UdpHdr *h() { return (UdpHdr *)(p->data + off); } - - void set(const PacketPtr &ptr, int offset) { p = ptr; off = offset; } - void set(const IpPtr &ptr) - { - if (ptr->proto() == IP_PROTO_UDP) - set(ptr.p, sizeof(eth_hdr) + ptr->hlen()); - else - set(0, 0); - } - - public: - UdpPtr() {} - UdpPtr(const IpPtr &ptr) { set(ptr); } - UdpPtr(const UdpPtr &ptr) : p(ptr.p), off(ptr.off) {} - - UdpHdr *operator->() { return h(); } - UdpHdr &operator*() { return *h(); } - operator UdpHdr *() { return h(); } - - const UdpHdr *operator->() const { return h(); } - const UdpHdr &operator*() const { return *h(); } - operator const UdpHdr *() const { return h(); } - - const UdpPtr &operator=(const IpPtr &i) { set(i); return *this; } - const UdpPtr &operator=(const UdpPtr &t) { set(t.p, t.off); return *this; } - - const PacketPtr packet() const { return p; } - PacketPtr packet() { return p; } - bool operator!() const { return !p; } - operator bool() const { return p; } - operator bool() { return p; } -}; - -uint16_t cksum(const UdpPtr &ptr); - -/* namespace Net */ } - -#endif // __BASE_INET_HH__ diff --git a/base/intmath.hh b/base/intmath.hh deleted file mode 100644 index df0687c62..000000000 --- a/base/intmath.hh +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Copyright (c) 2001, 2003-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __INTMATH_HH__ -#define __INTMATH_HH__ - -#include <assert.h> - -#include "sim/host.hh" - -// Returns the prime number one less than n. -int prevPrime(int n); - -// Determine if a number is prime -template <class T> -inline bool -isPrime(T n) -{ - T i; - - if (n == 2 || n == 3) - return true; - - // Don't try every odd number to prove if it is a prime. - // Toggle between every 2nd and 4th number. - // (This is because every 6th odd number is divisible by 3.) - for (i = 5; i*i <= n; i += 6) { - if (((n % i) == 0 ) || ((n % (i + 2)) == 0) ) { - return false; - } - } - - return true; -} - -template <class T> -inline T -leastSigBit(T n) -{ - return n & ~(n - 1); -} - -template <class T> -inline bool -isPowerOf2(T n) -{ - return n != 0 && leastSigBit(n) == n; -} - -inline int -floorLog2(unsigned x) -{ - assert(x > 0); - - int y = 0; - - if (x & 0xffff0000) { y += 16; x >>= 16; } - if (x & 0x0000ff00) { y += 8; x >>= 8; } - if (x & 0x000000f0) { y += 4; x >>= 4; } - if (x & 0x0000000c) { y += 2; x >>= 2; } - if (x & 0x00000002) { y += 1; } - - return y; -} - -inline int -floorLog2(unsigned long x) -{ - assert(x > 0); - - int y = 0; - -#if defined(__LP64__) - if (x & ULL(0xffffffff00000000)) { y += 32; x >>= 32; } -#endif - if (x & 0xffff0000) { y += 16; x >>= 16; } - if (x & 0x0000ff00) { y += 8; x >>= 8; } - if (x & 0x000000f0) { y += 4; x >>= 4; } - if (x & 0x0000000c) { y += 2; x >>= 2; } - if (x & 0x00000002) { y += 1; } - - return y; -} - -inline int -floorLog2(unsigned long long x) -{ - assert(x > 0); - - int y = 0; - - if (x & ULL(0xffffffff00000000)) { y += 32; x >>= 32; } - if (x & ULL(0x00000000ffff0000)) { y += 16; x >>= 16; } - if (x & ULL(0x000000000000ff00)) { y += 8; x >>= 8; } - if (x & ULL(0x00000000000000f0)) { y += 4; x >>= 4; } - if (x & ULL(0x000000000000000c)) { y += 2; x >>= 2; } - if (x & ULL(0x0000000000000002)) { y += 1; } - - return y; -} - -inline int -floorLog2(int x) -{ - assert(x > 0); - return floorLog2((unsigned)x); -} - -inline int -floorLog2(long x) -{ - assert(x > 0); - return floorLog2((unsigned long)x); -} - -inline int -floorLog2(long long x) -{ - assert(x > 0); - return floorLog2((unsigned long long)x); -} - -template <class T> -inline int -ceilLog2(T n) -{ - if (n == 1) - return 0; - - return floorLog2(n - (T)1) + 1; -} - -template <class T> -inline T -floorPow2(T n) -{ - return (T)1 << floorLog2(n); -} - -template <class T> -inline T -ceilPow2(T n) -{ - return (T)1 << ceilLog2(n); -} - -template <class T> -inline T -divCeil(T a, T b) -{ - return (a + b - 1) / b; -} - -template <class T> -inline T -roundUp(T val, int align) -{ - T mask = (T)align - 1; - return (val + mask) & ~mask; -} - -template <class T> -inline T -roundDown(T val, T align) -{ - T mask = align - 1; - return val & ~mask; -} - -inline bool -isHex(char c) -{ - return c >= '0' && c <= '9' || - c >= 'A' && c <= 'F' || - c >= 'a' && c <= 'f'; -} - -inline bool -isOct(char c) -{ - return c >= '0' && c <= '7'; -} - -inline bool -isDec(char c) -{ - return c >= '0' && c <= '9'; -} - -inline int -hex2Int(char c) -{ - if (c >= '0' && c <= '9') - return (c - '0'); - - if (c >= 'A' && c <= 'F') - return (c - 'A') + 10; - - if (c >= 'a' && c <= 'f') - return (c - 'a') + 10; - - return 0; -} - -#endif // __INTMATH_HH__ diff --git a/base/loader/aout_object.cc b/base/loader/aout_object.cc deleted file mode 100644 index c81f7123f..000000000 --- a/base/loader/aout_object.cc +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <string> - -#include "base/loader/aout_object.hh" - -#include "mem/functional/functional.hh" -#include "base/loader/symtab.hh" - -#include "base/trace.hh" // for DPRINTF - -#include "base/loader/exec_aout.h" - -using namespace std; - -ObjectFile * -AoutObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data) -{ - if (!N_BADMAG(*(aout_exechdr *)data)) { - // right now this is only used for Alpha PAL code - return new AoutObject(fname, fd, len, data, - ObjectFile::Alpha, ObjectFile::UnknownOpSys); - } - else { - return NULL; - } -} - - -AoutObject::AoutObject(const string &_filename, int _fd, - size_t _len, uint8_t *_data, - Arch _arch, OpSys _opSys) - : ObjectFile(_filename, _fd, _len, _data, _arch, _opSys) -{ - execHdr = (aout_exechdr *)fileData; - - entry = execHdr->entry; - - text.baseAddr = N_TXTADDR(*execHdr); - text.size = execHdr->tsize; - - data.baseAddr = N_DATADDR(*execHdr); - data.size = execHdr->dsize; - - bss.baseAddr = N_BSSADDR(*execHdr); - bss.size = execHdr->bsize; - - DPRINTFR(Loader, "text: 0x%x %d\ndata: 0x%x %d\nbss: 0x%x %d\n", - text.baseAddr, text.size, data.baseAddr, data.size, - bss.baseAddr, bss.size); -} - - -bool -AoutObject::loadSections(FunctionalMemory *mem, bool loadPhys) -{ - Addr textAddr = text.baseAddr; - Addr dataAddr = data.baseAddr; - - if (loadPhys) { - textAddr &= (ULL(1) << 40) - 1; - dataAddr &= (ULL(1) << 40) - 1; - } - - // Since we don't really have an MMU and all memory is - // zero-filled, there's no need to set up the BSS segment. - if (text.size != 0) - mem->prot_write(textAddr, fileData + N_TXTOFF(*execHdr), text.size); - if (data.size != 0) - mem->prot_write(dataAddr, fileData + N_DATOFF(*execHdr), data.size); - - return true; -} - - -bool -AoutObject::loadGlobalSymbols(SymbolTable *symtab) -{ - // a.out symbols not supported yet - return false; -} - -bool -AoutObject::loadLocalSymbols(SymbolTable *symtab) -{ - // a.out symbols not supported yet - return false; -} diff --git a/base/loader/aout_object.hh b/base/loader/aout_object.hh deleted file mode 100644 index 1868192b2..000000000 --- a/base/loader/aout_object.hh +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __AOUT_OBJECT_HH__ -#define __AOUT_OBJECT_HH__ - -#include "base/loader/object_file.hh" - -// forward decls: avoid including exec_aout.h here -struct aout_exechdr; - -class AoutObject : public ObjectFile -{ - protected: - aout_exechdr *execHdr; - - AoutObject(const std::string &_filename, int _fd, - size_t _len, uint8_t *_data, - Arch _arch, OpSys _opSys); - - public: - virtual ~AoutObject() {} - - virtual bool loadSections(FunctionalMemory *mem, - bool loadPhys = false); - virtual bool loadGlobalSymbols(SymbolTable *symtab); - virtual bool loadLocalSymbols(SymbolTable *symtab); - - static ObjectFile *tryFile(const std::string &fname, int fd, - size_t len, uint8_t *data); -}; - -#endif // __AOUT_OBJECT_HH__ diff --git a/base/loader/coff_sym.h b/base/loader/coff_sym.h deleted file mode 100644 index 734d96a98..000000000 --- a/base/loader/coff_sym.h +++ /dev/null @@ -1,489 +0,0 @@ -/* - * Taken from binutils-2.14.90.0.5 include/coff/sym.h - */ - -/* Declarations of internal format of MIPS ECOFF symbols. - Originally contributed by MIPS Computer Systems and Third Eye Software. - Changes contributed by Cygnus Support are in the public domain. - - This file is just aggregated with the files that make up the GNU - release; it is not considered part of GAS, GDB, or other GNU - programs. */ - -/* - * |-----------------------------------------------------------| - * | Copyright (c) 1992, 1991, 1990 MIPS Computer Systems, Inc.| - * | MIPS Computer Systems, Inc. grants reproduction and use | - * | rights to all parties, PROVIDED that this comment is | - * | maintained in the copy. | - * |-----------------------------------------------------------| - */ -#ifndef _SYM_H -#define _SYM_H - -/* (C) Copyright 1984 by Third Eye Software, Inc. - * - * Third Eye Software, Inc. grants reproduction and use rights to - * all parties, PROVIDED that this comment is maintained in the copy. - * - * Third Eye makes no claims about the applicability of this - * symbol table to a particular use. - */ - -/* - * This file contains the definition of the Third Eye Symbol Table. - * - * Symbols are assumed to be in 'encounter order' - i.e. the order that - * the things they represent were encountered by the compiler/assembler/loader. - * EXCEPT for globals! These are assumed to be bunched together, - * probably right after the last 'normal' symbol. Globals ARE sorted - * in ascending order. - * - * ----------------------------------------------------------------------- - * A brief word about Third Eye naming/use conventions: - * - * All arrays and index's are 0 based. - * All "ifooMax" values are the highest legal value PLUS ONE. This makes - * them good for allocating arrays, etc. All checks are "ifoo < ifooMax". - * - * "isym" Index into the SYMbol table. - * "ipd" Index into the Procedure Descriptor array. - * "ifd" Index into the File Descriptor array. - * "iss" Index into String Space. - * "cb" Count of Bytes. - * "rgPd" array whose domain is "0..ipdMax-1" and RanGe is PDR. - * "rgFd" array whose domain is "0..ifdMax-1" and RanGe is FDR. - */ - - -/* - * Symbolic Header (HDR) structure. - * As long as all the pointers are set correctly, - * we don't care WHAT order the various sections come out in! - * - * A file produced solely for the use of CDB will probably NOT have - * any instructions or data areas in it, as these are available - * in the original. - */ - -typedef struct ecoff_symhdr { - coff_short magic; /* to verify validity of the table */ - coff_short vstamp; /* version stamp */ - coff_int ilineMax; /* number of line number entries */ - coff_int idnMax; /* max index into dense number table */ - coff_int ipdMax; /* number of procedures */ - coff_int isymMax; /* number of local symbols */ - coff_int ioptMax; /* max index into optimization symbol entries */ - coff_int iauxMax; /* number of auxillary symbol entries */ - coff_int issMax; /* max index into local strings */ - coff_int issExtMax; /* max index into external strings */ - coff_int ifdMax; /* number of file descriptor entries */ - coff_int crfd; /* number of relative file descriptor entries */ - coff_int iextMax; /* max index into external symbols */ - coff_addr cbLine; /* number of bytes for line number entries */ - coff_addr cbLineOffset; /* offset to start of line number entries*/ - coff_addr cbDnOffset; /* offset to start dense number table */ - coff_addr cbPdOffset; /* offset to procedure descriptor table */ - coff_addr cbSymOffset; /* offset to start of local symbols*/ - coff_addr cbOptOffset; /* offset to optimization symbol entries */ - coff_addr cbAuxOffset; /* offset to start of auxillary symbol entries*/ - coff_addr cbSsOffset; /* offset to start of local strings */ - coff_addr cbSsExtOffset; /* offset to start of external strings */ - coff_addr cbFdOffset; /* offset to file descriptor table */ - coff_addr cbRfdOffset; /* offset to relative file descriptor table */ - coff_addr cbExtOffset; /* offset to start of external symbol entries*/ - /* If you add machine dependent fields, add them here */ -} HDRR, *pHDRR; -#define cbHDRR sizeof(HDRR) -#define hdrNil ((pHDRR)0) - -/* - * The FDR and PDR structures speed mapping of address <-> name. - * They are sorted in ascending memory order and are kept in - * memory by CDB at runtime. - */ - -/* - * File Descriptor - * - * There is one of these for EVERY FILE, whether compiled with - * full debugging symbols or not. The name of a file should be - * the path name given to the compiler. This allows the user - * to simply specify the names of the directories where the COMPILES - * were done, and we will be able to find their files. - * A field whose comment starts with "R - " indicates that it will be - * setup at runtime. - */ -typedef struct ecoff_fdr { - coff_addr adr; /* memory address of beginning of file */ - coff_addr cbLineOffset; /* byte offset from header for this file ln's */ - coff_addr cbLine; /* size of lines for this file */ - coff_addr cbSs; /* number of bytes in the ss */ - coff_int rss; /* file name (of source, if known) */ - coff_int issBase; /* file's string space */ - coff_int isymBase; /* beginning of symbols */ - coff_int csym; /* count file's of symbols */ - coff_int ilineBase; /* file's line symbols */ - coff_int cline; /* count of file's line symbols */ - coff_int ioptBase; /* file's optimization entries */ - coff_int copt; /* count of file's optimization entries */ - coff_int ipdFirst; /* start of procedures for this file */ - coff_int cpd; /* count of procedures for this file */ - coff_int iauxBase; /* file's auxiliary entries */ - coff_int caux; /* count of file's auxiliary entries */ - coff_int rfdBase; /* index into the file indirect table */ - coff_int crfd; /* count file indirect entries */ - unsigned lang: 5; /* language for this file */ - unsigned fMerge : 1; /* whether this file can be merged */ - unsigned fReadin : 1; /* true if it was read in (not just created) */ - unsigned fBigendian : 1;/* if set, was compiled on big endian machine */ - /* aux's will be in compile host's sex */ - unsigned glevel : 2; /* level this file was compiled with */ - unsigned reserved : 22; /* reserved for future use */ - coff_uint reserved2; -} FDR, *pFDR; -#define cbFDR sizeof(FDR) -#define fdNil ((pFDR)0) -#define ifdNil -1 -#define ifdTemp 0 -#define ilnNil -1 - - -/* - * Procedure Descriptor - * - * There is one of these for EVERY TEXT LABEL. - * If a procedure is in a file with full symbols, then isym - * will point to the PROC symbols, else it will point to the - * global symbol for the label. - */ - -typedef struct pdr { - coff_addr adr; /* memory address of start of procedure */ - coff_addr cbLineOffset; /* byte offset for this procedure from the fd base */ - coff_int isym; /* start of local symbol entries */ - coff_int iline; /* start of line number entries*/ - coff_uint regmask; /* save register mask */ - coff_int regoffset; /* save register offset */ - coff_int iopt; /* start of optimization symbol entries*/ - coff_uint fregmask; /* save floating point register mask */ - coff_int fregoffset; /* save floating point register offset */ - coff_int frameoffset; /* frame size */ - coff_int lnLow; /* lowest line in the procedure */ - coff_int lnHigh; /* highest line in the procedure */ - /* These fields are new for 64 bit ECOFF. */ - unsigned gp_prologue : 8; /* byte size of GP prologue */ - unsigned gp_used : 1; /* true if the procedure uses GP */ - unsigned reg_frame : 1; /* true if register frame procedure */ - unsigned prof : 1; /* true if compiled with -pg */ - unsigned reserved : 13; /* reserved: must be zero */ - unsigned localoff : 8; /* offset of local variables from vfp */ - coff_short framereg; /* frame pointer register */ - coff_short pcreg; /* offset or reg of return pc */ -} PDR, *pPDR; -#define cbPDR sizeof(PDR) -#define pdNil ((pPDR) 0) -#define ipdNil -1 - -/* - * The structure of the runtime procedure descriptor created by the loader - * for use by the static exception system. - */ -/* - * If 0'd out because exception_info chokes Visual C++ and because there - * don't seem to be any references to this structure elsewhere in gdb. - */ -#if 0 -typedef struct runtime_pdr { - coff_addr adr; /* memory address of start of procedure */ - coff_uint regmask; /* save register mask */ - coff_int regoffset; /* save register offset */ - coff_uint fregmask; /* save floating point register mask */ - coff_int fregoffset; /* save floating point register offset */ - coff_int frameoffset; /* frame size */ - coff_ushort framereg; /* frame pointer register */ - coff_ushort pcreg; /* offset or reg of return pc */ - coff_int irpss; /* index into the runtime string table */ - coff_uint reserved; - struct exception_info *exception_info;/* pointer to exception array */ -} RPDR, *pRPDR; -#define cbRPDR sizeof(RPDR) -#define rpdNil ((pRPDR) 0) -#endif - -/* - * Line Numbers - * - * Line Numbers are segregated from the normal symbols because they - * are [1] smaller , [2] are of no interest to your - * average loader, and [3] are never needed in the middle of normal - * scanning and therefore slow things down. - * - * By definition, the first LINER for any given procedure will have - * the first line of a procedure and represent the first address. - */ - -typedef coff_int LINER, *pLINER; -#define lineNil ((pLINER)0) -#define cbLINER sizeof(LINER) -#define ilineNil -1 - - - -/* - * The Symbol Structure (GFW, to those who Know!) - */ - -typedef struct ecoff_sym { - coff_long value; /* value of symbol */ - coff_int iss; /* index into String Space of name */ - unsigned st : 6; /* symbol type */ - unsigned sc : 5; /* storage class - text, data, etc */ - unsigned reserved : 1; /* reserved */ - unsigned index : 20; /* index into sym/aux table */ -} SYMR, *pSYMR; -#define symNil ((pSYMR)0) -#define cbSYMR sizeof(SYMR) -#define isymNil -1 -#define indexNil 0xfffff -#define issNil -1 -#define issNull 0 - - -/* The following converts a memory resident string to an iss. - * This hack is recognized in SbFIss, in sym.c of the debugger. - */ -#define IssFSb(sb) (0x80000000 | ((coff_ulong)(sb))) - -/* E X T E R N A L S Y M B O L R E C O R D - * - * Same as the SYMR except it contains file context to determine where - * the index is. - */ -typedef struct ecoff_extsym { - SYMR asym; /* symbol for the external */ - unsigned jmptbl:1; /* symbol is a jump table entry for shlibs */ - unsigned cobol_main:1; /* symbol is a cobol main procedure */ - unsigned weakext:1; /* symbol is weak external */ - unsigned reserved:29; /* reserved for future use */ - coff_int ifd; /* where the iss and index fields point into */ -} EXTR, *pEXTR; -#define extNil ((pEXTR)0) -#define cbEXTR sizeof(EXTR) - - -/* A U X I L L A R Y T Y P E I N F O R M A T I O N */ - -/* - * Type Information Record - */ -typedef struct { - unsigned fBitfield : 1; /* set if bit width is specified */ - unsigned continued : 1; /* indicates additional TQ info in next AUX */ - unsigned bt : 6; /* basic type */ - unsigned tq4 : 4; - unsigned tq5 : 4; - /* ---- 16 bit boundary ---- */ - unsigned tq0 : 4; - unsigned tq1 : 4; /* 6 type qualifiers - tqPtr, etc. */ - unsigned tq2 : 4; - unsigned tq3 : 4; -} TIR, *pTIR; -#define cbTIR sizeof(TIR) -#define tiNil ((pTIR)0) -#define itqMax 6 - -/* - * Relative symbol record - * - * If the rfd field is 4095, the index field indexes into the global symbol - * table. - */ - -typedef struct { - unsigned rfd : 12; /* index into the file indirect table */ - unsigned index : 20; /* index int sym/aux/iss tables */ -} RNDXR, *pRNDXR; -#define cbRNDXR sizeof(RNDXR) -#define rndxNil ((pRNDXR)0) - -/* dense numbers or sometimes called block numbers are stored in this type, - * a rfd of 0xffffffff is an index into the global table. - */ -typedef struct { - coff_uint rfd; /* index into the file table */ - coff_uint index; /* index int sym/aux/iss tables */ -} DNR, *pDNR; -#define cbDNR sizeof(DNR) -#define dnNil ((pDNR)0) - - - -/* - * Auxillary information occurs only if needed. - * It ALWAYS occurs in this order when present. - - isymMac used by stProc only - TIR type info - TIR additional TQ info (if first TIR was not enough) - rndx if (bt == btStruct,btUnion,btEnum,btSet,btRange, - btTypedef): - rsym.index == iaux for btSet or btRange - else rsym.index == isym - dimLow btRange, btSet - dimMac btRange, btSet - rndx0 As many as there are tq arrays - dimLow0 - dimHigh0 - ... - rndxMax-1 - dimLowMax-1 - dimHighMax-1 - width in bits if (bit field), width in bits. - */ -#define cAuxMax (6 + (idimMax*3)) - -/* a union of all possible info in the AUX universe */ -typedef union { - TIR ti; /* type information record */ - RNDXR rndx; /* relative index into symbol table */ - coff_int dnLow; /* low dimension */ - coff_int dnHigh; /* high dimension */ - coff_int isym; /* symbol table index (end of proc) */ - coff_int iss; /* index into string space (not used) */ - coff_int width; /* width for non-default sized struc fields */ - coff_int count; /* count of ranges for variant arm */ -} AUXU, *pAUXU; -#define cbAUXU sizeof(AUXU) -#define auxNil ((pAUXU)0) -#define iauxNil -1 - - -/* - * Optimization symbols - * - * Optimization symbols contain some overlap information with the normal - * symbol table. In particular, the proc information - * is somewhat redundant but necessary to easily find the other information - * present. - * - * All of the offsets are relative to the beginning of the last otProc - */ - -typedef struct { - unsigned ot: 8; /* optimization type */ - unsigned value: 24; /* address where we are moving it to */ - RNDXR rndx; /* points to a symbol or opt entry */ - coff_ulong offset; /* relative offset this occured */ -} OPTR, *pOPTR; -#define optNil ((pOPTR) 0) -#define cbOPTR sizeof(OPTR) -#define ioptNil -1 - -/* - * File Indirect - * - * When a symbol is referenced across files the following procedure is used: - * 1) use the file index to get the File indirect entry. - * 2) use the file indirect entry to get the File descriptor. - * 3) add the sym index to the base of that file's sym table - * - */ - -typedef coff_long RFDT, *pRFDT; -#define cbRFDT sizeof(RFDT) -#define rfdNil -1 - -/* - * The file indirect table in the mips loader is known as an array of FITs. - * This is done to keep the code in the loader readable in the area where - * these tables are merged. Note this is only a name change. - */ -typedef coff_int FIT, *pFIT; -#define cbFIT sizeof(FIT) -#define ifiNil -1 -#define fiNil ((pFIT) 0) - -#ifdef _LANGUAGE_PASCAL -#define ifdNil -1 -#define ilnNil -1 -#define ipdNil -1 -#define ilineNil -1 -#define isymNil -1 -#define indexNil 16#fffff -#define issNil -1 -#define issNull 0 -#define itqMax 6 -#define iauxNil -1 -#define ioptNil -1 -#define rfdNil -1 -#define ifiNil -1 -#endif /* _LANGUAGE_PASCAL */ - - -/* Dense numbers - * - * Rather than use file index, symbol index pairs to represent symbols - * and globals, we use dense number so that they can be easily embeded - * in intermediate code and the programs that process them can - * use direct access tabls instead of hash table (which would be - * necesary otherwise because of the sparse name space caused by - * file index, symbol index pairs. Dense number are represented - * by RNDXRs. - */ - -/* - * The following table defines the meaning of each SYM field as - * a function of the "st". (scD/B == scData OR scBss) - * - * Note: the value "isymMac" is used by symbols that have the concept - * of enclosing a block of related information. This value is the - * isym of the first symbol AFTER the end associated with the primary - * symbol. For example if a procedure was at isym==90 and had an - * isymMac==155, the associated end would be at isym==154, and the - * symbol at 155 would probably (although not necessarily) be the - * symbol for the next procedure. This allows rapid skipping over - * internal information of various sorts. "stEnd"s ALWAYS have the - * isym of the primary symbol that started the block. - * - -ST SC VALUE INDEX --------- ------ -------- ------ -stFile scText address isymMac -stLabel scText address --- -stGlobal scD/B address iaux -stStatic scD/B address iaux -stParam scAbs offset iaux -stLocal scAbs offset iaux -stProc scText address iaux (isymMac is first AUX) -stStaticProc scText address iaux (isymMac is first AUX) - -stMember scNil ordinal --- (if member of enum) - (mipsread thinks the case below has a bit, not byte, offset.) -stMember scNil byte offset iaux (if member of struct/union) -stMember scBits bit offset iaux (bit field spec) - -stBlock scText address isymMac (text block) - (the code seems to think that rather than scNil, we see scInfo for - the two cases below.) -stBlock scNil cb isymMac (struct/union member define) -stBlock scNil cMembers isymMac (enum member define) - - (New types added by SGI to simplify things:) -stStruct scInfo cb isymMac (struct type define) -stUnion scInfo cb isymMac (union type define) -stEnum scInfo cMembers isymMac (enum type define) - -stEnd scText address isymStart -stEnd scNil ------- isymStart (struct/union/enum) - -stTypedef scNil ------- iaux -stRegReloc sc??? value old register number -stForward sc??? new address isym to original symbol - -stConstant scInfo value --- (scalar) -stConstant scInfo iss --- (complex, e.g. string) - - * - */ -#endif diff --git a/base/loader/coff_symconst.h b/base/loader/coff_symconst.h deleted file mode 100644 index 87bace02d..000000000 --- a/base/loader/coff_symconst.h +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Taken from binutils-2.14.90.0.5 include/coff/symconst.h - */ - -/* Declarations of constants for internal format of MIPS ECOFF symbols. - Originally contributed by MIPS Computer Systems and Third Eye Software. - Changes contributed by Cygnus Support are in the public domain. - - This file is just aggregated with the files that make up the GNU - release; it is not considered part of GAS, GDB, or other GNU - programs. */ - -/* - * |-----------------------------------------------------------| - * | Copyright (c) 1992, 1991, 1990 MIPS Computer Systems, Inc.| - * | MIPS Computer Systems, Inc. grants reproduction and use | - * | rights to all parties, PROVIDED that this comment is | - * | maintained in the copy. | - * |-----------------------------------------------------------| - */ - -/* (C) Copyright 1984 by Third Eye Software, Inc. - * - * Third Eye Software, Inc. grants reproduction and use rights to - * all parties, PROVIDED that this comment is maintained in the copy. - * - * Third Eye makes no claims about the applicability of this - * symbol table to a particular use. - */ - -/* glevels for field in FDR */ -#define GLEVEL_0 2 -#define GLEVEL_1 1 -#define GLEVEL_2 0 /* for upward compat reasons. */ -#define GLEVEL_3 3 - -/* magic number fo symheader */ -#define magicSym 0x7009 -/* The Alpha uses this value instead, for some reason. */ -#define magicSym2 0x1992 - -/* Language codes */ -#define langC 0 -#define langPascal 1 -#define langFortran 2 -#define langAssembler 3 /* one Assembley inst might map to many mach */ -#define langMachine 4 -#define langNil 5 -#define langAda 6 -#define langPl1 7 -#define langCobol 8 -#define langStdc 9 /* FIXME: Collides with SGI langCplusplus */ -#define langCplusplus 9 /* FIXME: Collides with langStdc */ -#define langCplusplusV2 10 /* SGI addition */ -#define langMax 11 /* maximun allowed 32 -- 5 bits */ - -/* The following are value definitions for the fields in the SYMR */ - -/* - * Storage Classes - */ - -#define scNil 0 -#define scText 1 /* text symbol */ -#define scData 2 /* initialized data symbol */ -#define scBss 3 /* un-initialized data symbol */ -#define scRegister 4 /* value of symbol is register number */ -#define scAbs 5 /* value of symbol is absolute */ -#define scUndefined 6 /* who knows? */ -#define scCdbLocal 7 /* variable's value is IN se->va.?? */ -#define scBits 8 /* this is a bit field */ -#define scCdbSystem 9 /* variable's value is IN CDB's address space */ -#define scDbx 9 /* overlap dbx internal use */ -#define scRegImage 10 /* register value saved on stack */ -#define scInfo 11 /* symbol contains debugger information */ -#define scUserStruct 12 /* address in struct user for current process */ -#define scSData 13 /* load time only small data */ -#define scSBss 14 /* load time only small common */ -#define scRData 15 /* load time only read only data */ -#define scVar 16 /* Var parameter (fortran,pascal) */ -#define scCommon 17 /* common variable */ -#define scSCommon 18 /* small common */ -#define scVarRegister 19 /* Var parameter in a register */ -#define scVariant 20 /* Variant record */ -#define scSUndefined 21 /* small undefined(external) data */ -#define scInit 22 /* .init section symbol */ -#define scBasedVar 23 /* Fortran or PL/1 ptr based var */ -#define scXData 24 /* exception handling data */ -#define scPData 25 /* Procedure section */ -#define scFini 26 /* .fini section */ -#define scRConst 27 /* .rconst section */ -#define scMax 32 - - -/* - * Symbol Types - */ - -#define stNil 0 /* Nuthin' special */ -#define stGlobal 1 /* external symbol */ -#define stStatic 2 /* static */ -#define stParam 3 /* procedure argument */ -#define stLocal 4 /* local variable */ -#define stLabel 5 /* label */ -#define stProc 6 /* " " Procedure */ -#define stBlock 7 /* beginnning of block */ -#define stEnd 8 /* end (of anything) */ -#define stMember 9 /* member (of anything - struct/union/enum */ -#define stTypedef 10 /* type definition */ -#define stFile 11 /* file name */ -#define stRegReloc 12 /* register relocation */ -#define stForward 13 /* forwarding address */ -#define stStaticProc 14 /* load time only static procs */ -#define stConstant 15 /* const */ -#define stStaParam 16 /* Fortran static parameters */ - /* These new symbol types have been recently added to SGI machines. */ -#define stStruct 26 /* Beginning of block defining a struct type */ -#define stUnion 27 /* Beginning of block defining a union type */ -#define stEnum 28 /* Beginning of block defining an enum type */ -#define stIndirect 34 /* Indirect type specification */ - /* Pseudo-symbols - internal to debugger */ -#define stStr 60 /* string */ -#define stNumber 61 /* pure number (ie. 4 NOR 2+2) */ -#define stExpr 62 /* 2+2 vs. 4 */ -#define stType 63 /* post-coersion SER */ -#define stMax 64 - -/* definitions for fields in TIR */ - -/* type qualifiers for ti.tq0 -> ti.(itqMax-1) */ -#define tqNil 0 /* bt is what you see */ -#define tqPtr 1 /* pointer */ -#define tqProc 2 /* procedure */ -#define tqArray 3 /* duh */ -#define tqFar 4 /* longer addressing - 8086/8 land */ -#define tqVol 5 /* volatile */ -#define tqConst 6 /* const */ -#define tqMax 8 - -/* basic types as seen in ti.bt */ -#define btNil 0 /* undefined (also, enum members) */ -#define btAdr 1 /* address - integer same size as pointer */ -#define btChar 2 /* character */ -#define btUChar 3 /* unsigned character */ -#define btShort 4 /* short */ -#define btUShort 5 /* unsigned short */ -#define btInt 6 /* int */ -#define btUInt 7 /* unsigned int */ -#define btLong 8 /* long */ -#define btULong 9 /* unsigned long */ -#define btFloat 10 /* float (real) */ -#define btDouble 11 /* Double (real) */ -#define btStruct 12 /* Structure (Record) */ -#define btUnion 13 /* Union (variant) */ -#define btEnum 14 /* Enumerated */ -#define btTypedef 15 /* defined via a typedef, isymRef points */ -#define btRange 16 /* subrange of int */ -#define btSet 17 /* pascal sets */ -#define btComplex 18 /* fortran complex */ -#define btDComplex 19 /* fortran double complex */ -#define btIndirect 20 /* forward or unnamed typedef */ -#define btFixedDec 21 /* Fixed Decimal */ -#define btFloatDec 22 /* Float Decimal */ -#define btString 23 /* Varying Length Character String */ -#define btBit 24 /* Aligned Bit String */ -#define btPicture 25 /* Picture */ -#define btVoid 26 /* void */ -#define btLongLong 27 /* long long */ -#define btULongLong 28 /* unsigned long long */ -#define btMax 64 diff --git a/base/loader/ecoff_object.cc b/base/loader/ecoff_object.cc deleted file mode 100644 index 353a5f333..000000000 --- a/base/loader/ecoff_object.cc +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <string> - -#include "base/loader/ecoff_object.hh" - -#include "mem/functional/functional.hh" -#include "base/loader/symtab.hh" - -#include "base/trace.hh" // for DPRINTF - -#include "base/loader/exec_ecoff.h" -#include "base/loader/coff_sym.h" -#include "base/loader/coff_symconst.h" - -using namespace std; - -ObjectFile * -EcoffObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data) -{ - if (((ecoff_filehdr *)data)->f_magic == ECOFF_MAGIC_ALPHA) { - // it's Alpha ECOFF - return new EcoffObject(fname, fd, len, data, - ObjectFile::Alpha, ObjectFile::Tru64); - } - else { - return NULL; - } -} - - -EcoffObject::EcoffObject(const string &_filename, int _fd, - size_t _len, uint8_t *_data, - Arch _arch, OpSys _opSys) - : ObjectFile(_filename, _fd, _len, _data, _arch, _opSys) -{ - execHdr = (ecoff_exechdr *)fileData; - fileHdr = &(execHdr->f); - aoutHdr = &(execHdr->a); - - entry = aoutHdr->entry; - - text.baseAddr = aoutHdr->text_start; - text.size = aoutHdr->tsize; - - data.baseAddr = aoutHdr->data_start; - data.size = aoutHdr->dsize; - - bss.baseAddr = aoutHdr->bss_start; - bss.size = aoutHdr->bsize; - - DPRINTFR(Loader, "text: 0x%x %d\ndata: 0x%x %d\nbss: 0x%x %d\n", - text.baseAddr, text.size, data.baseAddr, data.size, - bss.baseAddr, bss.size); -} - - -bool -EcoffObject::loadSections(FunctionalMemory *mem, bool loadPhys) -{ - Addr textAddr = text.baseAddr; - Addr dataAddr = data.baseAddr; - - if (loadPhys) { - textAddr &= (ULL(1) << 40) - 1; - dataAddr &= (ULL(1) << 40) - 1; - } - - // Since we don't really have an MMU and all memory is - // zero-filled, there's no need to set up the BSS segment. - mem->prot_write(textAddr, fileData + ECOFF_TXTOFF(execHdr), text.size); - mem->prot_write(dataAddr, fileData + ECOFF_DATOFF(execHdr), data.size); - - return true; -} - - -bool -EcoffObject::loadGlobalSymbols(SymbolTable *symtab) -{ - if (!symtab) - return false; - - if (fileHdr->f_magic != ECOFF_MAGIC_ALPHA) { - warn("loadGlobalSymbols: wrong magic on %s\n", filename); - return false; - } - - ecoff_symhdr *syms = (ecoff_symhdr *)(fileData + fileHdr->f_symptr); - if (syms->magic != magicSym2) { - warn("loadGlobalSymbols: bad symbol header magic on %s\n", filename); - return false; - } - - ecoff_extsym *ext_syms = (ecoff_extsym *)(fileData + syms->cbExtOffset); - - char *ext_strings = (char *)(fileData + syms->cbSsExtOffset); - for (int i = 0; i < syms->iextMax; i++) { - ecoff_sym *entry = &(ext_syms[i].asym); - if (entry->iss != -1) - symtab->insert(entry->value, ext_strings + entry->iss); - } - - return true; -} - -bool -EcoffObject::loadLocalSymbols(SymbolTable *symtab) -{ - if (!symtab) - return false; - - if (fileHdr->f_magic != ECOFF_MAGIC_ALPHA) { - warn("loadGlobalSymbols: wrong magic on %s\n", filename); - return false; - } - - ecoff_symhdr *syms = (ecoff_symhdr *)(fileData + fileHdr->f_symptr); - if (syms->magic != magicSym2) { - warn("loadGlobalSymbols: bad symbol header magic on %s\n", filename); - return false; - } - - ecoff_sym *local_syms = (ecoff_sym *)(fileData + syms->cbSymOffset); - char *local_strings = (char *)(fileData + syms->cbSsOffset); - ecoff_fdr *fdesc = (ecoff_fdr *)(fileData + syms->cbFdOffset); - - for (int i = 0; i < syms->ifdMax; i++) { - ecoff_sym *entry = (ecoff_sym *)(local_syms + fdesc[i].isymBase); - char *strings = (char *)(local_strings + fdesc[i].issBase); - for (int j = 0; j < fdesc[i].csym; j++) { - if (entry[j].st == stGlobal || entry[j].st == stProc) - if (entry[j].iss != -1) - symtab->insert(entry[j].value, strings + entry[j].iss); - } - } - - for (int i = 0; i < syms->isymMax; i++) { - ecoff_sym *entry = &(local_syms[i]); - if (entry->st == stProc) - symtab->insert(entry->value, local_strings + entry->iss); - } - - return true; -} diff --git a/base/loader/ecoff_object.hh b/base/loader/ecoff_object.hh deleted file mode 100644 index 78aa7f3f7..000000000 --- a/base/loader/ecoff_object.hh +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __ECOFF_OBJECT_HH__ -#define __ECOFF_OBJECT_HH__ - -#include "base/loader/object_file.hh" - -// forward decls: avoid including exec_ecoff.h here -struct ecoff_exechdr; -struct ecoff_filehdr; -struct ecoff_aouthdr; - -class EcoffObject : public ObjectFile -{ - protected: - ecoff_exechdr *execHdr; - ecoff_filehdr *fileHdr; - ecoff_aouthdr *aoutHdr; - - EcoffObject(const std::string &_filename, int _fd, - size_t _len, uint8_t *_data, - Arch _arch, OpSys _opSys); - - public: - virtual ~EcoffObject() {} - - virtual bool loadSections(FunctionalMemory *mem, - bool loadPhys = false); - virtual bool loadGlobalSymbols(SymbolTable *symtab); - virtual bool loadLocalSymbols(SymbolTable *symtab); - - static ObjectFile *tryFile(const std::string &fname, int fd, - size_t len, uint8_t *data); -}; - -#endif // __ECOFF_OBJECT_HH__ diff --git a/base/loader/elf_object.cc b/base/loader/elf_object.cc deleted file mode 100644 index 791c6f6de..000000000 --- a/base/loader/elf_object.cc +++ /dev/null @@ -1,331 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <string> - -// Because of the -Wundef flag we have to do this -#define __LIBELF_INTERNAL__ 0 -// counterintuitive, but the flag below causes libelf to define -// 64-bit elf types that apparently didn't exist in some older -// versions of Linux. They seem to be there in 2.4.x, so don't -// set this now (it causes things to break on 64-bit platforms). -#define __LIBELF64_LINUX 0 -#define __LIBELF_NEED_LINK_H 0 -#define __LIBELF_SYMBOL_VERSIONS 0 - -#include "libelf/libelf.h" -#include "libelf/gelf.h" - -#include "base/loader/elf_object.hh" - -#include "mem/functional/functional.hh" -#include "base/loader/symtab.hh" - -#include "base/trace.hh" // for DPRINTF - - -using namespace std; - -ObjectFile * -ElfObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data) -{ - Elf *elf; - GElf_Ehdr ehdr; - Arch arch = UnknownArch; - OpSys opSys = UnknownOpSys; - - // check that header matches library version - if (elf_version(EV_CURRENT) == EV_NONE) - panic("wrong elf version number!"); - - // get a pointer to elf structure - elf = elf_memory((char*)data,len); - // will only fail if fd is invalid - assert(elf != NULL); - - // Check that we actually have a elf file - if (gelf_getehdr(elf, &ehdr) ==0) { - DPRINTFR(Loader, "Not ELF\n"); - elf_end(elf); - return NULL; - } - else { - //Detect the architecture - //Versioning issues in libelf need to be resolved to get the correct - //SPARC constants. - //If MIPS supports 32 bit executables, this may need to be changed. - //Also, there are other MIPS constants which may be used, like - //EM_MIPS_RS3_LE and EM_MIPS_X - //Since we don't know how to check for alpha right now, we'll - //just assume if it wasn't something else and it's 64 bit, that's - //what it must be. - if (ehdr.e_machine == EM_SPARC64 || - ehdr.e_machine == EM_SPARC || - ehdr.e_machine == EM_SPARCV9) { - arch = ObjectFile::SPARC; - } else if (ehdr.e_machine == EM_MIPS - && ehdr.e_ident[EI_CLASS] == ELFCLASS32) { - arch = ObjectFile::MIPS; - } else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) { - arch = ObjectFile::Alpha; - } else { - arch = ObjectFile::UnknownArch; - } - - //Detect the operating system - switch (ehdr.e_ident[EI_OSABI]) - { - - case ELFOSABI_LINUX: - opSys = ObjectFile::Linux; - break; - case ELFOSABI_SOLARIS: - opSys = ObjectFile::Solaris; - break; - case ELFOSABI_TRU64: - opSys = ObjectFile::Tru64; - break; - default: - opSys = ObjectFile::UnknownOpSys; - } - - //take a look at the .note.ABI section - //It can let us know what's what. - if (opSys == ObjectFile::UnknownOpSys) - { - Elf_Scn *section; - GElf_Shdr shdr; - Elf_Data *data; - uint32_t osAbi;; - int secIdx = 1; - - // Get the first section - section = elf_getscn(elf, secIdx); - - // While there are no more sections - while (section != NULL) { - gelf_getshdr(section, &shdr); - if (shdr.sh_type == SHT_NOTE && !strcmp(".note.ABI-tag", - elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name))) { - // we have found a ABI note section - // Check the 5th 32bit word for OS 0 == linux, 1 == hurd, - // 2 == solaris, 3 == freebsd - data = elf_rawdata(section, NULL); - assert(data->d_buf); - if(ehdr.e_ident[EI_DATA] == ELFDATA2LSB) - osAbi = htole(((uint32_t*)data->d_buf)[4]); - else - osAbi = htobe(((uint32_t*)data->d_buf)[4]); - - switch(osAbi) { - case 0: - opSys = ObjectFile::Linux; - break; - case 2: - opSys = ObjectFile::Solaris; - break; - } - } // if section found - section = elf_getscn(elf, ++secIdx); - } // while sections - } - elf_end(elf); - return new ElfObject(fname, fd, len, data, arch, opSys); - } -} - - -ElfObject::ElfObject(const string &_filename, int _fd, - size_t _len, uint8_t *_data, - Arch _arch, OpSys _opSys) - : ObjectFile(_filename, _fd, _len, _data, _arch, _opSys) - -{ - Elf *elf; - GElf_Ehdr ehdr; - - // check that header matches library version - if (elf_version(EV_CURRENT) == EV_NONE) - panic("wrong elf version number!"); - - // get a pointer to elf structure - elf = elf_memory((char*)fileData,len); - // will only fail if fd is invalid - assert(elf != NULL); - - // Check that we actually have a elf file - if (gelf_getehdr(elf, &ehdr) ==0) { - panic("Not ELF, shouldn't be here"); - } - - entry = ehdr.e_entry; - - // initialize segment sizes to 0 in case they're not present - text.size = data.size = bss.size = 0; - - for (int i = 0; i < ehdr.e_phnum; ++i) { - GElf_Phdr phdr; - if (gelf_getphdr(elf, i, &phdr) == 0) { - panic("gelf_getphdr failed for section %d", i); - } - - // for now we don't care about non-loadable segments - if (!(phdr.p_type & PT_LOAD)) - continue; - - // the headers don't explicitly distinguish text from data, - // but empirically the text segment comes first. - if (text.size == 0) { // haven't seen text segment yet - text.baseAddr = phdr.p_vaddr; - text.size = phdr.p_filesz; - // remember where the data is for loadSections() - fileTextBits = fileData + phdr.p_offset; - // if there's any padding at the end that's not in the - // file, call it the bss. This happens in the "text" - // segment if there's only one loadable segment (as for - // kernel images). - bss.size = phdr.p_memsz - phdr.p_filesz; - bss.baseAddr = phdr.p_vaddr + phdr.p_filesz; - } - else if (data.size == 0) { // have text, this must be data - data.baseAddr = phdr.p_vaddr; - data.size = phdr.p_filesz; - // remember where the data is for loadSections() - fileDataBits = fileData + phdr.p_offset; - // if there's any padding at the end that's not in the - // file, call it the bss. Warn if this happens for both - // the text & data segments (should only have one bss). - if (phdr.p_memsz - phdr.p_filesz > 0 && bss.size != 0) { - warn("Two implied bss segments in file!\n"); - } - bss.size = phdr.p_memsz - phdr.p_filesz; - bss.baseAddr = phdr.p_vaddr + phdr.p_filesz; - } - } - - // should have found at least one loadable segment - assert(text.size != 0); - - DPRINTFR(Loader, "text: 0x%x %d\ndata: 0x%x %d\nbss: 0x%x %d\n", - text.baseAddr, text.size, data.baseAddr, data.size, - bss.baseAddr, bss.size); - - elf_end(elf); - - // We will actually read the sections when we need to load them -} - - -bool -ElfObject::loadSections(FunctionalMemory *mem, bool loadPhys) -{ - Addr textAddr = text.baseAddr; - Addr dataAddr = data.baseAddr; - - if (loadPhys) { - textAddr &= (ULL(1) << 40) - 1; - dataAddr &= (ULL(1) << 40) - 1; - } - - // Since we don't really have an MMU and all memory is - // zero-filled, there's no need to set up the BSS segment. - if (text.size != 0) - mem->prot_write(textAddr, fileTextBits, text.size); - if (data.size != 0) - mem->prot_write(dataAddr, fileDataBits, data.size); - - return true; -} - - -bool -ElfObject::loadSomeSymbols(SymbolTable *symtab, int binding) -{ - Elf *elf; - int sec_idx = 1; // there is a 0 but it is nothing, go figure - Elf_Scn *section; - GElf_Shdr shdr; - Elf_Data *data; - int count, ii; - bool found = false; - GElf_Sym sym; - - if (!symtab) - return false; - - // check that header matches library version - if (elf_version(EV_CURRENT) == EV_NONE) - panic("wrong elf version number!"); - - // get a pointer to elf structure - elf = elf_memory((char*)fileData,len); - - assert(elf != NULL); - - // Get the first section - section = elf_getscn(elf, sec_idx); - - // While there are no more sections - while (section != NULL) { - gelf_getshdr(section, &shdr); - - if (shdr.sh_type == SHT_SYMTAB) { - found = true; - data = elf_getdata(section, NULL); - count = shdr.sh_size / shdr.sh_entsize; - DPRINTF(Loader, "Found Symbol Table, %d symbols present\n", count); - - // loop through all the symbols, only loading global ones - for (ii = 0; ii < count; ++ii) { - gelf_getsym(data, ii, &sym); - if (GELF_ST_BIND(sym.st_info) == binding) { - symtab->insert(sym.st_value, - elf_strptr(elf, shdr.sh_link, sym.st_name)); - } - } - } - ++sec_idx; - section = elf_getscn(elf, sec_idx); - } - - elf_end(elf); - - return found; -} - -bool -ElfObject::loadGlobalSymbols(SymbolTable *symtab) -{ - return loadSomeSymbols(symtab, STB_GLOBAL); -} - -bool -ElfObject::loadLocalSymbols(SymbolTable *symtab) -{ - return loadSomeSymbols(symtab, STB_LOCAL); -} diff --git a/base/loader/elf_object.hh b/base/loader/elf_object.hh deleted file mode 100644 index 66d8b3e63..000000000 --- a/base/loader/elf_object.hh +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __ELF_OBJECT_HH__ -#define __ELF_OBJECT_HH__ - -#include "base/loader/object_file.hh" - -class ElfObject : public ObjectFile -{ - protected: - - uint8_t *fileTextBits; //!< Pointer to file's text segment image - uint8_t *fileDataBits; //!< Pointer to file's data segment image - - /// Helper functions for loadGlobalSymbols() and loadLocalSymbols(). - bool loadSomeSymbols(SymbolTable *symtab, int binding); - - ElfObject(const std::string &_filename, int _fd, - size_t _len, uint8_t *_data, - Arch _arch, OpSys _opSys); - - public: - virtual ~ElfObject() {} - - virtual bool loadSections(FunctionalMemory *mem, - bool loadPhys = false); - virtual bool loadGlobalSymbols(SymbolTable *symtab); - virtual bool loadLocalSymbols(SymbolTable *symtab); - - static ObjectFile *tryFile(const std::string &fname, int fd, - size_t len, uint8_t *data); -}; - -#endif // __ELF_OBJECT_HH__ diff --git a/base/loader/object_file.cc b/base/loader/object_file.cc deleted file mode 100644 index 1410d05b8..000000000 --- a/base/loader/object_file.cc +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2002-2004 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <list> -#include <string> - -#include <sys/types.h> -#include <sys/mman.h> -#include <fcntl.h> -#include <stdio.h> -#include <unistd.h> - -#include "base/cprintf.hh" -#include "base/loader/object_file.hh" -#include "base/loader/symtab.hh" - -#include "base/loader/ecoff_object.hh" -#include "base/loader/aout_object.hh" -#include "base/loader/elf_object.hh" - -using namespace std; - -ObjectFile::ObjectFile(const string &_filename, int _fd, - size_t _len, uint8_t *_data, - Arch _arch, OpSys _opSys) - : filename(_filename), descriptor(_fd), fileData(_data), len(_len), - arch(_arch), opSys(_opSys) -{ -} - - -ObjectFile::~ObjectFile() -{ - close(); -} - - -void -ObjectFile::close() -{ - if (descriptor >= 0) { - ::close(descriptor); - descriptor = -1; - } - - if (fileData) { - ::munmap(fileData, len); - fileData = NULL; - } -} - - -ObjectFile * -createObjectFile(const string &fname) -{ - // open the file - int fd = open(fname.c_str(), O_RDONLY); - if (fd < 0) { - return NULL; - } - - // find the length of the file by seeking to the end - size_t len = (size_t)lseek(fd, 0, SEEK_END); - - // mmap the whole shebang - uint8_t *fileData = - (uint8_t *)mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0); - if (fileData == MAP_FAILED) { - close(fd); - return NULL; - } - - ObjectFile *fileObj = NULL; - - // figure out what we have here - if ((fileObj = EcoffObject::tryFile(fname, fd, len, fileData)) != NULL) { - return fileObj; - } - - if ((fileObj = AoutObject::tryFile(fname, fd, len, fileData)) != NULL) { - return fileObj; - } - - if ((fileObj = ElfObject::tryFile(fname, fd, len, fileData)) != NULL) { - return fileObj; - } - - // don't know what it is - close(fd); - munmap(fileData, len); - return NULL; -} diff --git a/base/loader/object_file.hh b/base/loader/object_file.hh deleted file mode 100644 index 1b44ae14f..000000000 --- a/base/loader/object_file.hh +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 2002-2004 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __OBJECT_FILE_HH__ -#define __OBJECT_FILE_HH__ - -#include <string> - -#include "sim/host.hh" // for Addr - -class FunctionalMemory; -class SymbolTable; - -class ObjectFile -{ - public: - - enum Arch { - UnknownArch, - Alpha, - SPARC, - MIPS - }; - - enum OpSys { - UnknownOpSys, - Tru64, - Linux, - Solaris - }; - - protected: - const std::string filename; - int descriptor; - uint8_t *fileData; - size_t len; - - Arch arch; - OpSys opSys; - - ObjectFile(const std::string &_filename, int _fd, - size_t _len, uint8_t *_data, - Arch _arch, OpSys _opSys); - - public: - virtual ~ObjectFile(); - - void close(); - - virtual bool loadSections(FunctionalMemory *mem, - bool loadPhys = false) = 0; - virtual bool loadGlobalSymbols(SymbolTable *symtab) = 0; - virtual bool loadLocalSymbols(SymbolTable *symtab) = 0; - - Arch getArch() const { return arch; } - OpSys getOpSys() const { return opSys; } - - protected: - - struct Section { - Addr baseAddr; - size_t size; - }; - - Addr entry; - Addr globalPtr; - - Section text; - Section data; - Section bss; - - public: - Addr entryPoint() const { return entry; } - Addr globalPointer() const { return globalPtr; } - - Addr textBase() const { return text.baseAddr; } - Addr dataBase() const { return data.baseAddr; } - Addr bssBase() const { return bss.baseAddr; } - - size_t textSize() const { return text.size; } - size_t dataSize() const { return data.size; } - size_t bssSize() const { return bss.size; } -}; - -ObjectFile *createObjectFile(const std::string &fname); - - -#endif // __OBJECT_FILE_HH__ diff --git a/base/loader/symtab.hh b/base/loader/symtab.hh deleted file mode 100644 index ebcda1345..000000000 --- a/base/loader/symtab.hh +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright (c) 2002-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __SYMTAB_HH__ -#define __SYMTAB_HH__ - -#include <iosfwd> -#include <map> - -#include "arch/isa_traits.hh" // for Addr - -class Checkpoint; -class SymbolTable -{ - public: - typedef std::map<Addr, std::string> ATable; - typedef std::map<std::string, Addr> STable; - - private: - ATable addrTable; - STable symbolTable; - - private: - bool - upperBound(Addr addr, ATable::const_iterator &iter) const - { - // find first key *larger* than desired address - iter = addrTable.upper_bound(addr); - - // if very first key is larger, we're out of luck - if (iter == addrTable.begin()) - return false; - - return true; - } - - public: - SymbolTable() {} - SymbolTable(const std::string &file) { load(file); } - ~SymbolTable() {} - - void clear(); - bool insert(Addr address, std::string symbol); - bool load(const std::string &file); - - const ATable &getAddrTable() const { return addrTable; } - const STable &getSymbolTable() const { return symbolTable; } - - public: - void serialize(const std::string &base, std::ostream &os); - void unserialize(const std::string &base, Checkpoint *cp, - const std::string §ion); - - public: - bool - findSymbol(Addr address, std::string &symbol) const - { - ATable::const_iterator i = addrTable.find(address); - if (i == addrTable.end()) - return false; - - symbol = (*i).second; - return true; - } - - bool - findAddress(const std::string &symbol, Addr &address) const - { - STable::const_iterator i = symbolTable.find(symbol); - if (i == symbolTable.end()) - return false; - - address = (*i).second; - return true; - } - - /// Find the nearest symbol equal to or less than the supplied - /// address (e.g., the label for the enclosing function). - /// @param address The address to look up. - /// @param symbol Return reference for symbol string. - /// @param sym_address Return reference for symbol address. - /// @param next_sym_address Address of following symbol (for - /// determining valid range of symbol). - /// @retval True if a symbol was found. - bool - findNearestSymbol(Addr addr, std::string &symbol, Addr &symaddr, - Addr &nextaddr) const - { - ATable::const_iterator i; - if (!upperBound(addr, i)) - return false; - - nextaddr = i->first; - --i; - symaddr = i->first; - symbol = i->second; - return true; - } - - /// Overload for findNearestSymbol() for callers who don't care - /// about next_sym_address. - bool - findNearestSymbol(Addr addr, std::string &symbol, Addr &symaddr) const - { - ATable::const_iterator i; - if (!upperBound(addr, i)) - return false; - - --i; - symaddr = i->first; - symbol = i->second; - return true; - } - - - bool - findNearestAddr(Addr addr, Addr &symaddr, Addr &nextaddr) const - { - ATable::const_iterator i; - if (!upperBound(addr, i)) - return false; - - nextaddr = i->first; - --i; - symaddr = i->first; - return true; - } - - bool - findNearestAddr(Addr addr, Addr &symaddr) const - { - ATable::const_iterator i; - if (!upperBound(addr, i)) - return false; - - --i; - symaddr = i->first; - return true; - } -}; - -/// Global unified debugging symbol table (for target). Conceptually -/// there should be one of these per System object for full system, -/// and per Process object for non-full-system, but so far one big -/// global one has worked well enough. -extern SymbolTable *debugSymbolTable; - -#endif // __SYMTAB_HH__ diff --git a/base/remote_gdb.cc b/base/remote_gdb.cc deleted file mode 100644 index 84093459c..000000000 --- a/base/remote_gdb.cc +++ /dev/null @@ -1,1232 +0,0 @@ -/* - * Copyright (c) 2002-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This software was developed by the Computer Systems Engineering group - * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and - * contributed to Berkeley. - * - * All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Lawrence Berkeley Laboratories. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)kgdb_stub.c 8.4 (Berkeley) 1/12/94 - */ - -/*- - * Copyright (c) 2001 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Jason R. Thorpe. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * $NetBSD: kgdb_stub.c,v 1.8 2001/07/07 22:58:00 wdk Exp $ - * - * Taken from NetBSD - * - * "Stub" to allow remote cpu to debug over a serial line using gdb. - */ - -#include <sys/signal.h> - -#include <cstdio> -#include <string> -#include <unistd.h> - -#include "base/intmath.hh" -#include "base/kgdb.h" -#include "base/remote_gdb.hh" -#include "base/socket.hh" -#include "base/trace.hh" -#include "cpu/exec_context.hh" -#include "cpu/static_inst.hh" -#include "mem/functional/physical.hh" -#include "sim/system.hh" -#include "arch/vtophys.hh" - -using namespace std; -using namespace TheISA; - -#ifndef NDEBUG -vector<RemoteGDB *> debuggers; -int current_debugger = -1; - -void -debugger() -{ - if (current_debugger >= 0 && current_debugger < debuggers.size()) { - RemoteGDB *gdb = debuggers[current_debugger]; - if (!gdb->isattached()) - gdb->listener->accept(); - if (gdb->isattached()) - gdb->trap(ALPHA_KENTRY_IF); - } -} -#endif - -/////////////////////////////////////////////////////////// -// -// -// - -GDBListener::Event::Event(GDBListener *l, int fd, int e) - : PollEvent(fd, e), listener(l) -{} - -void -GDBListener::Event::process(int revent) -{ - listener->accept(); -} - -GDBListener::GDBListener(RemoteGDB *g, int p) - : event(NULL), gdb(g), port(p) -{ - assert(!gdb->listener); - gdb->listener = this; -} - -GDBListener::~GDBListener() -{ - if (event) - delete event; -} - -string -GDBListener::name() -{ - return gdb->name() + ".listener"; -} - -void -GDBListener::listen() -{ - while (!listener.listen(port, true)) { - DPRINTF(GDBMisc, "Can't bind port %d\n", port); - port++; - } - - event = new Event(this, listener.getfd(), POLLIN); - pollQueue.schedule(event); - -#ifndef NDEBUG - gdb->number = debuggers.size(); - debuggers.push_back(gdb); -#endif - -#ifndef NDEBUG - ccprintf(cerr, "%d: %s: listening for remote gdb #%d on port %d\n", - curTick, name(), gdb->number, port); -#else - ccprintf(cerr, "%d: %s: listening for remote gdb on port %d\n", - curTick, name(), port); -#endif -} - -void -GDBListener::accept() -{ - if (!listener.islistening()) - panic("GDBListener::accept(): cannot accept if we're not listening!"); - - int sfd = listener.accept(true); - - if (sfd != -1) { - if (gdb->isattached()) - close(sfd); - else - gdb->attach(sfd); - } -} - -/////////////////////////////////////////////////////////// -// -// -// -int digit2i(char); -char i2digit(int); -void mem2hex(void *, const void *, int); -const char *hex2mem(void *, const char *, int); -Addr hex2i(const char **); - -RemoteGDB::Event::Event(RemoteGDB *g, int fd, int e) - : PollEvent(fd, e), gdb(g) -{} - -void -RemoteGDB::Event::process(int revent) -{ - if (revent & POLLIN) - gdb->trap(ALPHA_KENTRY_IF); - else if (revent & POLLNVAL) - gdb->detach(); -} - -RemoteGDB::RemoteGDB(System *_system, ExecContext *c) - : event(NULL), listener(NULL), number(-1), fd(-1), - active(false), attached(false), - system(_system), pmem(_system->physmem), context(c) -{ - memset(gdbregs, 0, sizeof(gdbregs)); -} - -RemoteGDB::~RemoteGDB() -{ - if (event) - delete event; -} - -string -RemoteGDB::name() -{ - return system->name() + ".remote_gdb"; -} - -bool -RemoteGDB::isattached() -{ return attached; } - -void -RemoteGDB::attach(int f) -{ - fd = f; - - event = new Event(this, fd, POLLIN); - pollQueue.schedule(event); - - attached = true; - DPRINTFN("remote gdb attached\n"); -} - -void -RemoteGDB::detach() -{ - attached = false; - close(fd); - fd = -1; - - pollQueue.remove(event); - DPRINTFN("remote gdb detached\n"); -} - -const char * -gdb_command(char cmd) -{ - switch (cmd) { - case KGDB_SIGNAL: return "KGDB_SIGNAL"; - case KGDB_SET_BAUD: return "KGDB_SET_BAUD"; - case KGDB_SET_BREAK: return "KGDB_SET_BREAK"; - case KGDB_CONT: return "KGDB_CONT"; - case KGDB_ASYNC_CONT: return "KGDB_ASYNC_CONT"; - case KGDB_DEBUG: return "KGDB_DEBUG"; - case KGDB_DETACH: return "KGDB_DETACH"; - case KGDB_REG_R: return "KGDB_REG_R"; - case KGDB_REG_W: return "KGDB_REG_W"; - case KGDB_SET_THREAD: return "KGDB_SET_THREAD"; - case KGDB_CYCLE_STEP: return "KGDB_CYCLE_STEP"; - case KGDB_SIG_CYCLE_STEP: return "KGDB_SIG_CYCLE_STEP"; - case KGDB_KILL: return "KGDB_KILL"; - case KGDB_MEM_W: return "KGDB_MEM_W"; - case KGDB_MEM_R: return "KGDB_MEM_R"; - case KGDB_SET_REG: return "KGDB_SET_REG"; - case KGDB_READ_REG: return "KGDB_READ_REG"; - case KGDB_QUERY_VAR: return "KGDB_QUERY_VAR"; - case KGDB_SET_VAR: return "KGDB_SET_VAR"; - case KGDB_RESET: return "KGDB_RESET"; - case KGDB_STEP: return "KGDB_STEP"; - case KGDB_ASYNC_STEP: return "KGDB_ASYNC_STEP"; - case KGDB_THREAD_ALIVE: return "KGDB_THREAD_ALIVE"; - case KGDB_TARGET_EXIT: return "KGDB_TARGET_EXIT"; - case KGDB_BINARY_DLOAD: return "KGDB_BINARY_DLOAD"; - case KGDB_CLR_HW_BKPT: return "KGDB_CLR_HW_BKPT"; - case KGDB_SET_HW_BKPT: return "KGDB_SET_HW_BKPT"; - case KGDB_START: return "KGDB_START"; - case KGDB_END: return "KGDB_END"; - case KGDB_GOODP: return "KGDB_GOODP"; - case KGDB_BADP: return "KGDB_BADP"; - default: return "KGDB_UNKNOWN"; - } -} - -/////////////////////////////////////////////////////////// -// RemoteGDB::acc -// -// Determine if the mapping at va..(va+len) is valid. -// -bool -RemoteGDB::acc(Addr va, size_t len) -{ - Addr last_va; - - va = TheISA::TruncPage(va); - last_va = TheISA::RoundPage(va + len); - - do { - if (TheISA::IsK0Seg(va)) { - if (va < (TheISA::K0SegBase + pmem->size())) { - DPRINTF(GDBAcc, "acc: Mapping is valid K0SEG <= " - "%#x < K0SEG + size\n", va); - return true; - } else { - DPRINTF(GDBAcc, "acc: Mapping invalid %#x > K0SEG + size\n", - va); - return false; - } - } - - /** - * This code says that all accesses to palcode (instruction and data) - * are valid since there isn't a va->pa mapping because palcode is - * accessed physically. At some point this should probably be cleaned up - * but there is no easy way to do it. - */ - - if (AlphaISA::PcPAL(va) || va < 0x10000) - return true; - - Addr ptbr = context->readMiscReg(AlphaISA::IPR_PALtemp20); - TheISA::PageTableEntry pte = kernel_pte_lookup(pmem, ptbr, va); - if (!pte.valid()) { - DPRINTF(GDBAcc, "acc: %#x pte is invalid\n", va); - return false; - } - va += TheISA::PageBytes; - } while (va < last_va); - - DPRINTF(GDBAcc, "acc: %#x mapping is valid\n", va); - return true; -} - -/////////////////////////////////////////////////////////// -// RemoteGDB::signal -// -// Translate a trap number into a Unix-compatible signal number. -// (GDB only understands Unix signal numbers.) -// -int -RemoteGDB::signal(int type) -{ - switch (type) { - case ALPHA_KENTRY_INT: - return (SIGTRAP); - - case ALPHA_KENTRY_UNA: - return (SIGBUS); - - case ALPHA_KENTRY_ARITH: - return (SIGFPE); - - case ALPHA_KENTRY_IF: - return (SIGILL); - - case ALPHA_KENTRY_MM: - return (SIGSEGV); - - default: - panic("unknown signal type"); - return 0; - } -} - -/////////////////////////////////////////////////////////// -// RemoteGDB::getregs -// -// Translate the kernel debugger register format into -// the GDB register format. -void -RemoteGDB::getregs() -{ - memset(gdbregs, 0, sizeof(gdbregs)); - - gdbregs[KGDB_REG_PC] = context->readPC(); - - // @todo: Currently this is very Alpha specific. - if (AlphaISA::PcPAL(gdbregs[KGDB_REG_PC])) { - for (int i = 0; i < TheISA::NumIntArchRegs; ++i) { - gdbregs[i] = context->readIntReg(AlphaISA::reg_redir[i]); - } - } else { - for (int i = 0; i < TheISA::NumIntArchRegs; ++i) { - gdbregs[i] = context->readIntReg(i); - } - } - -#ifdef KGDB_FP_REGS - for (int i = 0; i < TheISA::NumFloatArchRegs; ++i) { - gdbregs[i + KGDB_REG_F0] = context->readFloatRegInt(i); - } -#endif -} - -/////////////////////////////////////////////////////////// -// RemoteGDB::setregs -// -// Translate the GDB register format into the kernel -// debugger register format. -// -void -RemoteGDB::setregs() -{ - // @todo: Currently this is very Alpha specific. - if (AlphaISA::PcPAL(gdbregs[KGDB_REG_PC])) { - for (int i = 0; i < TheISA::NumIntArchRegs; ++i) { - context->setIntReg(AlphaISA::reg_redir[i], gdbregs[i]); - } - } else { - for (int i = 0; i < TheISA::NumIntArchRegs; ++i) { - context->setIntReg(i, gdbregs[i]); - } - } - -#ifdef KGDB_FP_REGS - for (int i = 0; i < TheISA::NumFloatArchRegs; ++i) { - context->setFloatRegInt(i, gdbregs[i + KGDB_REG_F0]); - } -#endif - context->setPC(gdbregs[KGDB_REG_PC]); -} - -void -RemoteGDB::setTempBreakpoint(TempBreakpoint &bkpt, Addr addr) -{ - DPRINTF(GDBMisc, "setTempBreakpoint: addr=%#x\n", addr); - - bkpt.address = addr; - insertHardBreak(addr, 4); -} - -void -RemoteGDB::clearTempBreakpoint(TempBreakpoint &bkpt) -{ - DPRINTF(GDBMisc, "setTempBreakpoint: addr=%#x\n", - bkpt.address); - - - removeHardBreak(bkpt.address, 4); - bkpt.address = 0; -} - -void -RemoteGDB::clearSingleStep() -{ - DPRINTF(GDBMisc, "clearSingleStep bt_addr=%#x nt_addr=%#x\n", - takenBkpt.address, notTakenBkpt.address); - - if (takenBkpt.address != 0) - clearTempBreakpoint(takenBkpt); - - if (notTakenBkpt.address != 0) - clearTempBreakpoint(notTakenBkpt); -} - -void -RemoteGDB::setSingleStep() -{ - Addr pc = context->readPC(); - Addr npc, bpc; - bool set_bt = false; - - npc = pc + sizeof(MachInst); - - // User was stopped at pc, e.g. the instruction at pc was not - // executed. - MachInst inst = read<MachInst>(pc); - StaticInstPtr si(inst); - if (si->hasBranchTarget(pc, context, bpc)) { - // Don't bother setting a breakpoint on the taken branch if it - // is the same as the next pc - if (bpc != npc) - set_bt = true; - } - - DPRINTF(GDBMisc, "setSingleStep bt_addr=%#x nt_addr=%#x\n", - takenBkpt.address, notTakenBkpt.address); - - setTempBreakpoint(notTakenBkpt, npc); - - if (set_bt) - setTempBreakpoint(takenBkpt, bpc); -} - -///////////////////////// -// -// - -uint8_t -RemoteGDB::getbyte() -{ - uint8_t b; - ::read(fd, &b, 1); - return b; -} - -void -RemoteGDB::putbyte(uint8_t b) -{ - ::write(fd, &b, 1); -} - -// Send a packet to gdb -void -RemoteGDB::send(const char *bp) -{ - const char *p; - uint8_t csum, c; - - DPRINTF(GDBSend, "send: %s\n", bp); - - do { - p = bp; - putbyte(KGDB_START); - for (csum = 0; (c = *p); p++) { - putbyte(c); - csum += c; - } - putbyte(KGDB_END); - putbyte(i2digit(csum >> 4)); - putbyte(i2digit(csum)); - } while ((c = getbyte() & 0x7f) == KGDB_BADP); -} - -// Receive a packet from gdb -int -RemoteGDB::recv(char *bp, int maxlen) -{ - char *p; - int c, csum; - int len; - - do { - p = bp; - csum = len = 0; - while ((c = getbyte()) != KGDB_START) - ; - - while ((c = getbyte()) != KGDB_END && len < maxlen) { - c &= 0x7f; - csum += c; - *p++ = c; - len++; - } - csum &= 0xff; - *p = '\0'; - - if (len >= maxlen) { - putbyte(KGDB_BADP); - continue; - } - - csum -= digit2i(getbyte()) * 16; - csum -= digit2i(getbyte()); - - if (csum == 0) { - putbyte(KGDB_GOODP); - // Sequence present? - if (bp[2] == ':') { - putbyte(bp[0]); - putbyte(bp[1]); - len -= 3; - bcopy(bp + 3, bp, len); - } - break; - } - putbyte(KGDB_BADP); - } while (1); - - DPRINTF(GDBRecv, "recv: %s: %s\n", gdb_command(*bp), bp); - - return (len); -} - -// Read bytes from kernel address space for debugger. -bool -RemoteGDB::read(Addr vaddr, size_t size, char *data) -{ - static Addr lastaddr = 0; - static size_t lastsize = 0; - - uint8_t *maddr; - - if (vaddr < 10) { - DPRINTF(GDBRead, "read: reading memory location zero!\n"); - vaddr = lastaddr + lastsize; - } - - DPRINTF(GDBRead, "read: addr=%#x, size=%d", vaddr, size); -#if TRACING_ON - char *d = data; - size_t s = size; -#endif - - lastaddr = vaddr; - lastsize = size; - - size_t count = min((Addr)size, - VMPageSize - (vaddr & (VMPageSize - 1))); - - maddr = vtomem(context, vaddr, count); - memcpy(data, maddr, count); - - vaddr += count; - data += count; - size -= count; - - while (size >= VMPageSize) { - maddr = vtomem(context, vaddr, count); - memcpy(data, maddr, VMPageSize); - - vaddr += VMPageSize; - data += VMPageSize; - size -= VMPageSize; - } - - if (size > 0) { - maddr = vtomem(context, vaddr, count); - memcpy(data, maddr, size); - } - -#if TRACING_ON - if (DTRACE(GDBRead)) { - if (DTRACE(GDBExtra)) { - char buf[1024]; - mem2hex(buf, d, s); - DPRINTFNR(": %s\n", buf); - } else - DPRINTFNR("\n"); - } -#endif - - return true; -} - -// Write bytes to kernel address space for debugger. -bool -RemoteGDB::write(Addr vaddr, size_t size, const char *data) -{ - static Addr lastaddr = 0; - static size_t lastsize = 0; - - uint8_t *maddr; - - if (vaddr < 10) { - DPRINTF(GDBWrite, "write: writing memory location zero!\n"); - vaddr = lastaddr + lastsize; - } - - if (DTRACE(GDBWrite)) { - DPRINTFN("write: addr=%#x, size=%d", vaddr, size); - if (DTRACE(GDBExtra)) { - char buf[1024]; - mem2hex(buf, data, size); - DPRINTFNR(": %s\n", buf); - } else - DPRINTFNR("\n"); - } - - lastaddr = vaddr; - lastsize = size; - - size_t count = min((Addr)size, - VMPageSize - (vaddr & (VMPageSize - 1))); - - maddr = vtomem(context, vaddr, count); - memcpy(maddr, data, count); - - vaddr += count; - data += count; - size -= count; - - while (size >= VMPageSize) { - maddr = vtomem(context, vaddr, count); - memcpy(maddr, data, VMPageSize); - - vaddr += VMPageSize; - data += VMPageSize; - size -= VMPageSize; - } - - if (size > 0) { - maddr = vtomem(context, vaddr, count); - memcpy(maddr, data, size); - } - -#ifdef IMB - alpha_pal_imb(); -#endif - - return true; -} - - -PCEventQueue *RemoteGDB::getPcEventQueue() -{ - return &system->pcEventQueue; -} - - -RemoteGDB::HardBreakpoint::HardBreakpoint(RemoteGDB *_gdb, Addr pc) - : PCEvent(_gdb->getPcEventQueue(), "HardBreakpoint Event", pc), - gdb(_gdb), refcount(0) -{ - DPRINTF(GDBMisc, "creating hardware breakpoint at %#x\n", evpc); -} - -void -RemoteGDB::HardBreakpoint::process(ExecContext *xc) -{ - DPRINTF(GDBMisc, "handling hardware breakpoint at %#x\n", pc()); - - if (xc == gdb->context) - gdb->trap(ALPHA_KENTRY_INT); -} - -bool -RemoteGDB::insertSoftBreak(Addr addr, size_t len) -{ - if (len != sizeof(MachInst)) - panic("invalid length\n"); - - return insertHardBreak(addr, len); -} - -bool -RemoteGDB::removeSoftBreak(Addr addr, size_t len) -{ - if (len != sizeof(MachInst)) - panic("invalid length\n"); - - return removeHardBreak(addr, len); -} - -bool -RemoteGDB::insertHardBreak(Addr addr, size_t len) -{ - if (len != sizeof(MachInst)) - panic("invalid length\n"); - - DPRINTF(GDBMisc, "inserting hardware breakpoint at %#x\n", addr); - - HardBreakpoint *&bkpt = hardBreakMap[addr]; - if (bkpt == 0) - bkpt = new HardBreakpoint(this, addr); - - bkpt->refcount++; - - return true; -} - -bool -RemoteGDB::removeHardBreak(Addr addr, size_t len) -{ - if (len != sizeof(MachInst)) - panic("invalid length\n"); - - DPRINTF(GDBMisc, "removing hardware breakpoint at %#x\n", addr); - - break_iter_t i = hardBreakMap.find(addr); - if (i == hardBreakMap.end()) - return false; - - HardBreakpoint *hbp = (*i).second; - if (--hbp->refcount == 0) { - delete hbp; - hardBreakMap.erase(i); - } - - return true; -} - -const char * -break_type(char c) -{ - switch(c) { - case '0': return "software breakpoint"; - case '1': return "hardware breakpoint"; - case '2': return "write watchpoint"; - case '3': return "read watchpoint"; - case '4': return "access watchpoint"; - default: return "unknown breakpoint/watchpoint"; - } -} - -// This function does all command processing for interfacing to a -// remote gdb. Note that the error codes are ignored by gdb at -// present, but might eventually become meaningful. (XXX) It might -// makes sense to use POSIX errno values, because that is what the -// gdb/remote.c functions want to return. -bool -RemoteGDB::trap(int type) -{ - uint64_t val; - size_t datalen, len; - char data[KGDB_BUFLEN + 1]; - char buffer[sizeof(gdbregs) * 2 + 256]; - char temp[KGDB_BUFLEN]; - const char *p; - char command, subcmd; - string var; - bool ret; - - if (!attached) - return false; - - DPRINTF(GDBMisc, "trap: PC=%#x NPC=%#x\n", - context->readPC(), context->readNextPC()); - - clearSingleStep(); - - /* - * The first entry to this function is normally through - * a breakpoint trap in kgdb_connect(), in which case we - * must advance past the breakpoint because gdb will not. - * - * On the first entry here, we expect that gdb is not yet - * listening to us, so just enter the interaction loop. - * After the debugger is "active" (connected) it will be - * waiting for a "signaled" message from us. - */ - if (!active) - active = true; - else - // Tell remote host that an exception has occurred. - snprintf((char *)buffer, sizeof(buffer), "S%02x", signal(type)); - send(buffer); - - // Stick frame regs into our reg cache. - getregs(); - - for (;;) { - datalen = recv(data, sizeof(data)); - data[sizeof(data) - 1] = 0; // Sentinel - command = data[0]; - subcmd = 0; - p = data + 1; - switch (command) { - - case KGDB_SIGNAL: - // if this command came from a running gdb, answer it -- - // the other guy has no way of knowing if we're in or out - // of this loop when he issues a "remote-signal". - snprintf((char *)buffer, sizeof(buffer), "S%02x", signal(type)); - send(buffer); - continue; - - case KGDB_REG_R: - if (2 * sizeof(gdbregs) > sizeof(buffer)) - panic("buffer too small"); - - mem2hex(buffer, gdbregs, sizeof(gdbregs)); - send(buffer); - continue; - - case KGDB_REG_W: - p = hex2mem(gdbregs, p, sizeof(gdbregs)); - if (p == NULL || *p != '\0') - send("E01"); - else { - setregs(); - send("OK"); - } - continue; - -#if 0 - case KGDB_SET_REG: - val = hex2i(&p); - if (*p++ != '=') { - send("E01"); - continue; - } - if (val < 0 && val >= KGDB_NUMREGS) { - send("E01"); - continue; - } - - gdbregs[val] = hex2i(&p); - setregs(); - send("OK"); - - continue; -#endif - - case KGDB_MEM_R: - val = hex2i(&p); - if (*p++ != ',') { - send("E02"); - continue; - } - len = hex2i(&p); - if (*p != '\0') { - send("E03"); - continue; - } - if (len > sizeof(buffer)) { - send("E04"); - continue; - } - if (!acc(val, len)) { - send("E05"); - continue; - } - - if (read(val, (size_t)len, (char *)buffer)) { - mem2hex(temp, buffer, len); - send(temp); - } else { - send("E05"); - } - continue; - - case KGDB_MEM_W: - val = hex2i(&p); - if (*p++ != ',') { - send("E06"); - continue; - } - len = hex2i(&p); - if (*p++ != ':') { - send("E07"); - continue; - } - if (len > datalen - (p - data)) { - send("E08"); - continue; - } - p = hex2mem(buffer, p, sizeof(buffer)); - if (p == NULL) { - send("E09"); - continue; - } - if (!acc(val, len)) { - send("E0A"); - continue; - } - if (write(val, (size_t)len, (char *)buffer)) - send("OK"); - else - send("E0B"); - continue; - - case KGDB_SET_THREAD: - subcmd = *p++; - val = hex2i(&p); - if (val == 0) - send("OK"); - else - send("E01"); - continue; - - case KGDB_DETACH: - case KGDB_KILL: - active = false; - clearSingleStep(); - detach(); - goto out; - - case KGDB_ASYNC_CONT: - subcmd = hex2i(&p); - if (*p++ == ';') { - val = hex2i(&p); - context->setPC(val); - context->setNextPC(val + sizeof(MachInst)); - } - clearSingleStep(); - goto out; - - case KGDB_CONT: - if (p - data < datalen) { - val = hex2i(&p); - context->setPC(val); - context->setNextPC(val + sizeof(MachInst)); - } - clearSingleStep(); - goto out; - - case KGDB_ASYNC_STEP: - subcmd = hex2i(&p); - if (*p++ == ';') { - val = hex2i(&p); - context->setPC(val); - context->setNextPC(val + sizeof(MachInst)); - } - setSingleStep(); - goto out; - - case KGDB_STEP: - if (p - data < datalen) { - val = hex2i(&p); - context->setPC(val); - context->setNextPC(val + sizeof(MachInst)); - } - setSingleStep(); - goto out; - - case KGDB_CLR_HW_BKPT: - subcmd = *p++; - if (*p++ != ',') send("E0D"); - val = hex2i(&p); - if (*p++ != ',') send("E0D"); - len = hex2i(&p); - - DPRINTF(GDBMisc, "clear %s, addr=%#x, len=%d\n", - break_type(subcmd), val, len); - - ret = false; - - switch (subcmd) { - case '0': // software breakpoint - ret = removeSoftBreak(val, len); - break; - - case '1': // hardware breakpoint - ret = removeHardBreak(val, len); - break; - - case '2': // write watchpoint - case '3': // read watchpoint - case '4': // access watchpoint - default: // unknown - send(""); - break; - } - - send(ret ? "OK" : "E0C"); - continue; - - case KGDB_SET_HW_BKPT: - subcmd = *p++; - if (*p++ != ',') send("E0D"); - val = hex2i(&p); - if (*p++ != ',') send("E0D"); - len = hex2i(&p); - - DPRINTF(GDBMisc, "set %s, addr=%#x, len=%d\n", - break_type(subcmd), val, len); - - ret = false; - - switch (subcmd) { - case '0': // software breakpoint - ret = insertSoftBreak(val, len); - break; - - case '1': // hardware breakpoint - ret = insertHardBreak(val, len); - break; - - case '2': // write watchpoint - case '3': // read watchpoint - case '4': // access watchpoint - default: // unknown - send(""); - break; - } - - send(ret ? "OK" : "E0C"); - continue; - - case KGDB_QUERY_VAR: - var = string(p, datalen - 1); - if (var == "C") - send("QC0"); - else - send(""); - continue; - - case KGDB_SET_BAUD: - case KGDB_SET_BREAK: - case KGDB_DEBUG: - case KGDB_CYCLE_STEP: - case KGDB_SIG_CYCLE_STEP: - case KGDB_READ_REG: - case KGDB_SET_VAR: - case KGDB_RESET: - case KGDB_THREAD_ALIVE: - case KGDB_TARGET_EXIT: - case KGDB_BINARY_DLOAD: - // Unsupported command - DPRINTF(GDBMisc, "Unsupported command: %s\n", - gdb_command(command)); - DDUMP(GDBMisc, (uint8_t *)data, datalen); - send(""); - continue; - - default: - // Unknown command. - DPRINTF(GDBMisc, "Unknown command: %c(%#x)\n", - command, command); - send(""); - continue; - - - } - } - - out: - return true; -} - -// Convert a hex digit into an integer. -// This returns -1 if the argument passed is no valid hex digit. -int -digit2i(char c) -{ - if (c >= '0' && c <= '9') - return (c - '0'); - else if (c >= 'a' && c <= 'f') - return (c - 'a' + 10); - else if (c >= 'A' && c <= 'F') - - return (c - 'A' + 10); - else - return (-1); -} - -// Convert the low 4 bits of an integer into an hex digit. -char -i2digit(int n) -{ - return ("0123456789abcdef"[n & 0x0f]); -} - -// Convert a byte array into an hex string. -void -mem2hex(void *vdst, const void *vsrc, int len) -{ - char *dst = (char *)vdst; - const char *src = (const char *)vsrc; - - while (len--) { - *dst++ = i2digit(*src >> 4); - *dst++ = i2digit(*src++); - } - *dst = '\0'; -} - -// Convert an hex string into a byte array. -// This returns a pointer to the character following the last valid -// hex digit. If the string ends in the middle of a byte, NULL is -// returned. -const char * -hex2mem(void *vdst, const char *src, int maxlen) -{ - char *dst = (char *)vdst; - int msb, lsb; - - while (*src && maxlen--) { - msb = digit2i(*src++); - if (msb < 0) - return (src - 1); - lsb = digit2i(*src++); - if (lsb < 0) - return (NULL); - *dst++ = (msb << 4) | lsb; - } - return (src); -} - -// Convert an hex string into an integer. -// This returns a pointer to the character following the last valid -// hex digit. -Addr -hex2i(const char **srcp) -{ - const char *src = *srcp; - Addr r = 0; - int nibble; - - while ((nibble = digit2i(*src)) >= 0) { - r *= 16; - r += nibble; - src++; - } - *srcp = src; - return (r); -} - diff --git a/base/statistics.cc b/base/statistics.cc deleted file mode 100644 index c97564641..000000000 --- a/base/statistics.cc +++ /dev/null @@ -1,357 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <iomanip> -#include <fstream> -#include <list> -#include <map> -#include <string> -#include <sstream> - -#include "base/callback.hh" -#include "base/cprintf.hh" -#include "base/hostinfo.hh" -#include "base/misc.hh" -#include "base/statistics.hh" -#include "base/str.hh" -#include "base/time.hh" -#include "base/trace.hh" -#include "base/stats/statdb.hh" -#include "config/stats_binning.hh" - -using namespace std; - -namespace Stats { - -StatData * -DataAccess::find() const -{ - return Database::find(const_cast<void *>((const void *)this)); -} - -const StatData * -getStatData(const void *stat) -{ - return Database::find(const_cast<void *>(stat)); -} - -void -DataAccess::map(StatData *data) -{ - Database::regStat(this, data); -} - -StatData * -DataAccess::statData() -{ - StatData *ptr = find(); - assert(ptr); - return ptr; -} - -const StatData * -DataAccess::statData() const -{ - const StatData *ptr = find(); - assert(ptr); - return ptr; -} - -void -DataAccess::setInit() -{ - statData()->flags |= init; -} - -void -DataAccess::setPrint() -{ - Database::regPrint(this); -} - -StatData::StatData() - : flags(none), precision(-1), prereq(0) -{ - static int count = 0; - id = count++; -} - -StatData::~StatData() -{ -} - -bool -StatData::less(StatData *stat1, StatData *stat2) -{ - const string &name1 = stat1->name; - const string &name2 = stat2->name; - - vector<string> v1; - vector<string> v2; - - tokenize(v1, name1, '.'); - tokenize(v2, name2, '.'); - - int last = min(v1.size(), v2.size()) - 1; - for (int i = 0; i < last; ++i) - if (v1[i] != v2[i]) - return v1[i] < v2[i]; - - // Special compare for last element. - if (v1[last] == v2[last]) - return v1.size() < v2.size(); - else - return v1[last] < v2[last]; - - return false; -} - -bool -StatData::baseCheck() const -{ - if (!(flags & init)) { -#ifdef DEBUG - cprintf("this is stat number %d\n", id); -#endif - panic("Not all stats have been initialized"); - return false; - } - - if ((flags & print) && name.empty()) { - panic("all printable stats must be named"); - return false; - } - - return true; -} - - -void -FormulaBase::result(VResult &vec) const -{ - if (root) - vec = root->result(); -} - -Result -FormulaBase::total() const -{ - return root ? root->total() : 0.0; -} - -size_t -FormulaBase::size() const -{ - if (!root) - return 0; - else - return root->size(); -} - -bool -FormulaBase::binned() const -{ - return root && root->binned(); -} - -void -FormulaBase::reset() -{ -} - -bool -FormulaBase::zero() const -{ - VResult vec; - result(vec); - for (int i = 0; i < vec.size(); ++i) - if (vec[i] != 0.0) - return false; - return true; -} - -void -FormulaBase::update(StatData *) -{ -} - -string -FormulaBase::str() const -{ - return root ? root->str() : ""; -} - -Formula::Formula() -{ - setInit(); -} - -Formula::Formula(Temp r) -{ - root = r; - assert(size()); -} - -const Formula & -Formula::operator=(Temp r) -{ - assert(!root && "Can't change formulas"); - root = r; - assert(size()); - return *this; -} - -const Formula & -Formula::operator+=(Temp r) -{ - if (root) - root = NodePtr(new BinaryNode<std::plus<Result> >(root, r)); - else - root = r; - assert(size()); - return *this; -} - -MainBin::MainBin(const string &name) - : _name(name), mem(NULL), memsize(-1) -{ - Database::regBin(this, name); -} - -MainBin::~MainBin() -{ - if (mem) - delete [] mem; -} - -char * -MainBin::memory(off_t off) -{ - if (memsize == -1) - memsize = ceilPow2((size_t) offset()); - - if (!mem) { - mem = new char[memsize]; - memset(mem, 0, memsize); - } - - assert(offset() <= size()); - return mem + off; -} - -void -check() -{ - typedef Database::stat_list_t::iterator iter_t; - - iter_t i, end = Database::stats().end(); - for (i = Database::stats().begin(); i != end; ++i) { - StatData *data = *i; - assert(data); - if (!data->check() || !data->baseCheck()) - panic("stat check failed for %s\n", data->name); - } - - int j = 0; - for (i = Database::stats().begin(); i != end; ++i) { - StatData *data = *i; - if (!(data->flags & print)) - data->name = "__Stat" + to_string(j++); - } - - Database::stats().sort(StatData::less); - -#if STATS_BINNING - if (MainBin::curBin() == NULL) { - static MainBin mainBin("main bin"); - mainBin.activate(); - } -#endif - - if (i == end) - return; - - iter_t last = i; - ++i; - - for (i = Database::stats().begin(); i != end; ++i) { - if ((*i)->name == (*last)->name) - panic("same name used twice! name=%s\n", (*i)->name); - - last = i; - } -} - -CallbackQueue resetQueue; - -void -reset() -{ - // reset non-binned stats - Database::stat_list_t::iterator i = Database::stats().begin(); - Database::stat_list_t::iterator end = Database::stats().end(); - while (i != end) { - StatData *data = *i; - if (!data->binned()) - data->reset(); - ++i; - } - - // save the bin so we can go back to where we were - MainBin *orig = MainBin::curBin(); - - // reset binned stats - Database::bin_list_t::iterator bi = Database::bins().begin(); - Database::bin_list_t::iterator be = Database::bins().end(); - while (bi != be) { - MainBin *bin = *bi; - bin->activate(); - - i = Database::stats().begin(); - while (i != end) { - StatData *data = *i; - if (data->binned()) - data->reset(); - ++i; - } - ++bi; - } - - // restore bin - MainBin::curBin() = orig; - - resetQueue.process(); -} - -void -registerResetCallback(Callback *cb) -{ - resetQueue.add(cb); -} - -/* namespace Stats */ } diff --git a/base/statistics.hh b/base/statistics.hh deleted file mode 100644 index c46744cac..000000000 --- a/base/statistics.hh +++ /dev/null @@ -1,2897 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** @file - * Declaration of Statistics objects. - */ - -/** -* @todo -* -* Generalized N-dimensinal vector -* documentation -* key stats -* interval stats -* -- these both can use the same function that prints out a -* specific set of stats -* VectorStandardDeviation totals -* Document Namespaces -*/ -#ifndef __BASE_STATISTICS_HH__ -#define __BASE_STATISTICS_HH__ - -#include <algorithm> -#include <cassert> -#include <cmath> -#include <functional> -#include <iosfwd> -#include <sstream> -#include <string> -#include <vector> - -#include "base/cprintf.hh" -#include "base/intmath.hh" -#include "base/refcnt.hh" -#include "base/str.hh" -#include "base/stats/bin.hh" -#include "base/stats/flags.hh" -#include "base/stats/visit.hh" -#include "base/stats/types.hh" -#include "config/stats_binning.hh" -#include "sim/host.hh" - -class Callback; - -/** The current simulated cycle. */ -extern Tick curTick; - -/* A namespace for all of the Statistics */ -namespace Stats { - -/* Contains the statistic implementation details */ -////////////////////////////////////////////////////////////////////// -// -// Statistics Framework Base classes -// -////////////////////////////////////////////////////////////////////// -struct StatData -{ - /** The name of the stat. */ - std::string name; - /** The description of the stat. */ - std::string desc; - /** The formatting flags. */ - StatFlags flags; - /** The display precision. */ - int precision; - /** A pointer to a prerequisite Stat. */ - const StatData *prereq; - /** - * A unique stat ID for each stat in the simulator. - * Can be used externally for lookups as well as for debugging. - */ - int id; - - StatData(); - virtual ~StatData(); - - /** - * @return true if the stat is binned. - */ - virtual bool binned() const = 0; - - /** - * Reset the corresponding stat to the default state. - */ - virtual void reset() = 0; - - /** - * @return true if this stat has a value and satisfies its - * requirement as a prereq - */ - virtual bool zero() const = 0; - - /** - * Check that this stat has been set up properly and is ready for - * use - * @return true for success - */ - virtual bool check() const = 0; - bool baseCheck() const; - - /** - * Visitor entry for outputing statistics data - */ - virtual void visit(Visit &visitor) = 0; - - /** - * Checks if the first stat's name is alphabetically less than the second. - * This function breaks names up at periods and considers each subname - * separately. - * @param stat1 The first stat. - * @param stat2 The second stat. - * @return stat1's name is alphabetically before stat2's - */ - static bool less(StatData *stat1, StatData *stat2); -}; - -class ScalarData : public StatData -{ - public: - virtual Counter value() const = 0; - virtual Result result() const = 0; - virtual Result total() const = 0; - virtual void visit(Visit &visitor) { visitor.visit(*this); } -}; - -template <class Stat> -class ScalarStatData : public ScalarData -{ - protected: - Stat &s; - - public: - ScalarStatData(Stat &stat) : s(stat) {} - - virtual bool binned() const { return s.binned(); } - virtual bool check() const { return s.check(); } - virtual Counter value() const { return s.value(); } - virtual Result result() const { return s.result(); } - virtual Result total() const { return s.total(); } - virtual void reset() { s.reset(); } - virtual bool zero() const { return s.zero(); } -}; - -struct VectorData : public StatData -{ - /** Names and descriptions of subfields. */ - mutable std::vector<std::string> subnames; - mutable std::vector<std::string> subdescs; - - virtual size_t size() const = 0; - virtual const VCounter &value() const = 0; - virtual const VResult &result() const = 0; - virtual Result total() const = 0; - void update() - { - if (!subnames.empty()) { - int s = size(); - if (subnames.size() < s) - subnames.resize(s); - - if (subdescs.size() < s) - subdescs.resize(s); - } - } -}; - -template <class Stat> -class VectorStatData : public VectorData -{ - protected: - Stat &s; - mutable VCounter cvec; - mutable VResult rvec; - - public: - VectorStatData(Stat &stat) : s(stat) {} - - virtual bool binned() const { return s.binned(); } - virtual bool check() const { return s.check(); } - virtual bool zero() const { return s.zero(); } - virtual void reset() { s.reset(); } - - virtual size_t size() const { return s.size(); } - virtual VCounter &value() const - { - s.value(cvec); - return cvec; - } - virtual const VResult &result() const - { - s.result(rvec); - return rvec; - } - virtual Result total() const { return s.total(); } - virtual void visit(Visit &visitor) - { - update(); - s.update(this); - visitor.visit(*this); - } -}; - -struct DistDataData -{ - Counter min_val; - Counter max_val; - Counter underflow; - Counter overflow; - VCounter cvec; - Counter sum; - Counter squares; - Counter samples; - - Counter min; - Counter max; - Counter bucket_size; - int size; - bool fancy; -}; - -struct DistData : public StatData -{ - /** Local storage for the entry values, used for printing. */ - DistDataData data; -}; - -template <class Stat> -class DistStatData : public DistData -{ - protected: - Stat &s; - - public: - DistStatData(Stat &stat) : s(stat) {} - - virtual bool binned() const { return s.binned(); } - virtual bool check() const { return s.check(); } - virtual void reset() { s.reset(); } - virtual bool zero() const { return s.zero(); } - virtual void visit(Visit &visitor) - { - s.update(this); - visitor.visit(*this); - } -}; - -struct VectorDistData : public StatData -{ - std::vector<DistDataData> data; - - /** Names and descriptions of subfields. */ - mutable std::vector<std::string> subnames; - mutable std::vector<std::string> subdescs; - - /** Local storage for the entry values, used for printing. */ - mutable VResult rvec; - - virtual size_t size() const = 0; - void update() - { - int s = size(); - if (subnames.size() < s) - subnames.resize(s); - - if (subdescs.size() < s) - subdescs.resize(s); - } -}; - -template <class Stat> -class VectorDistStatData : public VectorDistData -{ - protected: - Stat &s; - typedef typename Stat::bin_t bin_t; - - public: - VectorDistStatData(Stat &stat) : s(stat) {} - - virtual bool binned() const { return bin_t::binned; } - virtual bool check() const { return s.check(); } - virtual void reset() { s.reset(); } - virtual size_t size() const { return s.size(); } - virtual bool zero() const { return s.zero(); } - virtual void visit(Visit &visitor) - { - update(); - s.update(this); - visitor.visit(*this); - } -}; - -struct Vector2dData : public StatData -{ - /** Names and descriptions of subfields. */ - std::vector<std::string> subnames; - std::vector<std::string> subdescs; - std::vector<std::string> y_subnames; - - /** Local storage for the entry values, used for printing. */ - mutable VCounter cvec; - mutable int x; - mutable int y; - - void update() - { - if (subnames.size() < x) - subnames.resize(x); - } -}; - -template <class Stat> -class Vector2dStatData : public Vector2dData -{ - protected: - Stat &s; - typedef typename Stat::bin_t bin_t; - - public: - Vector2dStatData(Stat &stat) : s(stat) {} - - virtual bool binned() const { return bin_t::binned; } - virtual bool check() const { return s.check(); } - virtual void reset() { s.reset(); } - virtual bool zero() const { return s.zero(); } - virtual void visit(Visit &visitor) - { - update(); - s.update(this); - visitor.visit(*this); - } -}; - - -class DataAccess -{ - protected: - StatData *find() const; - void map(StatData *data); - - StatData *statData(); - const StatData *statData() const; - - void setInit(); - void setPrint(); -}; - -template <class Parent, class Child, template <class> class Data> -class Wrap : public Child -{ - protected: - Parent &self() { return *reinterpret_cast<Parent *>(this); } - - protected: - Data<Child> *statData() - { - StatData *__data = DataAccess::statData(); - Data<Child> *ptr = dynamic_cast<Data<Child> *>(__data); - assert(ptr); - return ptr; - } - - public: - const Data<Child> *statData() const - { - const StatData *__data = DataAccess::statData(); - const Data<Child> *ptr = dynamic_cast<const Data<Child> *>(__data); - assert(ptr); - return ptr; - } - - protected: - /** - * Copy constructor, copies are not allowed. - */ - Wrap(const Wrap &stat); - /** - * Can't copy stats. - */ - void operator=(const Wrap &); - - public: - Wrap() - { - map(new Data<Child>(*this)); - } - - /** - * Set the name and marks this stat to print at the end of simulation. - * @param name The new name. - * @return A reference to this stat. - */ - Parent &name(const std::string &_name) - { - Data<Child> *data = this->statData(); - data->name = _name; - this->setPrint(); - return this->self(); - } - - /** - * Set the description and marks this stat to print at the end of - * simulation. - * @param desc The new description. - * @return A reference to this stat. - */ - Parent &desc(const std::string &_desc) - { - this->statData()->desc = _desc; - return this->self(); - } - - /** - * Set the precision and marks this stat to print at the end of simulation. - * @param p The new precision - * @return A reference to this stat. - */ - Parent &precision(int _precision) - { - this->statData()->precision = _precision; - return this->self(); - } - - /** - * Set the flags and marks this stat to print at the end of simulation. - * @param f The new flags. - * @return A reference to this stat. - */ - Parent &flags(StatFlags _flags) - { - this->statData()->flags |= _flags; - return this->self(); - } - - /** - * Set the prerequisite stat and marks this stat to print at the end of - * simulation. - * @param prereq The prerequisite stat. - * @return A reference to this stat. - */ - template <class Stat> - Parent &prereq(const Stat &prereq) - { - this->statData()->prereq = prereq.statData(); - return this->self(); - } -}; - -template <class Parent, class Child, template <class Child> class Data> -class WrapVec : public Wrap<Parent, Child, Data> -{ - public: - // The following functions are specific to vectors. If you use them - // in a non vector context, you will get a nice compiler error! - - /** - * Set the subfield name for the given index, and marks this stat to print - * at the end of simulation. - * @param index The subfield index. - * @param name The new name of the subfield. - * @return A reference to this stat. - */ - Parent &subname(int index, const std::string &name) - { - std::vector<std::string> &subn = this->statData()->subnames; - if (subn.size() <= index) - subn.resize(index + 1); - subn[index] = name; - return this->self(); - } - - /** - * Set the subfield description for the given index and marks this stat to - * print at the end of simulation. - * @param index The subfield index. - * @param desc The new description of the subfield - * @return A reference to this stat. - */ - Parent &subdesc(int index, const std::string &desc) - { - std::vector<std::string> &subd = this->statData()->subdescs; - if (subd.size() <= index) - subd.resize(index + 1); - subd[index] = desc; - - return this->self(); - } - -}; - -template <class Parent, class Child, template <class Child> class Data> -class WrapVec2d : public WrapVec<Parent, Child, Data> -{ - public: - /** - * @warning This makes the assumption that if you're gonna subnames a 2d - * vector, you're subnaming across all y - */ - Parent &ysubnames(const char **names) - { - Data<Child> *data = this->statData(); - data->y_subnames.resize(this->y); - for (int i = 0; i < this->y; ++i) - data->y_subnames[i] = names[i]; - return this->self(); - } - Parent &ysubname(int index, const std::string subname) - { - Data<Child> *data = this->statData(); - assert(index < this->y); - data->y_subnames.resize(this->y); - data->y_subnames[index] = subname.c_str(); - return this->self(); - } -}; - -////////////////////////////////////////////////////////////////////// -// -// Simple Statistics -// -////////////////////////////////////////////////////////////////////// - -/** - * Templatized storage and interface for a simple scalar stat. - */ -struct StatStor -{ - public: - /** The paramaters for this storage type, none for a scalar. */ - struct Params { }; - - private: - /** The statistic value. */ - Counter data; - - public: - /** - * Builds this storage element and calls the base constructor of the - * datatype. - */ - StatStor(const Params &) : data(Counter()) {} - - /** - * The the stat to the given value. - * @param val The new value. - * @param p The paramters of this storage type. - */ - void set(Counter val, const Params &p) { data = val; } - /** - * Increment the stat by the given value. - * @param val The new value. - * @param p The paramters of this storage type. - */ - void inc(Counter val, const Params &p) { data += val; } - /** - * Decrement the stat by the given value. - * @param val The new value. - * @param p The paramters of this storage type. - */ - void dec(Counter val, const Params &p) { data -= val; } - /** - * Return the value of this stat as its base type. - * @param p The params of this storage type. - * @return The value of this stat. - */ - Counter value(const Params &p) const { return data; } - /** - * Return the value of this stat as a result type. - * @param p The parameters of this storage type. - * @return The value of this stat. - */ - Result result(const Params &p) const { return (Result)data; } - /** - * Reset stat value to default - */ - void reset() { data = Counter(); } - - /** - * @return true if zero value - */ - bool zero() const { return data == Counter(); } -}; - -/** - * Templatized storage and interface to a per-cycle average stat. This keeps - * a current count and updates a total (count * cycles) when this count - * changes. This allows the quick calculation of a per cycle count of the item - * being watched. This is good for keeping track of residencies in structures - * among other things. - * @todo add lateny to the stat and fix binning. - */ -struct AvgStor -{ - public: - /** The paramaters for this storage type */ - struct Params - { - /** - * The current count. We stash this here because the current - * value is not a binned value. - */ - Counter current; - }; - - private: - /** The total count for all cycles. */ - mutable Result total; - /** The cycle that current last changed. */ - mutable Tick last; - - public: - /** - * Build and initializes this stat storage. - */ - AvgStor(Params &p) : total(0), last(0) { p.current = Counter(); } - - /** - * Set the current count to the one provided, update the total and last - * set values. - * @param val The new count. - * @param p The parameters for this storage. - */ - void set(Counter val, Params &p) { - total += p.current * (curTick - last); - last = curTick; - p.current = val; - } - - /** - * Increment the current count by the provided value, calls set. - * @param val The amount to increment. - * @param p The parameters for this storage. - */ - void inc(Counter val, Params &p) { set(p.current + val, p); } - - /** - * Deccrement the current count by the provided value, calls set. - * @param val The amount to decrement. - * @param p The parameters for this storage. - */ - void dec(Counter val, Params &p) { set(p.current - val, p); } - - /** - * Return the current count. - * @param p The parameters for this storage. - * @return The current count. - */ - Counter value(const Params &p) const { return p.current; } - - /** - * Return the current average. - * @param p The parameters for this storage. - * @return The current average. - */ - Result result(const Params &p) const - { - total += p.current * (curTick - last); - last = curTick; - return (Result)(total + p.current) / (Result)(curTick + 1); - } - - /** - * Reset stat value to default - */ - void reset() - { - total = 0; - last = curTick; - } - - /** - * @return true if zero value - */ - bool zero() const { return total == 0.0; } -}; - -/** - * Implementation of a scalar stat. The type of stat is determined by the - * Storage template. The storage for this stat is held within the Bin class. - * This allows for breaking down statistics across multiple bins easily. - */ -template <class Storage, class Bin> -class ScalarBase : public DataAccess -{ - public: - /** Define the params of the storage class. */ - typedef typename Storage::Params params_t; - /** Define the bin type. */ - typedef typename Bin::template Bin<Storage> bin_t; - - protected: - /** The bin of this stat. */ - bin_t bin; - /** The parameters for this stat. */ - params_t params; - - protected: - /** - * Retrieve the storage from the bin. - * @return The storage object for this stat. - */ - Storage *data() { return bin.data(params); } - /** - * Retrieve a const pointer to the storage from the bin. - * @return A const pointer to the storage object for this stat. - */ - const Storage *data() const - { - bin_t *_bin = const_cast<bin_t *>(&bin); - params_t *_params = const_cast<params_t *>(¶ms); - return _bin->data(*_params); - } - - public: - /** - * Return the current value of this stat as its base type. - * @return The current value. - */ - Counter value() const { return data()->value(params); } - - public: - /** - * Create and initialize this stat, register it with the database. - */ - ScalarBase() - { - bin.init(params); - } - - public: - // Common operators for stats - /** - * Increment the stat by 1. This calls the associated storage object inc - * function. - */ - void operator++() { data()->inc(1, params); } - /** - * Decrement the stat by 1. This calls the associated storage object dec - * function. - */ - void operator--() { data()->dec(1, params); } - - /** Increment the stat by 1. */ - void operator++(int) { ++*this; } - /** Decrement the stat by 1. */ - void operator--(int) { --*this; } - - /** - * Set the data value to the given value. This calls the associated storage - * object set function. - * @param v The new value. - */ - template <typename U> - void operator=(const U &v) { data()->set(v, params); } - - /** - * Increment the stat by the given value. This calls the associated - * storage object inc function. - * @param v The value to add. - */ - template <typename U> - void operator+=(const U &v) { data()->inc(v, params); } - - /** - * Decrement the stat by the given value. This calls the associated - * storage object dec function. - * @param v The value to substract. - */ - template <typename U> - void operator-=(const U &v) { data()->dec(v, params); } - - /** - * Return the number of elements, always 1 for a scalar. - * @return 1. - */ - size_t size() const { return 1; } - /** - * Return true if stat is binned. - *@return True is stat is binned. - */ - bool binned() const { return bin_t::binned; } - - bool check() const { return bin.initialized(); } - - /** - * Reset stat value to default - */ - void reset() { bin.reset(); } - - Counter value() { return data()->value(params); } - - Result result() { return data()->result(params); } - - Result total() { return result(); } - - bool zero() { return result() == 0.0; } - -}; - -class ProxyData : public ScalarData -{ - public: - virtual void visit(Visit &visitor) { visitor.visit(*this); } - virtual bool binned() const { return false; } - virtual std::string str() const { return to_string(value()); } - virtual size_t size() const { return 1; } - virtual bool zero() const { return value() == 0; } - virtual bool check() const { return true; } - virtual void reset() { } -}; - -template <class T> -class ValueProxy : public ProxyData -{ - private: - T *scalar; - - public: - ValueProxy(T &val) : scalar(&val) {} - virtual Counter value() const { return *scalar; } - virtual Result result() const { return *scalar; } - virtual Result total() const { return *scalar; } -}; - -template <class T> -class FunctorProxy : public ProxyData -{ - private: - T *functor; - - public: - FunctorProxy(T &func) : functor(&func) {} - virtual Counter value() const { return (*functor)(); } - virtual Result result() const { return (*functor)(); } - virtual Result total() const { return (*functor)(); } -}; - -class ValueBase : public DataAccess -{ - private: - ProxyData *proxy; - - public: - ValueBase() : proxy(NULL) { } - ~ValueBase() { if (proxy) delete proxy; } - - template <class T> - void scalar(T &value) - { - proxy = new ValueProxy<T>(value); - setInit(); - } - - template <class T> - void functor(T &func) - { - proxy = new FunctorProxy<T>(func); - setInit(); - } - - Counter value() { return proxy->value(); } - Result result() const { return proxy->result(); } - Result total() const { return proxy->total(); }; - size_t size() const { return proxy->size(); } - - bool binned() const { return proxy->binned(); } - std::string str() const { return proxy->str(); } - bool zero() const { return proxy->zero(); } - bool check() const { return proxy != NULL; } - void reset() { } -}; - -////////////////////////////////////////////////////////////////////// -// -// Vector Statistics -// -////////////////////////////////////////////////////////////////////// -template <class Storage, class Bin> -class ScalarProxy; - -/** - * Implementation of a vector of stats. The type of stat is determined by the - * Storage class. @sa ScalarBase - */ -template <class Storage, class Bin> -class VectorBase : public DataAccess -{ - public: - /** Define the params of the storage class. */ - typedef typename Storage::Params params_t; - /** Define the bin type. */ - typedef typename Bin::template VectorBin<Storage> bin_t; - - protected: - /** The bin of this stat. */ - bin_t bin; - /** The parameters for this stat. */ - params_t params; - - protected: - /** - * Retrieve the storage from the bin for the given index. - * @param index The vector index to access. - * @return The storage object at the given index. - */ - Storage *data(int index) { return bin.data(index, params); } - /** - * Retrieve a const pointer to the storage from the bin - * for the given index. - * @param index The vector index to access. - * @return A const pointer to the storage object at the given index. - */ - const Storage *data(int index) const - { - bin_t *_bin = const_cast<bin_t *>(&bin); - params_t *_params = const_cast<params_t *>(¶ms); - return _bin->data(index, *_params); - } - - public: - void value(VCounter &vec) const - { - vec.resize(size()); - for (int i = 0; i < size(); ++i) - vec[i] = data(i)->value(params); - } - - /** - * Copy the values to a local vector and return a reference to it. - * @return A reference to a vector of the stat values. - */ - void result(VResult &vec) const - { - vec.resize(size()); - for (int i = 0; i < size(); ++i) - vec[i] = data(i)->result(params); - } - - /** - * @return True is stat is binned. - */ - bool binned() const { return bin_t::binned; } - - /** - * Return a total of all entries in this vector. - * @return The total of all vector entries. - */ - Result total() const { - Result total = 0.0; - for (int i = 0; i < size(); ++i) - total += data(i)->result(params); - return total; - } - - /** - * @return the number of elements in this vector. - */ - size_t size() const { return bin.size(); } - - bool zero() const - { - for (int i = 0; i < size(); ++i) - if (data(i)->zero()) - return true; - return false; - } - - bool check() const { return bin.initialized(); } - void reset() { bin.reset(); } - - public: - VectorBase() {} - - /** Friend this class with the associated scalar proxy. */ - friend class ScalarProxy<Storage, Bin>; - - /** - * Return a reference (ScalarProxy) to the stat at the given index. - * @param index The vector index to access. - * @return A reference of the stat. - */ - ScalarProxy<Storage, Bin> operator[](int index); - - void update(StatData *data) {} -}; - -const StatData * getStatData(const void *stat); - -/** - * A proxy class to access the stat at a given index in a VectorBase stat. - * Behaves like a ScalarBase. - */ -template <class Storage, class Bin> -class ScalarProxy -{ - public: - /** Define the params of the storage class. */ - typedef typename Storage::Params params_t; - /** Define the bin type. */ - typedef typename Bin::template VectorBin<Storage> bin_t; - - private: - /** Pointer to the bin in the parent VectorBase. */ - bin_t *bin; - /** Pointer to the params in the parent VectorBase. */ - params_t *params; - /** The index to access in the parent VectorBase. */ - int index; - /** Keep a pointer to the original stat so was can get data */ - void *stat; - - protected: - /** - * Retrieve the storage from the bin. - * @return The storage from the bin for this stat. - */ - Storage *data() { return bin->data(index, *params); } - /** - * Retrieve a const pointer to the storage from the bin. - * @return A const pointer to the storage for this stat. - */ - const Storage *data() const - { - bin_t *_bin = const_cast<bin_t *>(bin); - params_t *_params = const_cast<params_t *>(params); - return _bin->data(index, *_params); - } - - public: - /** - * Return the current value of this stat as its base type. - * @return The current value. - */ - Counter value() const { return data()->value(*params); } - - /** - * Return the current value of this statas a result type. - * @return The current value. - */ - Result result() const { return data()->result(*params); } - - public: - /** - * Create and initialize this proxy, do not register it with the database. - * @param b The bin to use. - * @param p The params to use. - * @param i The index to access. - */ - ScalarProxy(bin_t &b, params_t &p, int i, void *s) - : bin(&b), params(&p), index(i), stat(s) {} - /** - * Create a copy of the provided ScalarProxy. - * @param sp The proxy to copy. - */ - ScalarProxy(const ScalarProxy &sp) - : bin(sp.bin), params(sp.params), index(sp.index), stat(sp.stat) {} - /** - * Set this proxy equal to the provided one. - * @param sp The proxy to copy. - * @return A reference to this proxy. - */ - const ScalarProxy &operator=(const ScalarProxy &sp) { - bin = sp.bin; - params = sp.params; - index = sp.index; - stat = sp.stat; - return *this; - } - - public: - // Common operators for stats - /** - * Increment the stat by 1. This calls the associated storage object inc - * function. - */ - void operator++() { data()->inc(1, *params); } - /** - * Decrement the stat by 1. This calls the associated storage object dec - * function. - */ - void operator--() { data()->dec(1, *params); } - - /** Increment the stat by 1. */ - void operator++(int) { ++*this; } - /** Decrement the stat by 1. */ - void operator--(int) { --*this; } - - /** - * Set the data value to the given value. This calls the associated storage - * object set function. - * @param v The new value. - */ - template <typename U> - void operator=(const U &v) { data()->set(v, *params); } - - /** - * Increment the stat by the given value. This calls the associated - * storage object inc function. - * @param v The value to add. - */ - template <typename U> - void operator+=(const U &v) { data()->inc(v, *params); } - - /** - * Decrement the stat by the given value. This calls the associated - * storage object dec function. - * @param v The value to substract. - */ - template <typename U> - void operator-=(const U &v) { data()->dec(v, *params); } - - /** - * Return the number of elements, always 1 for a scalar. - * @return 1. - */ - size_t size() const { return 1; } - - /** - * Return true if stat is binned. - *@return false since Proxies aren't printed/binned - */ - bool binned() const { return false; } - - /** - * This stat has no state. Nothing to reset - */ - void reset() { } - - public: - const StatData *statData() const { return getStatData(stat); } - std::string str() const - { - return csprintf("%s[%d]", this->statData()->name, index); - - } -}; - -template <class Storage, class Bin> -inline ScalarProxy<Storage, Bin> -VectorBase<Storage, Bin>::operator[](int index) -{ - assert (index >= 0 && index < size()); - return ScalarProxy<Storage, Bin>(bin, params, index, this); -} - -template <class Storage, class Bin> -class VectorProxy; - -template <class Storage, class Bin> -class Vector2dBase : public DataAccess -{ - public: - typedef typename Storage::Params params_t; - typedef typename Bin::template VectorBin<Storage> bin_t; - - protected: - size_t x; - size_t y; - bin_t bin; - params_t params; - - protected: - Storage *data(int index) { return bin.data(index, params); } - const Storage *data(int index) const - { - bin_t *_bin = const_cast<bin_t *>(&bin); - params_t *_params = const_cast<params_t *>(¶ms); - return _bin->data(index, *_params); - } - - public: - Vector2dBase() {} - - void update(Vector2dData *data) - { - int size = this->size(); - data->cvec.resize(size); - for (int i = 0; i < size; ++i) - data->cvec[i] = this->data(i)->value(params); - } - - std::string ysubname(int i) const { return (*this->y_subnames)[i]; } - - friend class VectorProxy<Storage, Bin>; - VectorProxy<Storage, Bin> operator[](int index); - - size_t size() const { return bin.size(); } - bool zero() const { return data(0)->value(params) == 0.0; } - - /** - * Reset stat value to default - */ - void reset() { bin.reset(); } - - bool check() { return bin.initialized(); } -}; - -template <class Storage, class Bin> -class VectorProxy -{ - public: - typedef typename Storage::Params params_t; - typedef typename Bin::template VectorBin<Storage> bin_t; - - private: - bin_t *bin; - params_t *params; - int offset; - int len; - void *stat; - - private: - mutable VResult *vec; - - Storage *data(int index) { - assert(index < len); - return bin->data(offset + index, *params); - } - - const Storage *data(int index) const { - bin_t *_bin = const_cast<bin_t *>(bin); - params_t *_params = const_cast<params_t *>(params); - return _bin->data(offset + index, *_params); - } - - public: - const VResult &result() const { - if (vec) - vec->resize(size()); - else - vec = new VResult(size()); - - for (int i = 0; i < size(); ++i) - (*vec)[i] = data(i)->result(*params); - - return *vec; - } - - Result total() const { - Result total = 0.0; - for (int i = 0; i < size(); ++i) - total += data(i)->result(*params); - return total; - } - - public: - VectorProxy(bin_t &b, params_t &p, int o, int l, void *s) - : bin(&b), params(&p), offset(o), len(l), stat(s), vec(NULL) - { - } - - VectorProxy(const VectorProxy &sp) - : bin(sp.bin), params(sp.params), offset(sp.offset), len(sp.len), - stat(sp.stat), vec(NULL) - { - } - - ~VectorProxy() - { - if (vec) - delete vec; - } - - const VectorProxy &operator=(const VectorProxy &sp) - { - bin = sp.bin; - params = sp.params; - offset = sp.offset; - len = sp.len; - stat = sp.stat; - if (vec) - delete vec; - vec = NULL; - return *this; - } - - ScalarProxy<Storage, Bin> operator[](int index) - { - assert (index >= 0 && index < size()); - return ScalarProxy<Storage, Bin>(*bin, *params, offset + index, stat); - } - - size_t size() const { return len; } - - /** - * Return true if stat is binned. - *@return false since Proxies aren't printed/binned - */ - bool binned() const { return false; } - - /** - * This stat has no state. Nothing to reset. - */ - void reset() { } -}; - -template <class Storage, class Bin> -inline VectorProxy<Storage, Bin> -Vector2dBase<Storage, Bin>::operator[](int index) -{ - int offset = index * y; - assert (index >= 0 && offset < size()); - return VectorProxy<Storage, Bin>(bin, params, offset, y, this); -} - -////////////////////////////////////////////////////////////////////// -// -// Non formula statistics -// -////////////////////////////////////////////////////////////////////// - -/** - * Templatized storage and interface for a distrbution stat. - */ -struct DistStor -{ - public: - /** The parameters for a distribution stat. */ - struct Params - { - /** The minimum value to track. */ - Counter min; - /** The maximum value to track. */ - Counter max; - /** The number of entries in each bucket. */ - Counter bucket_size; - /** The number of buckets. Equal to (max-min)/bucket_size. */ - int size; - }; - enum { fancy = false }; - - private: - /** The smallest value sampled. */ - Counter min_val; - /** The largest value sampled. */ - Counter max_val; - /** The number of values sampled less than min. */ - Counter underflow; - /** The number of values sampled more than max. */ - Counter overflow; - /** The current sum. */ - Counter sum; - /** The sum of squares. */ - Counter squares; - /** The number of samples. */ - Counter samples; - /** Counter for each bucket. */ - VCounter cvec; - - public: - /** - * Construct this storage with the supplied params. - * @param params The parameters. - */ - DistStor(const Params ¶ms) - : min_val(INT_MAX), max_val(INT_MIN), underflow(Counter()), - overflow(Counter()), sum(Counter()), squares(Counter()), - samples(Counter()), cvec(params.size) - { - reset(); - } - - /** - * Add a value to the distribution for the given number of times. - * @param val The value to add. - * @param number The number of times to add the value. - * @param params The paramters of the distribution. - */ - void sample(Counter val, int number, const Params ¶ms) - { - if (val < params.min) - underflow += number; - else if (val > params.max) - overflow += number; - else { - int index = (int)floor((val - params.min) / params.bucket_size); - assert(index < size(params)); - cvec[index] += number; - } - - if (val < min_val) - min_val = val; - - if (val > max_val) - max_val = val; - - Counter sample = val * number; - sum += sample; - squares += sample * sample; - samples += number; - } - - /** - * Return the number of buckets in this distribution. - * @return the number of buckets. - * @todo Is it faster to return the size from the parameters? - */ - size_t size(const Params &) const { return cvec.size(); } - - /** - * Returns true if any calls to sample have been made. - * @param params The paramters of the distribution. - * @return True if any values have been sampled. - */ - bool zero(const Params ¶ms) const - { - return samples == Counter(); - } - - void update(DistDataData *data, const Params ¶ms) - { - data->min = params.min; - data->max = params.max; - data->bucket_size = params.bucket_size; - data->size = params.size; - - data->min_val = (min_val == INT_MAX) ? 0 : min_val; - data->max_val = (max_val == INT_MIN) ? 0 : max_val; - data->underflow = underflow; - data->overflow = overflow; - data->cvec.resize(params.size); - for (int i = 0; i < params.size; ++i) - data->cvec[i] = cvec[i]; - - data->sum = sum; - data->squares = squares; - data->samples = samples; - } - - /** - * Reset stat value to default - */ - void reset() - { - min_val = INT_MAX; - max_val = INT_MIN; - underflow = 0; - overflow = 0; - - int size = cvec.size(); - for (int i = 0; i < size; ++i) - cvec[i] = Counter(); - - sum = Counter(); - squares = Counter(); - samples = Counter(); - } -}; - -/** - * Templatized storage and interface for a distribution that calculates mean - * and variance. - */ -struct FancyStor -{ - public: - /** - * No paramters for this storage. - */ - struct Params {}; - enum { fancy = true }; - - private: - /** The current sum. */ - Counter sum; - /** The sum of squares. */ - Counter squares; - /** The number of samples. */ - Counter samples; - - public: - /** - * Create and initialize this storage. - */ - FancyStor(const Params &) - : sum(Counter()), squares(Counter()), samples(Counter()) - { } - - /** - * Add a value the given number of times to this running average. - * Update the running sum and sum of squares, increment the number of - * values seen by the given number. - * @param val The value to add. - * @param number The number of times to add the value. - * @param p The parameters of this stat. - */ - void sample(Counter val, int number, const Params &p) - { - Counter value = val * number; - sum += value; - squares += value * value; - samples += number; - } - - void update(DistDataData *data, const Params ¶ms) - { - data->sum = sum; - data->squares = squares; - data->samples = samples; - } - - /** - * Return the number of entries in this stat, 1 - * @return 1. - */ - size_t size(const Params &) const { return 1; } - - /** - * Return true if no samples have been added. - * @return True if no samples have been added. - */ - bool zero(const Params &) const { return samples == Counter(); } - - /** - * Reset stat value to default - */ - void reset() - { - sum = Counter(); - squares = Counter(); - samples = Counter(); - } -}; - -/** - * Templatized storage for distribution that calculates per cycle mean and - * variance. - */ -struct AvgFancy -{ - public: - /** No parameters for this storage. */ - struct Params {}; - enum { fancy = true }; - - private: - /** Current total. */ - Counter sum; - /** Current sum of squares. */ - Counter squares; - - public: - /** - * Create and initialize this storage. - */ - AvgFancy(const Params &) : sum(Counter()), squares(Counter()) {} - - /** - * Add a value to the distribution for the given number of times. - * Update the running sum and sum of squares. - * @param val The value to add. - * @param number The number of times to add the value. - * @param p The paramters of the distribution. - */ - void sample(Counter val, int number, const Params &p) - { - Counter value = val * number; - sum += value; - squares += value * value; - } - - void update(DistDataData *data, const Params ¶ms) - { - data->sum = sum; - data->squares = squares; - data->samples = curTick; - } - - /** - * Return the number of entries, in this case 1. - * @return 1. - */ - size_t size(const Params ¶ms) const { return 1; } - /** - * Return true if no samples have been added. - * @return True if the sum is zero. - */ - bool zero(const Params ¶ms) const { return sum == Counter(); } - /** - * Reset stat value to default - */ - void reset() - { - sum = Counter(); - squares = Counter(); - } -}; - -/** - * Implementation of a distribution stat. The type of distribution is - * determined by the Storage template. @sa ScalarBase - */ -template <class Storage, class Bin> -class DistBase : public DataAccess -{ - public: - /** Define the params of the storage class. */ - typedef typename Storage::Params params_t; - /** Define the bin type. */ - typedef typename Bin::template Bin<Storage> bin_t; - - protected: - /** The bin of this stat. */ - bin_t bin; - /** The parameters for this stat. */ - params_t params; - - protected: - /** - * Retrieve the storage from the bin. - * @return The storage object for this stat. - */ - Storage *data() { return bin.data(params); } - /** - * Retrieve a const pointer to the storage from the bin. - * @return A const pointer to the storage object for this stat. - */ - const Storage *data() const - { - bin_t *_bin = const_cast<bin_t *>(&bin); - params_t *_params = const_cast<params_t *>(¶ms); - return _bin->data(*_params); - } - - public: - DistBase() { } - - /** - * Add a value to the distribtion n times. Calls sample on the storage - * class. - * @param v The value to add. - * @param n The number of times to add it, defaults to 1. - */ - template <typename U> - void sample(const U &v, int n = 1) { data()->sample(v, n, params); } - - /** - * Return the number of entries in this stat. - * @return The number of entries. - */ - size_t size() const { return data()->size(params); } - /** - * Return true if no samples have been added. - * @return True if there haven't been any samples. - */ - bool zero() const { return data()->zero(params); } - - void update(DistData *base) - { - base->data.fancy = Storage::fancy; - data()->update(&(base->data), params); - } - /** - * @return True is stat is binned. - */ - bool binned() const { return bin_t::binned; } - /** - * Reset stat value to default - */ - void reset() - { - bin.reset(); - } - - bool check() { return bin.initialized(); } -}; - -template <class Storage, class Bin> -class DistProxy; - -template <class Storage, class Bin> -class VectorDistBase : public DataAccess -{ - public: - typedef typename Storage::Params params_t; - typedef typename Bin::template VectorBin<Storage> bin_t; - - protected: - bin_t bin; - params_t params; - - protected: - Storage *data(int index) { return bin.data(index, params); } - const Storage *data(int index) const - { - bin_t *_bin = const_cast<bin_t *>(&bin); - params_t *_params = const_cast<params_t *>(¶ms); - return _bin->data(index, *_params); - } - - public: - VectorDistBase() {} - - friend class DistProxy<Storage, Bin>; - DistProxy<Storage, Bin> operator[](int index); - const DistProxy<Storage, Bin> operator[](int index) const; - - size_t size() const { return bin.size(); } - bool zero() const { return false; } - /** - * Return true if stat is binned. - *@return True is stat is binned. - */ - bool binned() const { return bin_t::binned; } - /** - * Reset stat value to default - */ - void reset() { bin.reset(); } - - bool check() { return bin.initialized(); } - void update(VectorDistData *base) - { - int size = this->size(); - base->data.resize(size); - for (int i = 0; i < size; ++i) { - base->data[i].fancy = Storage::fancy; - data(i)->update(&(base->data[i]), params); - } - } -}; - -template <class Storage, class Bin> -class DistProxy -{ - public: - typedef typename Storage::Params params_t; - typedef typename Bin::template Bin<Storage> bin_t; - typedef VectorDistBase<Storage, Bin> base_t; - - private: - union { - base_t *stat; - const base_t *cstat; - }; - int index; - - protected: - Storage *data() { return stat->data(index); } - const Storage *data() const { return cstat->data(index); } - - public: - DistProxy(const VectorDistBase<Storage, Bin> &s, int i) - : cstat(&s), index(i) {} - DistProxy(const DistProxy &sp) - : cstat(sp.cstat), index(sp.index) {} - const DistProxy &operator=(const DistProxy &sp) { - cstat = sp.cstat; index = sp.index; return *this; - } - - public: - template <typename U> - void sample(const U &v, int n = 1) { data()->sample(v, n, cstat->params); } - - size_t size() const { return 1; } - bool zero() const { return data()->zero(cstat->params); } - /** - * Return true if stat is binned. - *@return false since Proxies are not binned/printed. - */ - bool binned() const { return false; } - /** - * Proxy has no state. Nothing to reset. - */ - void reset() { } -}; - -template <class Storage, class Bin> -inline DistProxy<Storage, Bin> -VectorDistBase<Storage, Bin>::operator[](int index) -{ - assert (index >= 0 && index < size()); - return DistProxy<Storage, Bin>(*this, index); -} - -template <class Storage, class Bin> -inline const DistProxy<Storage, Bin> -VectorDistBase<Storage, Bin>::operator[](int index) const -{ - assert (index >= 0 && index < size()); - return DistProxy<Storage, Bin>(*this, index); -} - -#if 0 -template <class Storage, class Bin> -Result -VectorDistBase<Storage, Bin>::total(int index) const -{ - int total = 0; - for (int i=0; i < x_size(); ++i) { - total += data(i)->result(*params); - } -} -#endif - -////////////////////////////////////////////////////////////////////// -// -// Formula Details -// -////////////////////////////////////////////////////////////////////// - -/** - * Base class for formula statistic node. These nodes are used to build a tree - * that represents the formula. - */ -class Node : public RefCounted -{ - public: - /** - * Return the number of nodes in the subtree starting at this node. - * @return the number of nodes in this subtree. - */ - virtual size_t size() const = 0; - /** - * Return the result vector of this subtree. - * @return The result vector of this subtree. - */ - virtual const VResult &result() const = 0; - /** - * Return the total of the result vector. - * @return The total of the result vector. - */ - virtual Result total() const = 0; - /** - * Return true if stat is binned. - *@return True is stat is binned. - */ - virtual bool binned() const = 0; - - /** - * - */ - virtual std::string str() const = 0; -}; - -/** Reference counting pointer to a function Node. */ -typedef RefCountingPtr<Node> NodePtr; - -class ScalarStatNode : public Node -{ - private: - const ScalarData *data; - mutable VResult vresult; - - public: - ScalarStatNode(const ScalarData *d) : data(d), vresult(1) {} - virtual const VResult &result() const - { - vresult[0] = data->result(); - return vresult; - } - virtual Result total() const { return data->result(); }; - - virtual size_t size() const { return 1; } - /** - * Return true if stat is binned. - *@return True is stat is binned. - */ - virtual bool binned() const { return data->binned(); } - - /** - * - */ - virtual std::string str() const { return data->name; } -}; - -template <class Storage, class Bin> -class ScalarProxyNode : public Node -{ - private: - const ScalarProxy<Storage, Bin> proxy; - mutable VResult vresult; - - public: - ScalarProxyNode(const ScalarProxy<Storage, Bin> &p) - : proxy(p), vresult(1) { } - virtual const VResult &result() const - { - vresult[0] = proxy.result(); - return vresult; - } - virtual Result total() const { return proxy.result(); }; - - virtual size_t size() const { return 1; } - /** - * Return true if stat is binned. - *@return True is stat is binned. - */ - virtual bool binned() const { return proxy.binned(); } - - /** - * - */ - virtual std::string str() const { return proxy.str(); } -}; - -class VectorStatNode : public Node -{ - private: - const VectorData *data; - - public: - VectorStatNode(const VectorData *d) : data(d) { } - virtual const VResult &result() const { return data->result(); } - virtual Result total() const { return data->total(); }; - - virtual size_t size() const { return data->size(); } - /** - * Return true if stat is binned. - *@return True is stat is binned. - */ - virtual bool binned() const { return data->binned(); } - - virtual std::string str() const { return data->name; } -}; - -template <class T> -class ConstNode : public Node -{ - private: - VResult vresult; - - public: - ConstNode(T s) : vresult(1, (Result)s) {} - const VResult &result() const { return vresult; } - virtual Result total() const { return vresult[0]; }; - virtual size_t size() const { return 1; } - - /** - * Return true if stat is binned. - *@return False since constants aren't binned. - */ - virtual bool binned() const { return false; } - - virtual std::string str() const { return to_string(vresult[0]); } -}; - -template <class Op> -struct OpString; - -template<> -struct OpString<std::plus<Result> > -{ - static std::string str() { return "+"; } -}; - -template<> -struct OpString<std::minus<Result> > -{ - static std::string str() { return "-"; } -}; - -template<> -struct OpString<std::multiplies<Result> > -{ - static std::string str() { return "*"; } -}; - -template<> -struct OpString<std::divides<Result> > -{ - static std::string str() { return "/"; } -}; - -template<> -struct OpString<std::modulus<Result> > -{ - static std::string str() { return "%"; } -}; - -template<> -struct OpString<std::negate<Result> > -{ - static std::string str() { return "-"; } -}; - -template <class Op> -class UnaryNode : public Node -{ - public: - NodePtr l; - mutable VResult vresult; - - public: - UnaryNode(NodePtr &p) : l(p) {} - - const VResult &result() const - { - const VResult &lvec = l->result(); - int size = lvec.size(); - - assert(size > 0); - - vresult.resize(size); - Op op; - for (int i = 0; i < size; ++i) - vresult[i] = op(lvec[i]); - - return vresult; - } - - Result total() const { - Op op; - return op(l->total()); - } - - virtual size_t size() const { return l->size(); } - /** - * Return true if child of node is binned. - *@return True if child of node is binned. - */ - virtual bool binned() const { return l->binned(); } - - virtual std::string str() const - { - return OpString<Op>::str() + l->str(); - } -}; - -template <class Op> -class BinaryNode : public Node -{ - public: - NodePtr l; - NodePtr r; - mutable VResult vresult; - - public: - BinaryNode(NodePtr &a, NodePtr &b) : l(a), r(b) {} - - const VResult &result() const - { - Op op; - const VResult &lvec = l->result(); - const VResult &rvec = r->result(); - - assert(lvec.size() > 0 && rvec.size() > 0); - - if (lvec.size() == 1 && rvec.size() == 1) { - vresult.resize(1); - vresult[0] = op(lvec[0], rvec[0]); - } else if (lvec.size() == 1) { - int size = rvec.size(); - vresult.resize(size); - for (int i = 0; i < size; ++i) - vresult[i] = op(lvec[0], rvec[i]); - } else if (rvec.size() == 1) { - int size = lvec.size(); - vresult.resize(size); - for (int i = 0; i < size; ++i) - vresult[i] = op(lvec[i], rvec[0]); - } else if (rvec.size() == lvec.size()) { - int size = rvec.size(); - vresult.resize(size); - for (int i = 0; i < size; ++i) - vresult[i] = op(lvec[i], rvec[i]); - } - - return vresult; - } - - Result total() const { - Op op; - return op(l->total(), r->total()); - } - - virtual size_t size() const { - int ls = l->size(); - int rs = r->size(); - if (ls == 1) - return rs; - else if (rs == 1) - return ls; - else { - assert(ls == rs && "Node vector sizes are not equal"); - return ls; - } - } - /** - * Return true if any children of node are binned - *@return True if either child of node is binned. - */ - virtual bool binned() const { return (l->binned() || r->binned()); } - - virtual std::string str() const - { - return csprintf("(%s %s %s)", l->str(), OpString<Op>::str(), r->str()); - } -}; - -template <class Op> -class SumNode : public Node -{ - public: - NodePtr l; - mutable VResult vresult; - - public: - SumNode(NodePtr &p) : l(p), vresult(1) {} - - const VResult &result() const - { - const VResult &lvec = l->result(); - int size = lvec.size(); - assert(size > 0); - - vresult[0] = 0.0; - - Op op; - for (int i = 0; i < size; ++i) - vresult[0] = op(vresult[0], lvec[i]); - - return vresult; - } - - Result total() const - { - const VResult &lvec = l->result(); - int size = lvec.size(); - assert(size > 0); - - Result vresult = 0.0; - - Op op; - for (int i = 0; i < size; ++i) - vresult = op(vresult, lvec[i]); - - return vresult; - } - - virtual size_t size() const { return 1; } - /** - * Return true if child of node is binned. - *@return True if child of node is binned. - */ - virtual bool binned() const { return l->binned(); } - - virtual std::string str() const - { - return csprintf("total(%s)", l->str()); - } -}; - - -////////////////////////////////////////////////////////////////////// -// -// Visible Statistics Types -// -////////////////////////////////////////////////////////////////////// -/** - * @defgroup VisibleStats "Statistic Types" - * These are the statistics that are used in the simulator. By default these - * store counters and don't use binning, but are templatized to accept any type - * and any Bin class. - * @{ - */ - -/** - * This is an easy way to assign all your stats to be binned or not - * binned. If the typedef is NoBin, nothing is binned. If it is - * MainBin, then all stats are binned under that Bin. - */ -#if STATS_BINNING -typedef MainBin DefaultBin; -#else -typedef NoBin DefaultBin; -#endif - -/** - * This is a simple scalar statistic, like a counter. - * @sa Stat, ScalarBase, StatStor - */ -template <class Bin = DefaultBin> -class Scalar - : public Wrap<Scalar<Bin>, - ScalarBase<StatStor, Bin>, - ScalarStatData> -{ - public: - /** The base implementation. */ - typedef ScalarBase<StatStor, Bin> Base; - - Scalar() - { - this->setInit(); - } - - /** - * Sets the stat equal to the given value. Calls the base implementation - * of operator= - * @param v The new value. - */ - template <typename U> - void operator=(const U &v) { Base::operator=(v); } -}; - -class Value - : public Wrap<Value, - ValueBase, - ScalarStatData> -{ - public: - /** The base implementation. */ - typedef ValueBase Base; - - template <class T> - Value &scalar(T &value) - { - Base::scalar(value); - return *this; - } - - template <class T> - Value &functor(T &func) - { - Base::functor(func); - return *this; - } -}; - -/** - * A stat that calculates the per cycle average of a value. - * @sa Stat, ScalarBase, AvgStor - */ -template <class Bin = DefaultBin> -class Average - : public Wrap<Average<Bin>, - ScalarBase<AvgStor, Bin>, - ScalarStatData> -{ - public: - /** The base implementation. */ - typedef ScalarBase<AvgStor, Bin> Base; - - Average() - { - this->setInit(); - } - - /** - * Sets the stat equal to the given value. Calls the base implementation - * of operator= - * @param v The new value. - */ - template <typename U> - void operator=(const U &v) { Base::operator=(v); } -}; - -/** - * A vector of scalar stats. - * @sa Stat, VectorBase, StatStor - */ -template <class Bin = DefaultBin> -class Vector - : public WrapVec<Vector<Bin>, - VectorBase<StatStor, Bin>, - VectorStatData> -{ - public: - /** The base implementation. */ - typedef ScalarBase<StatStor, Bin> Base; - - /** - * Set this vector to have the given size. - * @param size The new size. - * @return A reference to this stat. - */ - Vector &init(size_t size) { - this->bin.init(size, this->params); - this->setInit(); - - return *this; - } -}; - -/** - * A vector of Average stats. - * @sa Stat, VectorBase, AvgStor - */ -template <class Bin = DefaultBin> -class AverageVector - : public WrapVec<AverageVector<Bin>, - VectorBase<AvgStor, Bin>, - VectorStatData> -{ - public: - /** - * Set this vector to have the given size. - * @param size The new size. - * @return A reference to this stat. - */ - AverageVector &init(size_t size) { - this->bin.init(size, this->params); - this->setInit(); - - return *this; - } -}; - -/** - * A 2-Dimensional vecto of scalar stats. - * @sa Stat, Vector2dBase, StatStor - */ -template <class Bin = DefaultBin> -class Vector2d - : public WrapVec2d<Vector2d<Bin>, - Vector2dBase<StatStor, Bin>, - Vector2dStatData> -{ - public: - Vector2d &init(size_t _x, size_t _y) { - this->statData()->x = this->x = _x; - this->statData()->y = this->y = _y; - this->bin.init(this->x * this->y, this->params); - this->setInit(); - - return *this; - } -}; - -/** - * A simple distribution stat. - * @sa Stat, DistBase, DistStor - */ -template <class Bin = DefaultBin> -class Distribution - : public Wrap<Distribution<Bin>, - DistBase<DistStor, Bin>, - DistStatData> -{ - public: - /** Base implementation. */ - typedef DistBase<DistStor, Bin> Base; - /** The Parameter type. */ - typedef typename DistStor::Params Params; - - public: - /** - * Set the parameters of this distribution. @sa DistStor::Params - * @param min The minimum value of the distribution. - * @param max The maximum value of the distribution. - * @param bkt The number of values in each bucket. - * @return A reference to this distribution. - */ - Distribution &init(Counter min, Counter max, Counter bkt) { - this->params.min = min; - this->params.max = max; - this->params.bucket_size = bkt; - this->params.size = (int)rint((max - min) / bkt + 1.0); - this->bin.init(this->params); - this->setInit(); - - return *this; - } -}; - -/** - * Calculates the mean and variance of all the samples. - * @sa Stat, DistBase, FancyStor - */ -template <class Bin = DefaultBin> -class StandardDeviation - : public Wrap<StandardDeviation<Bin>, - DistBase<FancyStor, Bin>, - DistStatData> -{ - public: - /** The base implementation */ - typedef DistBase<DistStor, Bin> Base; - /** The parameter type. */ - typedef typename DistStor::Params Params; - - public: - /** - * Construct and initialize this distribution. - */ - StandardDeviation() { - this->bin.init(this->params); - this->setInit(); - } -}; - -/** - * Calculates the per cycle mean and variance of the samples. - * @sa Stat, DistBase, AvgFancy - */ -template <class Bin = DefaultBin> -class AverageDeviation - : public Wrap<AverageDeviation<Bin>, - DistBase<AvgFancy, Bin>, - DistStatData> -{ - public: - /** The base implementation */ - typedef DistBase<DistStor, Bin> Base; - /** The parameter type. */ - typedef typename DistStor::Params Params; - - public: - /** - * Construct and initialize this distribution. - */ - AverageDeviation() - { - this->bin.init(this->params); - this->setInit(); - } -}; - -/** - * A vector of distributions. - * @sa Stat, VectorDistBase, DistStor - */ -template <class Bin = DefaultBin> -class VectorDistribution - : public WrapVec<VectorDistribution<Bin>, - VectorDistBase<DistStor, Bin>, - VectorDistStatData> -{ - public: - /** The base implementation */ - typedef VectorDistBase<DistStor, Bin> Base; - /** The parameter type. */ - typedef typename DistStor::Params Params; - - public: - /** - * Initialize storage and parameters for this distribution. - * @param size The size of the vector (the number of distributions). - * @param min The minimum value of the distribution. - * @param max The maximum value of the distribution. - * @param bkt The number of values in each bucket. - * @return A reference to this distribution. - */ - VectorDistribution &init(int size, Counter min, Counter max, Counter bkt) { - this->params.min = min; - this->params.max = max; - this->params.bucket_size = bkt; - this->params.size = (int)rint((max - min) / bkt + 1.0); - this->bin.init(size, this->params); - this->setInit(); - - return *this; - } -}; - -/** - * This is a vector of StandardDeviation stats. - * @sa Stat, VectorDistBase, FancyStor - */ -template <class Bin = DefaultBin> -class VectorStandardDeviation - : public WrapVec<VectorStandardDeviation<Bin>, - VectorDistBase<FancyStor, Bin>, - VectorDistStatData> -{ - public: - /** The base implementation */ - typedef VectorDistBase<FancyStor, Bin> Base; - /** The parameter type. */ - typedef typename DistStor::Params Params; - - public: - /** - * Initialize storage for this distribution. - * @param size The size of the vector. - * @return A reference to this distribution. - */ - VectorStandardDeviation &init(int size) { - this->bin.init(size, this->params); - this->setInit(); - - return *this; - } -}; - -/** - * This is a vector of AverageDeviation stats. - * @sa Stat, VectorDistBase, AvgFancy - */ -template <class Bin = DefaultBin> -class VectorAverageDeviation - : public WrapVec<VectorAverageDeviation<Bin>, - VectorDistBase<AvgFancy, Bin>, - VectorDistStatData> -{ - public: - /** The base implementation */ - typedef VectorDistBase<AvgFancy, Bin> Base; - /** The parameter type. */ - typedef typename DistStor::Params Params; - - public: - /** - * Initialize storage for this distribution. - * @param size The size of the vector. - * @return A reference to this distribution. - */ - VectorAverageDeviation &init(int size) { - this->bin.init(size, this->params); - this->setInit(); - - return *this; - } -}; - -/** - * A formula for statistics that is calculated when printed. A formula is - * stored as a tree of Nodes that represent the equation to calculate. - * @sa Stat, ScalarStat, VectorStat, Node, Temp - */ -class FormulaBase : public DataAccess -{ - protected: - /** The root of the tree which represents the Formula */ - NodePtr root; - friend class Temp; - - public: - /** - * Return the result of the Fomula in a vector. If there were no Vector - * components to the Formula, then the vector is size 1. If there were, - * like x/y with x being a vector of size 3, then the result returned will - * be x[0]/y, x[1]/y, x[2]/y, respectively. - * @return The result vector. - */ - void result(VResult &vec) const; - - /** - * Return the total Formula result. If there is a Vector - * component to this Formula, then this is the result of the - * Formula if the formula is applied after summing all the - * components of the Vector. For example, if Formula is x/y where - * x is size 3, then total() will return (x[1]+x[2]+x[3])/y. If - * there is no Vector component, total() returns the same value as - * the first entry in the VResult val() returns. - * @return The total of the result vector. - */ - Result total() const; - - /** - * Return the number of elements in the tree. - */ - size_t size() const; - - /** - * Return true if Formula is binned. i.e. any of its children - * nodes are binned - * @return True if Formula is binned. - */ - bool binned() const; - - bool check() const { return true; } - - /** - * Formulas don't need to be reset - */ - void reset(); - - /** - * - */ - bool zero() const; - - /** - * - */ - void update(StatData *); - - std::string str() const; -}; - -class FormulaData : public VectorData -{ - public: - virtual std::string str() const = 0; - virtual bool check() const { return true; } -}; - -template <class Stat> -class FormulaStatData : public FormulaData -{ - protected: - Stat &s; - mutable VResult vec; - mutable VCounter cvec; - - public: - FormulaStatData(Stat &stat) : s(stat) {} - - virtual bool binned() const { return s.binned(); } - virtual bool zero() const { return s.zero(); } - virtual void reset() { s.reset(); } - - virtual size_t size() const { return s.size(); } - virtual const VResult &result() const - { - s.result(vec); - return vec; - } - virtual Result total() const { return s.total(); } - virtual VCounter &value() const { return cvec; } - virtual void visit(Visit &visitor) - { - update(); - s.update(this); - visitor.visit(*this); - } - virtual std::string str() const { return s.str(); } -}; - -class Temp; -class Formula - : public WrapVec<Formula, - FormulaBase, - FormulaStatData> -{ - public: - /** - * Create and initialize thie formula, and register it with the database. - */ - Formula(); - - /** - * Create a formula with the given root node, register it with the - * database. - * @param r The root of the expression tree. - */ - Formula(Temp r); - - /** - * Set an unitialized Formula to the given root. - * @param r The root of the expression tree. - * @return a reference to this formula. - */ - const Formula &operator=(Temp r); - - /** - * Add the given tree to the existing one. - * @param r The root of the expression tree. - * @return a reference to this formula. - */ - const Formula &operator+=(Temp r); -}; - -class FormulaNode : public Node -{ - private: - const Formula &formula; - mutable VResult vec; - - public: - FormulaNode(const Formula &f) : formula(f) {} - - virtual size_t size() const { return formula.size(); } - virtual const VResult &result() const { formula.result(vec); return vec; } - virtual Result total() const { return formula.total(); } - virtual bool binned() const { return formula.binned(); } - - virtual std::string str() const { return formula.str(); } -}; - -/** - * Helper class to construct formula node trees. - */ -class Temp -{ - protected: - /** - * Pointer to a Node object. - */ - NodePtr node; - - public: - /** - * Copy the given pointer to this class. - * @param n A pointer to a Node object to copy. - */ - Temp(NodePtr n) : node(n) { } - - /** - * Return the node pointer. - * @return the node pointer. - */ - operator NodePtr&() { return node;} - - public: - /** - * Create a new ScalarStatNode. - * @param s The ScalarStat to place in a node. - */ - template <class Bin> - Temp(const Scalar<Bin> &s) - : node(new ScalarStatNode(s.statData())) { } - - /** - * Create a new ScalarStatNode. - * @param s The ScalarStat to place in a node. - */ - Temp(const Value &s) - : node(new ScalarStatNode(s.statData())) { } - - /** - * Create a new ScalarStatNode. - * @param s The ScalarStat to place in a node. - */ - template <class Bin> - Temp(const Average<Bin> &s) - : node(new ScalarStatNode(s.statData())) { } - - /** - * Create a new VectorStatNode. - * @param s The VectorStat to place in a node. - */ - template <class Bin> - Temp(const Vector<Bin> &s) - : node(new VectorStatNode(s.statData())) { } - - /** - * - */ - Temp(const Formula &f) - : node(new FormulaNode(f)) { } - - /** - * Create a new ScalarProxyNode. - * @param p The ScalarProxy to place in a node. - */ - template <class Storage, class Bin> - Temp(const ScalarProxy<Storage, Bin> &p) - : node(new ScalarProxyNode<Storage, Bin>(p)) { } - - /** - * Create a ConstNode - * @param value The value of the const node. - */ - Temp(signed char value) - : node(new ConstNode<signed char>(value)) {} - - /** - * Create a ConstNode - * @param value The value of the const node. - */ - Temp(unsigned char value) - : node(new ConstNode<unsigned char>(value)) {} - - /** - * Create a ConstNode - * @param value The value of the const node. - */ - Temp(signed short value) - : node(new ConstNode<signed short>(value)) {} - - /** - * Create a ConstNode - * @param value The value of the const node. - */ - Temp(unsigned short value) - : node(new ConstNode<unsigned short>(value)) {} - - /** - * Create a ConstNode - * @param value The value of the const node. - */ - Temp(signed int value) - : node(new ConstNode<signed int>(value)) {} - - /** - * Create a ConstNode - * @param value The value of the const node. - */ - Temp(unsigned int value) - : node(new ConstNode<unsigned int>(value)) {} - - /** - * Create a ConstNode - * @param value The value of the const node. - */ - Temp(signed long value) - : node(new ConstNode<signed long>(value)) {} - - /** - * Create a ConstNode - * @param value The value of the const node. - */ - Temp(unsigned long value) - : node(new ConstNode<unsigned long>(value)) {} - - /** - * Create a ConstNode - * @param value The value of the const node. - */ - Temp(signed long long value) - : node(new ConstNode<signed long long>(value)) {} - - /** - * Create a ConstNode - * @param value The value of the const node. - */ - Temp(unsigned long long value) - : node(new ConstNode<unsigned long long>(value)) {} - - /** - * Create a ConstNode - * @param value The value of the const node. - */ - Temp(float value) - : node(new ConstNode<float>(value)) {} - - /** - * Create a ConstNode - * @param value The value of the const node. - */ - Temp(double value) - : node(new ConstNode<double>(value)) {} -}; - - -/** - * @} - */ - -void check(); -void reset(); -void registerResetCallback(Callback *cb); - -inline Temp -operator+(Temp l, Temp r) -{ - return NodePtr(new BinaryNode<std::plus<Result> >(l, r)); -} - -inline Temp -operator-(Temp l, Temp r) -{ - return NodePtr(new BinaryNode<std::minus<Result> >(l, r)); -} - -inline Temp -operator*(Temp l, Temp r) -{ - return NodePtr(new BinaryNode<std::multiplies<Result> >(l, r)); -} - -inline Temp -operator/(Temp l, Temp r) -{ - return NodePtr(new BinaryNode<std::divides<Result> >(l, r)); -} - -inline Temp -operator-(Temp l) -{ - return NodePtr(new UnaryNode<std::negate<Result> >(l)); -} - -template <typename T> -inline Temp -constant(T val) -{ - return NodePtr(new ConstNode<T>(val)); -} - -inline Temp -sum(Temp val) -{ - return NodePtr(new SumNode<std::plus<Result> >(val)); -} - -/* namespace Stats */ } - -#endif // __BASE_STATISTICS_HH__ diff --git a/base/stats/text.cc b/base/stats/text.cc deleted file mode 100644 index 3d77ff87d..000000000 --- a/base/stats/text.cc +++ /dev/null @@ -1,735 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(__APPLE__) -#define _GLIBCPP_USE_C99 1 -#endif - -#include <iostream> -#include <fstream> -#include <string> - -#include "base/misc.hh" -#include "base/statistics.hh" -#include "base/stats/statdb.hh" -#include "base/stats/text.hh" -#include "base/stats/visit.hh" - -using namespace std; - -#ifndef NAN -float __nan(); -/** Define Not a number. */ -#define NAN (__nan()) -/** Need to define __nan() */ -#define __M5_NAN -#endif - -#ifdef __M5_NAN -float -__nan() -{ - union { - uint32_t ui; - float f; - } nan; - - nan.ui = 0x7fc00000; - return nan.f; -} -#endif - -namespace Stats { - -Text::Text() - : mystream(false), stream(NULL), compat(false), descriptions(false) -{ -} - -Text::Text(std::ostream &stream) - : mystream(false), stream(NULL), compat(false), descriptions(false) -{ - open(stream); -} - -Text::Text(const std::string &file) - : mystream(false), stream(NULL), compat(false), descriptions(false) -{ - open(file); -} - - -Text::~Text() -{ - if (mystream) { - assert(stream); - delete stream; - } -} - -void -Text::open(std::ostream &_stream) -{ - if (stream) - panic("stream already set!"); - - mystream = false; - stream = &_stream; - assert(valid()); -} - -void -Text::open(const std::string &file) -{ - if (stream) - panic("stream already set!"); - - mystream = true; - stream = new ofstream(file.c_str(), ios::trunc); - assert(valid()); -} - -bool -Text::valid() const -{ - return stream != NULL; -} - -void -Text::output() -{ - using namespace Database; - - ccprintf(*stream, "\n---------- Begin Simulation Statistics ----------\n"); - if (bins().empty() || bins().size() == 1) { - stat_list_t::const_iterator i, end = stats().end(); - for (i = stats().begin(); i != end; ++i) - (*i)->visit(*this); - } else { - ccprintf(*stream, "PRINTING BINNED STATS\n"); - bin_list_t::iterator i, end = bins().end(); - for (i = bins().begin(); i != end; ++i) { - MainBin *bin = *i; - bin->activate(); - ccprintf(*stream,"---%s Bin------------\n", bin->name()); - stat_list_t::const_iterator i, end = stats().end(); - for (i = stats().begin(); i != end; ++i) - (*i)->visit(*this); - ccprintf(*stream, "---------------------------------\n"); - } - } - ccprintf(*stream, "\n---------- End Simulation Statistics ----------\n"); - stream->flush(); -} - -bool -Text::noOutput(const StatData &data) -{ - if (!(data.flags & print)) - return true; - - if (data.prereq && data.prereq->zero()) - return true; - - return false; -} - -string -ValueToString(Result value, int precision, bool compat) -{ - stringstream val; - - if (!isnan(value)) { - if (precision != -1) - val.precision(precision); - else if (value == rint(value)) - val.precision(0); - - val.unsetf(ios::showpoint); - val.setf(ios::fixed); - val << value; - } else { - val << (compat ? "<err: div-0>" : "no value"); - } - - return val.str(); -} - -struct ScalarPrint -{ - Result value; - string name; - string desc; - StatFlags flags; - bool compat; - bool descriptions; - int precision; - Result pdf; - Result cdf; - - void operator()(ostream &stream) const; -}; - -void -ScalarPrint::operator()(ostream &stream) const -{ - if (flags & nozero && value == 0.0 || - flags & nonan && isnan(value)) - return; - - stringstream pdfstr, cdfstr; - - if (!isnan(pdf)) - ccprintf(pdfstr, "%.2f%%", pdf * 100.0); - - if (!isnan(cdf)) - ccprintf(cdfstr, "%.2f%%", cdf * 100.0); - - if (compat && flags & __substat) { - ccprintf(stream, "%32s %12s %10s %10s", name, - ValueToString(value, precision, compat), pdfstr, cdfstr); - } else { - ccprintf(stream, "%-40s %12s %10s %10s", name, - ValueToString(value, precision, compat), pdfstr, cdfstr); - } - - if (descriptions) { - if (!desc.empty()) - ccprintf(stream, " # %s", desc); - } - stream << endl; -} - -struct VectorPrint -{ - string name; - string desc; - vector<string> subnames; - vector<string> subdescs; - StatFlags flags; - bool compat; - bool descriptions; - int precision; - VResult vec; - Result total; - - void operator()(ostream &stream) const; -}; - -void -VectorPrint::operator()(std::ostream &stream) const -{ - int _size = vec.size(); - Result _total = 0.0; - - if (flags & (pdf | cdf)) { - for (int i = 0; i < _size; ++i) { - _total += vec[i]; - } - } - - string base = name + (compat ? "_" : "::"); - - ScalarPrint print; - print.name = name; - print.desc = desc; - print.precision = precision; - print.descriptions = descriptions; - print.flags = flags; - print.pdf = NAN; - print.cdf = NAN; - - bool havesub = !subnames.empty(); - - if (_size == 1) { - print.value = vec[0]; - print(stream); - } else if (!compat) { - for (int i = 0; i < _size; ++i) { - if (havesub && (i >= subnames.size() || subnames[i].empty())) - continue; - - print.name = base + (havesub ? subnames[i] : to_string(i)); - print.desc = subdescs.empty() ? desc : subdescs[i]; - print.value = vec[i]; - - if (_total && (flags & pdf)) { - print.pdf = vec[i] / _total; - print.cdf += print.pdf; - } - - print(stream); - } - - if (flags & ::Stats::total) { - print.name = base + "total"; - print.desc = desc; - print.value = total; - print(stream); - } - } else { - if (flags & ::Stats::total) { - print.value = total; - print(stream); - } - - Result _pdf = 0.0; - Result _cdf = 0.0; - if (flags & dist) { - ccprintf(stream, "%s.start_dist\n", name); - for (int i = 0; i < _size; ++i) { - print.name = havesub ? subnames[i] : to_string(i); - print.desc = subdescs.empty() ? desc : subdescs[i]; - print.flags |= __substat; - print.value = vec[i]; - - if (_total) { - _pdf = vec[i] / _total; - _cdf += _pdf; - } - - if (flags & pdf) - print.pdf = _pdf; - if (flags & cdf) - print.cdf = _cdf; - - print(stream); - } - ccprintf(stream, "%s.end_dist\n", name); - } else { - for (int i = 0; i < _size; ++i) { - if (havesub && subnames[i].empty()) - continue; - - print.name = base; - print.name += havesub ? subnames[i] : to_string(i); - print.desc = subdescs.empty() ? desc : subdescs[i]; - print.value = vec[i]; - - if (_total) { - _pdf = vec[i] / _total; - _cdf += _pdf; - } else { - _pdf = _cdf = NAN; - } - - if (flags & pdf) { - print.pdf = _pdf; - print.cdf = _cdf; - } - - print(stream); - } - } - } -} - -struct DistPrint -{ - string name; - string desc; - StatFlags flags; - bool compat; - bool descriptions; - int precision; - - Result min_val; - Result max_val; - Result underflow; - Result overflow; - VResult vec; - Result sum; - Result squares; - Result samples; - - Counter min; - Counter max; - Counter bucket_size; - int size; - bool fancy; - - void operator()(ostream &stream) const; -}; - -void -DistPrint::operator()(ostream &stream) const -{ - if (fancy) { - ScalarPrint print; - string base = name + (compat ? "_" : "::"); - - print.precision = precision; - print.flags = flags; - print.compat = compat; - print.descriptions = descriptions; - print.desc = desc; - print.pdf = NAN; - print.cdf = NAN; - - print.name = base + "mean"; - print.value = samples ? sum / samples : NAN; - print(stream); - - print.name = base + "stdev"; - print.value = samples ? sqrt((samples * squares - sum * sum) / - (samples * (samples - 1.0))) : NAN; - print(stream); - - print.name = "**Ignore: " + base + "TOT"; - print.value = samples; - print(stream); - return; - } - - assert(size == vec.size()); - - Result total = 0.0; - - total += underflow; - for (int i = 0; i < size; ++i) - total += vec[i]; - total += overflow; - - string base = name + (compat ? "." : "::"); - - ScalarPrint print; - print.desc = compat ? "" : desc; - print.flags = flags; - print.compat = compat; - print.descriptions = descriptions; - print.precision = precision; - print.pdf = NAN; - print.cdf = NAN; - - if (compat) { - ccprintf(stream, "%-42s", base + "start_dist"); - if (descriptions && !desc.empty()) - ccprintf(stream, " # %s", desc); - stream << endl; - } - - print.name = base + "samples"; - print.value = samples; - print(stream); - - print.name = base + "min_value"; - print.value = min_val; - print(stream); - - if (!compat || underflow > 0.0) { - print.name = base + "underflows"; - print.value = underflow; - if (!compat && total) { - print.pdf = underflow / total; - print.cdf += print.pdf; - } - print(stream); - } - - - if (!compat) { - for (int i = 0; i < size; ++i) { - stringstream namestr; - namestr << name; - - Counter low = i * bucket_size + min; - Counter high = ::min(low + bucket_size, max); - namestr << low; - if (low < high) - namestr << "-" << high; - - print.name = namestr.str(); - print.value = vec[i]; - if (total) { - print.pdf = vec[i] / total; - print.cdf += print.pdf; - } - print(stream); - } - - } else { - Counter _min; - Result _pdf; - Result _cdf = 0.0; - - print.flags = flags | __substat; - - for (int i = 0; i < size; ++i) { - if (flags & nozero && vec[i] == 0.0 || - flags & nonan && isnan(vec[i])) - continue; - - _min = i * bucket_size + min; - _pdf = vec[i] / total * 100.0; - _cdf += _pdf; - - - print.name = ValueToString(_min, 0, compat); - print.value = vec[i]; - print.pdf = (flags & pdf) ? _pdf : NAN; - print.cdf = (flags & cdf) ? _cdf : NAN; - print(stream); - } - - print.flags = flags; - } - - if (!compat || overflow > 0.0) { - print.name = base + "overflows"; - print.value = overflow; - if (!compat && total) { - print.pdf = overflow / total; - print.cdf += print.pdf; - } else { - print.pdf = NAN; - print.cdf = NAN; - } - print(stream); - } - - print.pdf = NAN; - print.cdf = NAN; - - if (!compat) { - print.name = base + "total"; - print.value = total; - print(stream); - } - - print.name = base + "max_value"; - print.value = max_val; - print(stream); - - if (!compat && samples != 0) { - print.name = base + "mean"; - print.value = sum / samples; - print(stream); - - print.name = base + "stdev"; - print.value = sqrt((samples * squares - sum * sum) / - (samples * (samples - 1.0))); - print(stream); - } - - if (compat) - ccprintf(stream, "%send_dist\n\n", base); -} - -void -Text::visit(const ScalarData &data) -{ - if (noOutput(data)) - return; - - ScalarPrint print; - print.value = data.result(); - print.name = data.name; - print.desc = data.desc; - print.flags = data.flags; - print.compat = compat; - print.descriptions = descriptions; - print.precision = data.precision; - print.pdf = NAN; - print.cdf = NAN; - - print(*stream); -} - -void -Text::visit(const VectorData &data) -{ - if (noOutput(data)) - return; - - int size = data.size(); - VectorPrint print; - - print.name = data.name; - print.desc = data.desc; - print.flags = data.flags; - print.compat = compat; - print.descriptions = descriptions; - print.precision = data.precision; - print.vec = data.result(); - print.total = data.total(); - - if (!data.subnames.empty()) { - for (int i = 0; i < size; ++i) { - if (!data.subnames[i].empty()) { - print.subnames = data.subnames; - print.subnames.resize(size); - for (int i = 0; i < size; ++i) { - if (!data.subnames[i].empty() && - !data.subdescs[i].empty()) { - print.subdescs = data.subdescs; - print.subdescs.resize(size); - break; - } - } - break; - } - } - } - - print(*stream); -} - -void -Text::visit(const Vector2dData &data) -{ - if (noOutput(data)) - return; - - bool havesub = false; - VectorPrint print; - - print.subnames = data.y_subnames; - print.flags = data.flags; - print.compat = compat; - print.descriptions = descriptions; - print.precision = data.precision; - - if (!data.subnames.empty()) { - for (int i = 0; i < data.x; ++i) - if (!data.subnames[i].empty()) - havesub = true; - } - - VResult tot_vec(data.y); - Result super_total = 0.0; - for (int i = 0; i < data.x; ++i) { - if (havesub && (i >= data.subnames.size() || data.subnames[i].empty())) - continue; - - int iy = i * data.y; - VResult yvec(data.y); - - Result total = 0.0; - for (int j = 0; j < data.y; ++j) { - yvec[j] = data.cvec[iy + j]; - tot_vec[j] += yvec[j]; - total += yvec[j]; - super_total += yvec[j]; - } - - print.name = data.name + "_" + (havesub ? data.subnames[i] : to_string(i)); - print.desc = data.desc; - print.vec = yvec; - print.total = total; - print(*stream); - } - - if ((data.flags & ::Stats::total) && (data.x > 1)) { - print.name = data.name; - print.desc = data.desc; - print.vec = tot_vec; - print.total = super_total; - print(*stream); - } -} - -void -Text::visit(const DistData &data) -{ - if (noOutput(data)) - return; - - DistPrint print; - - print.name = data.name; - print.desc = data.desc; - print.flags = data.flags; - print.compat = compat; - print.descriptions = descriptions; - print.precision = data.precision; - - print.min_val = data.data.min_val; - print.max_val = data.data.max_val; - print.underflow = data.data.underflow; - print.overflow = data.data.overflow; - print.vec.resize(data.data.cvec.size()); - for (int i = 0; i < print.vec.size(); ++i) - print.vec[i] = (Result)data.data.cvec[i]; - print.sum = data.data.sum; - print.squares = data.data.squares; - print.samples = data.data.samples; - - print.min = data.data.min; - print.max = data.data.max; - print.bucket_size = data.data.bucket_size; - print.size = data.data.size; - print.fancy = data.data.fancy; - - print(*stream); -} - -void -Text::visit(const VectorDistData &data) -{ - if (noOutput(data)) - return; - - for (int i = 0; i < data.size(); ++i) { - DistPrint print; - - print.name = data.name + - (data.subnames[i].empty() ? ("_" + to_string(i)) : data.subnames[i]); - print.desc = data.subdescs[i].empty() ? data.desc : data.subdescs[i]; - print.flags = data.flags; - print.compat = compat; - print.descriptions = descriptions; - print.precision = data.precision; - - print.min_val = data.data[i].min_val; - print.max_val = data.data[i].max_val; - print.underflow = data.data[i].underflow; - print.overflow = data.data[i].overflow; - print.vec.resize(data.data[i].cvec.size()); - for (int j = 0; j < print.vec.size(); ++j) - print.vec[j] = (Result)data.data[i].cvec[j]; - print.sum = data.data[i].sum; - print.squares = data.data[i].squares; - print.samples = data.data[i].samples; - - print.min = data.data[i].min; - print.max = data.data[i].max; - print.bucket_size = data.data[i].bucket_size; - print.size = data.data[i].size; - print.fancy = data.data[i].fancy; - - print(*stream); - } -} - -void -Text::visit(const FormulaData &data) -{ - visit((const VectorData &)data); -} - -/* namespace Stats */ } diff --git a/base/traceflags.py b/base/traceflags.py deleted file mode 100644 index 47ed59c3a..000000000 --- a/base/traceflags.py +++ /dev/null @@ -1,325 +0,0 @@ -#!/usr/bin/env python - -# Copyright (c) 2004-2005 The Regents of The University of Michigan -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer; -# redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution; -# neither the name of the copyright holders nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -# -# This file generates the header and source files for the flags -# that control the tracing facility. -# - -import sys - -if len(sys.argv) != 2: - print "%s: Need argument (basename of cc/hh files)" % sys.argv[0] - sys.exit(1) - -hhfilename = sys.argv[1] + '.hh' -ccfilename = sys.argv[1] + '.cc' - -# -# The list of trace flags that can be used to condition DPRINTFs etc. -# To define a new flag, simply add it to this list. -# -baseFlags = [ - 'TCPIP', - 'Bus', - 'ScsiDisk', - 'ScsiCtrl', - 'ScsiNone', - 'DMA', - 'DMAReadVerbose', - 'DMAWriteVerbose', - 'TLB', - 'SimpleDisk', - 'SimpleDiskData', - 'Clock', - 'Regs', - 'MC146818', - 'IPI', - 'Timer', - 'Mbox', - 'PCIA', - 'PCIDEV', - 'PciConfigAll', - 'ISP', - 'BADADDR', - 'Console', - 'ConsolePoll', - 'ConsoleVerbose', - 'AlphaConsole', - 'Flow', - 'Interrupt', - 'Fault', - 'Cycle', - 'Loader', - 'MMU', - 'Ethernet', - 'EthernetPIO', - 'EthernetDMA', - 'EthernetData', - 'EthernetDesc', - 'EthernetIntr', - 'EthernetSM', - 'EthernetCksum', - 'GDBMisc', - 'GDBAcc', - 'GDBRead', - 'GDBWrite', - 'GDBSend', - 'GDBRecv', - 'GDBExtra', - 'VtoPhys', - 'Printf', - 'DebugPrintf', - 'Serialize', - 'Event', - 'PCEvent', - 'Syscall', - 'SyscallVerbose', - 'DiskImage', - 'DiskImageRead', - 'DiskImageWrite', - 'InstExec', - 'BPredRAS', - 'Cache', - 'IIC', - 'IICMore', - 'MSHR', - 'Chains', - 'Pipeline', - 'Stats', - 'StatEvents', - 'Context', - 'Config', - 'Sampler', - 'WriteBarrier', - 'IdeCtrl', - 'IdeDisk', - 'Tsunami', - 'Uart', - 'Split', - 'SQL', - 'Thread', - 'Fetch', - 'Decode', - 'Rename', - 'IEW', - 'Commit', - 'IQ', - 'ROB', - 'FreeList', - 'RenameMap', - 'LSQ', - 'LSQUnit', - 'StoreSet', - 'MemDepUnit', - 'DynInst', - 'FullCPU', - 'CommitRate', - 'OzoneCPU', - 'FE', - 'IBE', - 'BE', - 'OzoneLSQ', - 'HWPrefetch', - 'Stack', - 'DependGraph', - 'Activity', - 'Scoreboard', - 'Writeback', - 'Checker' - ] - -# -# "Compound" flags correspond to a set of base flags. These exist -# solely for convenience in setting them via the command line: if a -# compound flag is specified, all of the corresponding base flags are -# set. Compound flags cannot be used directly in DPRINTFs etc. -# To define a new compound flag, add a new entry to this hash -# following the existing examples. -# -compoundFlagMap = { - 'GDBAll' : [ 'GDBMisc', 'GDBAcc', 'GDBRead', 'GDBWrite', 'GDBSend', 'GDBRecv', 'GDBExtra' ], - 'ScsiAll' : [ 'ScsiDisk', 'ScsiCtrl', 'ScsiNone' ], - 'DiskImageAll' : [ 'DiskImage', 'DiskImageRead', 'DiskImageWrite' ], - 'EthernetAll' : [ 'Ethernet', 'EthernetPIO', 'EthernetDMA', 'EthernetData' , 'EthernetDesc', 'EthernetIntr', 'EthernetSM', 'EthernetCksum' ], - 'EthernetNoData' : [ 'Ethernet', 'EthernetPIO', 'EthernetDesc', 'EthernetIntr', 'EthernetSM', 'EthernetCksum' ], - 'IdeAll' : [ 'IdeCtrl', 'IdeDisk' ], - 'FullCPUAll' : [ 'Fetch', 'Decode', 'Rename', 'IEW', 'Commit', 'IQ', 'ROB', 'FreeList', 'RenameMap', 'LSQ', 'LSQUnit', 'StoreSet', 'MemDepUnit', 'DynInst', 'FullCPU', 'Activity','Scoreboard','Writeback'], - 'OzoneCPUAll' : [ 'BE', 'FE', 'IBE', 'OzoneLSQ', 'OzoneCPU'] -} - -############################################################# -# -# Everything below this point generates the appropriate C++ -# declarations and definitions for the trace flags. If you are simply -# adding or modifying flag definitions, you should not have to change -# anything below. -# - -import sys - -# extract just the compound flag names into a list -compoundFlags = [] -compoundFlags.extend(compoundFlagMap.keys()) -compoundFlags.sort() - -# -# First generate the header file. This defines the Flag enum -# and some extern declarations for the .cc file. -# -try: - hhfile = file(hhfilename, 'w') -except IOError, e: - sys.exit("can't open %s: %s" % (hhfilename, e)) - -# file header boilerplate -print >>hhfile, ''' -/* - * DO NOT EDIT THIS FILE! - * - * Automatically generated from traceflags.py - */ - -#ifndef __BASE_TRACE_FLAGS_HH__ -#define __BASE_TRACE_FLAGS_HH__ - -namespace Trace { - -enum Flags { -''', - -# Generate the enum. Base flags come first, then compound flags. -idx = 0 -for flag in baseFlags: - print >>hhfile, ' %s = %d,' % (flag, idx) - idx += 1 - -numBaseFlags = idx -print >>hhfile, ' NumFlags = %d,' % idx - -# put a comment in here to separate base from compound flags -print >>hhfile, ''' - // The remaining enum values are *not* valid indices for Trace::flags. - // They are "compound" flags, which correspond to sets of base - // flags, and are used only by TraceParamContext::setFlags(). -''', - -for flag in compoundFlags: - print >>hhfile, ' %s = %d,' % (flag, idx) - idx += 1 - -numCompoundFlags = idx - numBaseFlags -print >>hhfile, ' NumCompoundFlags = %d' % numCompoundFlags - -# trailer boilerplate -print >>hhfile, '''\ -}; // enum Flags - -// Array of strings for SimpleEnumParam -extern const char *flagStrings[]; -extern const int numFlagStrings; - -// Array of arraay pointers: for each compound flag, gives the list of -// base flags to set. Inidividual flag arrays are terminated by -1. -extern const Flags *compoundFlags[]; - -/* namespace Trace */ } - -#endif // __BASE_TRACE_FLAGS_HH__ -''', - -hhfile.close() - -# -# -# Print out .cc file with array definitions. -# -# -try: - ccfile = file(ccfilename, 'w') -except OSError, e: - sys.exit("can't open %s: %s" % (ccfilename, e)) - -# file header -print >>ccfile, ''' -/* - * DO NOT EDIT THIS FILE! - * - * Automatically generated from traceflags.pl. - */ - -#include "base/traceflags.hh" - -using namespace Trace; - -const char *Trace::flagStrings[] = -{ -''', - -# The string array is used by SimpleEnumParam to map the strings -# provided by the user to enum values. -for flag in baseFlags: - print >>ccfile, ' "%s",' % flag - -for flag in compoundFlags: - print >>ccfile, ' "%s",' % flag - -print >>ccfile, '};\n' - -numFlagStrings = len(baseFlags) + len(compoundFlags); - -print >>ccfile, 'const int Trace::numFlagStrings = %d;' % numFlagStrings -print >>ccfile - -# -# Now define the individual compound flag arrays. There is an array -# for each compound flag listing the component base flags. -# - -for flag in compoundFlags: - flags = compoundFlagMap[flag] - flags.append('(Flags)-1') - print >>ccfile, 'static const Flags %sMap[] =' % flag - print >>ccfile, '{ %s };' % (', '.join(flags)) - print >>ccfile - -# -# Finally the compoundFlags[] array maps the compound flags -# to their individual arrays/ -# -print >>ccfile, 'const Flags *Trace::compoundFlags[] =' -print >>ccfile, '{' - -for flag in compoundFlags: - print >>ccfile, ' %sMap,' % flag - -# file trailer -print >>ccfile, '};' - -ccfile.close() - diff --git a/build/SConstruct b/build/SConstruct deleted file mode 100644 index 110a0f250..000000000 --- a/build/SConstruct +++ /dev/null @@ -1,421 +0,0 @@ -# -*- mode:python -*- - -# Copyright (c) 2004-2005 The Regents of The University of Michigan -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer; -# redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution; -# neither the name of the copyright holders nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -################################################### -# -# SCons top-level build description (SConstruct) file. -# -# To build M5, you need a directory with three things: -# 1. A copy of this file (named SConstruct). -# 2. A link named 'm5' to the top of the M5 simulator source tree. -# 3. A link named 'ext' to the top of the M5 external source tree. -# -# Then type 'scons' to build the default configuration (see below), or -# 'scons <CONFIG>/<binary>' to build some other configuration (e.g., -# 'ALPHA_FS/m5.opt' for the optimized full-system version). -# -################################################### - -# Python library imports -import sys -import os - -# Check for recent-enough Python and SCons versions -EnsurePythonVersion(2,3) -EnsureSConsVersion(0,96) - -# The absolute path to the current directory (where this file lives). -ROOT = Dir('.').abspath - -# Paths to the M5 and external source trees (local symlinks). -SRCDIR = os.path.join(ROOT, 'm5') -EXT_SRCDIR = os.path.join(ROOT, 'ext') - -# Check for 'm5' and 'ext' links, die if they don't exist. -if not os.path.isdir(SRCDIR): - print "Error: '%s' must be a link to the M5 source tree." % SRCDIR - Exit(1) - -if not os.path.isdir('ext'): - print "Error: '%s' must be a link to the M5 external source tree." \ - % EXT_SRCDIR - Exit(1) - -# tell python where to find m5 python code -sys.path.append(os.path.join(SRCDIR, 'python')) - -################################################### -# -# Figure out which configurations to set up. -# -# -# It's prohibitive to do all the combinations of base configurations -# and options, so we have to infer which ones the user wants. -# -# 1. If there are command-line targets, the configuration(s) are inferred -# from the directories of those targets. If scons was invoked from a -# subdirectory (using 'scons -u'), those targets have to be -# interpreted relative to that subdirectory. -# -# 2. If there are no command-line targets, and scons was invoked from a -# subdirectory (using 'scons -u'), the configuration is inferred from -# the name of the subdirectory. -# -# 3. If there are no command-line targets and scons was invoked from -# the root build directory, a default configuration is used. The -# built-in default is ALPHA_SE, but this can be overridden by setting the -# M5_DEFAULT_CONFIG shell environment veriable. -# -# In cases 2 & 3, the specific file target defaults to 'm5.debug', but -# this can be overridden by setting the M5_DEFAULT_BINARY shell -# environment veriable. -# -################################################### - -# Find default configuration & binary. -default_config = os.environ.get('M5_DEFAULT_CONFIG', 'ALPHA_SE') -default_binary = os.environ.get('M5_DEFAULT_BINARY', 'm5.debug') - -# Ask SCons which directory it was invoked from. If you invoke SCons -# from a subdirectory you must use the '-u' flag. -launch_dir = GetLaunchDir() - -# Build a list 'my_targets' of all the targets relative to ROOT. -if launch_dir == ROOT: - # invoked from root build dir - if len(COMMAND_LINE_TARGETS) != 0: - # easy: use specified targets as is - my_targets = COMMAND_LINE_TARGETS - else: - # default target (ALPHA_SE/m5.debug, unless overridden) - target = os.path.join(default_config, default_binary) - my_targets = [target] - Default(target) -else: - # invoked from subdirectory - if not launch_dir.startswith(ROOT): - print "Error: launch dir (%s) not a subdirectory of ROOT (%s)!" \ - (launch_dir, ROOT) - Exit(1) - # make launch_dir relative to ROOT (strip ROOT plus slash off front) - launch_dir = launch_dir[len(ROOT)+1:] - if len(COMMAND_LINE_TARGETS) != 0: - # make specified targets relative to ROOT - my_targets = map(lambda x: os.path.join(launch_dir, x), - COMMAND_LINE_TARGETS) - else: - # build default binary (m5.debug, unless overridden) using the - # config inferred by the invocation directory (the first - # subdirectory after ROOT) - target = os.path.join(launch_dir.split('/')[0], default_binary) - my_targets = [target] - Default(target) - -# Normalize target paths (gets rid of '..' in the middle, etc.) -my_targets = map(os.path.normpath, my_targets) - -# Generate a list of the unique configs that the collected targets reference. -build_dirs = [] -for t in my_targets: - dir = t.split('/')[0] - if dir not in build_dirs: - build_dirs.append(dir) - -################################################### -# -# Set up the default build environment. This environment is copied -# and modified according to each selected configuration. -# -################################################### - -env = Environment(ENV = os.environ, # inherit user's environment vars - ROOT = ROOT, - SRCDIR = SRCDIR, - EXT_SRCDIR = EXT_SRCDIR) - -env.SConsignFile("sconsign") - -# I waffle on this setting... it does avoid a few painful but -# unnecessary builds, but it also seems to make trivial builds take -# noticeably longer. -if False: - env.TargetSignatures('content') - -# M5_EXT is used by isa_parser.py to find the PLY package. -env.Append(ENV = { 'M5_EXT' : EXT_SRCDIR }) - -# Set up default C++ compiler flags -env.Append(CCFLAGS='-pipe') -env.Append(CCFLAGS='-fno-strict-aliasing') -env.Append(CCFLAGS=Split('-Wall -Wno-sign-compare -Werror -Wundef')) -if sys.platform == 'cygwin': - # cygwin has some header file issues... - env.Append(CCFLAGS=Split("-Wno-uninitialized")) -env.Append(CPPPATH=[os.path.join(EXT_SRCDIR + '/dnet')]) - -# Default libraries -env.Append(LIBS=['z']) - -# Platform-specific configuration -conf = Configure(env) - -# Check for <fenv.h> (C99 FP environment control) -have_fenv = conf.CheckHeader('fenv.h', '<>') -if not have_fenv: - print "Warning: Header file <fenv.h> not found." - print " This host has no IEEE FP rounding mode control." - -# Check for mysql. -mysql_config = WhereIs('mysql_config') -have_mysql = mysql_config != None - -# Check MySQL version. -if have_mysql: - mysql_version = os.popen(mysql_config + ' --version').read() - mysql_version = mysql_version.split('.') - mysql_major = int(mysql_version[0]) - mysql_minor = int(mysql_version[1]) - # This version check is probably overly conservative, but it deals - # with the versions we have installed. - if mysql_major < 4 or (mysql_major == 4 and mysql_minor < 1): - print "Warning: MySQL v4.1 or newer required." - have_mysql = False - -# Set up mysql_config commands. -if have_mysql: - mysql_config_include = mysql_config + ' --include' - if os.system(mysql_config_include + ' > /dev/null') != 0: - # older mysql_config versions don't support --include, use - # --cflags instead - mysql_config_include = mysql_config + ' --cflags | sed s/\\\'//g' - # This seems to work in all versions - mysql_config_libs = mysql_config + ' --libs' - -env = conf.Finish() - -# Define the universe of supported ISAs -env['ALL_ISA_LIST'] = ['alpha', 'sparc', 'mips'] - -# Define the universe of supported CPU models -env['ALL_CPU_LIST'] = ['SimpleCPU', 'FastCPU', 'FullCPU', 'AlphaFullCPU', - 'OzoneSimpleCPU', 'OzoneCPU', 'CheckerCPU'] - - -# Sticky options get saved in the options file so they persist from -# one invocation to the next (unless overridden, in which case the new -# value becomes sticky). -sticky_opts = Options(args=ARGUMENTS) -sticky_opts.AddOptions( - EnumOption('TARGET_ISA', 'Target ISA', 'alpha', env['ALL_ISA_LIST']), - BoolOption('FULL_SYSTEM', 'Full-system support', False), - BoolOption('ALPHA_TLASER', - 'Model Alpha TurboLaser platform (vs. Tsunami)', False), - BoolOption('NO_FAST_ALLOC', 'Disable fast object allocator', False), - BoolOption('EFENCE', 'Link with Electric Fence malloc debugger', - False), - BoolOption('SS_COMPATIBLE_FP', - 'Make floating-point results compatible with SimpleScalar', - False), - BoolOption('USE_SSE2', - 'Compile for SSE2 (-msse2) to get IEEE FP on x86 hosts', - False), - BoolOption('STATS_BINNING', 'Bin statistics by CPU mode', have_mysql), - BoolOption('USE_MYSQL', 'Use MySQL for stats output', have_mysql), - BoolOption('USE_FENV', 'Use <fenv.h> IEEE mode control', have_fenv), - ('CC', 'C compiler', os.environ.get('CC', env['CC'])), - ('CXX', 'C++ compiler', os.environ.get('CXX', env['CXX'])), - BoolOption('BATCH', 'Use batch pool for build and tests', False), - ('BATCH_CMD', 'Batch pool submission command name', 'qdo') - ) - -# Non-sticky options only apply to the current build. -nonsticky_opts = Options(args=ARGUMENTS) -nonsticky_opts.AddOptions( - # This really should be a sticky option, but there's a bug in - # scons 0.96.1 that causes ListOptions not to be able to be - # restored from a saved option file. It looks like this is fixed - # in 0.96.9, but there's a different bug in that version that means we - # can't just upgrade. - ListOption('CPU_MODELS', 'CPU models', 'all', env['ALL_CPU_LIST']), - BoolOption('update_ref', 'Update test reference outputs', False) - ) - -# These options get exported to #defines in config/*.hh (see m5/SConscript). -env.ExportOptions = ['FULL_SYSTEM', 'ALPHA_TLASER', 'USE_FENV', \ - 'USE_MYSQL', 'NO_FAST_ALLOC', 'SS_COMPATIBLE_FP', \ - 'STATS_BINNING'] - -# Define a handy 'no-op' action -def no_action(target, source, env): - return 0 - -env.NoAction = Action(no_action, None) - -# libelf build is described in its own SConscript file. -# SConscript-global is the build in build/libelf shared among all -# configs. -env.SConscript('m5/libelf/SConscript-global', exports = 'env') - -################################################### -# -# Define a SCons builder for configuration flag headers. -# -################################################### - -# This function generates a config header file that #defines the -# option symbol to the current option setting (0 or 1). The source -# operands are the name of the option and a Value node containing the -# value of the option. -def build_config_file(target, source, env): - (option, value) = [s.get_contents() for s in source] - f = file(str(target[0]), 'w') - print >> f, '#define', option, value - f.close() - return None - -# Generate the message to be printed when building the config file. -def build_config_file_string(target, source, env): - (option, value) = [s.get_contents() for s in source] - return "Defining %s as %s in %s." % (option, value, target[0]) - -# Combine the two functions into a scons Action object. -config_action = Action(build_config_file, build_config_file_string) - -# The emitter munges the source & target node lists to reflect what -# we're really doing. -def config_emitter(target, source, env): - # extract option name from Builder arg - option = str(target[0]) - # True target is config header file - target = os.path.join('config', option.lower() + '.hh') - # Force value to 0/1 even if it's a Python bool - val = int(eval(str(env[option]))) - # Sources are option name & value (packaged in SCons Value nodes) - return ([target], [Value(option), Value(val)]) - -config_builder = Builder(emitter = config_emitter, action = config_action) - -env.Append(BUILDERS = { 'ConfigFile' : config_builder }) - -################################################### -# -# Define build environments for selected configurations. -# -################################################### - -# rename base env -base_env = env - -for build_dir in build_dirs: - # Make a copy of the default environment to use for this config. - env = base_env.Copy() - - # Record what build_dir was in the environment - env.Append(BUILD_DIR=build_dir); - - # Set env according to the build directory config. - - sticky_opts.files = [] - # Name of default options file is taken from 'default=' on command - # line if set, otherwise name of build dir. - default_options_file = os.path.join('default_options', - ARGUMENTS.get('default', build_dir)) - if os.path.isfile(default_options_file): - sticky_opts.files.append(default_options_file) - current_options_file = os.path.join('options', build_dir) - if os.path.isfile(current_options_file): - sticky_opts.files.append(current_options_file) - else: - # if file doesn't exist, make sure at least the directory is there - # so we can create it later - opt_dir = os.path.dirname(current_options_file) - if not os.path.isdir(opt_dir): - os.mkdir(opt_dir) - if not sticky_opts.files: - print "%s: No options file found in options, using defaults." \ - % build_dir - - # Apply current option settings to env - sticky_opts.Update(env) - nonsticky_opts.Update(env) - - # Process option settings. - - if not have_fenv and env['USE_FENV']: - print "Warning: <fenv.h> not available; " \ - "forcing USE_FENV to False in", build_dir + "." - env['USE_FENV'] = False - - if not env['USE_FENV']: - print "Warning: No IEEE FP rounding mode control in", build_dir + "." - print " FP results may deviate slightly from other platforms." - - if env['EFENCE']: - env.Append(LIBS=['efence']) - - if env['USE_MYSQL']: - if not have_mysql: - print "Warning: MySQL not available; " \ - "forcing USE_MYSQL to False in", build_dir + "." - env['USE_MYSQL'] = False - else: - print "Compiling in", build_dir, "with MySQL support." - env.ParseConfig(mysql_config_libs) - env.ParseConfig(mysql_config_include) - - # Save sticky option settings back to current options file - sticky_opts.Save(current_options_file, env) - - # Do this after we save setting back, or else we'll tack on an - # extra 'qdo' every time we run scons. - if env['BATCH']: - env['CC'] = env['BATCH_CMD'] + ' ' + env['CC'] - env['CXX'] = env['BATCH_CMD'] + ' ' + env['CXX'] - - if env['USE_SSE2']: - env.Append(CCFLAGS='-msse2') - - # The m5/SConscript file sets up the build rules in 'env' according - # to the configured options. It returns a list of environments, - # one for each variant build (debug, opt, etc.) - envList = SConscript('m5/SConscript', build_dir = build_dir, - exports = 'env', duplicate = False) - - # Set up the regression tests for each build. - for e in envList: - SConscript('m5-test/SConscript', - build_dir = os.path.join(build_dir, 'test', e.Label), - exports = { 'env' : e }, duplicate = False) - -################################################### -# -# Let SCons do its thing. At this point SCons will use the defined -# build environments to build the requested targets. -# -################################################### - diff --git a/build/default_options/ALPHA_FS b/build_opts/ALPHA_FS index ddd69b9b3..ddd69b9b3 100644 --- a/build/default_options/ALPHA_FS +++ b/build_opts/ALPHA_FS diff --git a/build/default_options/ALPHA_FS_TL b/build_opts/ALPHA_FS_TL index 4f3e201ec..4f3e201ec 100644 --- a/build/default_options/ALPHA_FS_TL +++ b/build_opts/ALPHA_FS_TL diff --git a/build/default_options/ALPHA_SE b/build_opts/ALPHA_SE index 3fedc22ca..3fedc22ca 100644 --- a/build/default_options/ALPHA_SE +++ b/build_opts/ALPHA_SE diff --git a/build/default_options/MIPS_SE b/build_opts/MIPS_SE index e74e2f69c..e74e2f69c 100644 --- a/build/default_options/MIPS_SE +++ b/build_opts/MIPS_SE diff --git a/build_opts/SPARC_FS b/build_opts/SPARC_FS new file mode 100644 index 000000000..59d17eee9 --- /dev/null +++ b/build_opts/SPARC_FS @@ -0,0 +1,2 @@ +TARGET_ISA = 'sparc' +FULL_SYSTEM = 1 diff --git a/build/default_options/SPARC_SE b/build_opts/SPARC_SE index 3b256fc34..3b256fc34 100644 --- a/build/default_options/SPARC_SE +++ b/build_opts/SPARC_SE diff --git a/configs/test/SysPaths.py b/configs/test/SysPaths.py new file mode 100644 index 000000000..c7c7db4e7 --- /dev/null +++ b/configs/test/SysPaths.py @@ -0,0 +1,32 @@ +from m5 import * + +import os.path +import sys + +# Edit the following list to include the possible paths to the binary +# and disk image directories. The first directory on the list that +# exists will be selected. +SYSTEMDIR_PATH = ['/n/poolfs/z/dist/m5/system'] + +SYSTEMDIR = None +for d in SYSTEMDIR_PATH: + if os.path.exists(d): + SYSTEMDIR = d + break + +if not SYSTEMDIR: + print >>sys.stderr, "Can't find a path to system files." + sys.exit(1) + +BINDIR = SYSTEMDIR + '/binaries' +DISKDIR = SYSTEMDIR + '/disks' + +def disk(file): + return os.path.join(DISKDIR, file) + +def binary(file): + return os.path.join(BINDIR, file) + +def script(file): + return os.path.join(SYSTEMDIR, 'boot', file) + diff --git a/configs/test/fs.py b/configs/test/fs.py new file mode 100644 index 000000000..fdbf86abe --- /dev/null +++ b/configs/test/fs.py @@ -0,0 +1,215 @@ +from m5 import * +import os +from SysPaths import * + +# Base for tests is directory containing this file. +test_base = os.path.dirname(__file__) + +linux_image = env.get('LINUX_IMAGE', disk('linux-latest.img')) + +class IdeControllerPciData(PciConfigData): + VendorID = 0x8086 + DeviceID = 0x7111 + Command = 0x0 + Status = 0x280 + Revision = 0x0 + ClassCode = 0x01 + SubClassCode = 0x01 + ProgIF = 0x85 + BAR0 = 0x00000001 + BAR1 = 0x00000001 + BAR2 = 0x00000001 + BAR3 = 0x00000001 + BAR4 = 0x00000001 + BAR5 = 0x00000001 + InterruptLine = 0x1f + InterruptPin = 0x01 + BAR0Size = '8B' + BAR1Size = '4B' + BAR2Size = '8B' + BAR3Size = '4B' + BAR4Size = '16B' + +class SinicPciData(PciConfigData): + VendorID = 0x1291 + DeviceID = 0x1293 + Status = 0x0290 + SubClassCode = 0x00 + ClassCode = 0x02 + ProgIF = 0x00 + BAR0 = 0x00000000 + BAR1 = 0x00000000 + BAR2 = 0x00000000 + BAR3 = 0x00000000 + BAR4 = 0x00000000 + BAR5 = 0x00000000 + MaximumLatency = 0x34 + MinimumGrant = 0xb0 + InterruptLine = 0x1e + InterruptPin = 0x01 + BAR0Size = '64kB' + +class NSGigEPciData(PciConfigData): + VendorID = 0x100B + DeviceID = 0x0022 + Status = 0x0290 + SubClassCode = 0x00 + ClassCode = 0x02 + ProgIF = 0x00 + BAR0 = 0x00000001 + BAR1 = 0x00000000 + BAR2 = 0x00000000 + BAR3 = 0x00000000 + BAR4 = 0x00000000 + BAR5 = 0x00000000 + MaximumLatency = 0x34 + MinimumGrant = 0xb0 + InterruptLine = 0x1e + InterruptPin = 0x01 + BAR0Size = '256B' + BAR1Size = '4kB' + +class LinuxRootDisk(IdeDisk): + raw_image = RawDiskImage(image_file=linux_image, read_only=True) + image = CowDiskImage(child=Parent.raw_image, read_only=False) + +class LinuxSwapDisk(IdeDisk): + raw_image = RawDiskImage(image_file = disk('linux-bigswap2.img'), + read_only=True) + image = CowDiskImage(child = Parent.raw_image, read_only=False) + +class SpecwebFilesetDisk(IdeDisk): + raw_image = RawDiskImage(image_file = disk('specweb-fileset.img'), + read_only=True) + image = CowDiskImage(child = Parent.raw_image, read_only=False) + +class BaseTsunami(Tsunami): + cchip = TsunamiCChip(pio_addr=0x801a0000000) + pchip = TsunamiPChip(pio_addr=0x80180000000) + pciconfig = PciConfigAll(pio_addr=0x801fe000000) + fake_sm_chip = IsaFake(pio_addr=0x801fc000370) + + fake_uart1 = IsaFake(pio_addr=0x801fc0002f8) + fake_uart2 = IsaFake(pio_addr=0x801fc0003e8) + fake_uart3 = IsaFake(pio_addr=0x801fc0002e8) + fake_uart4 = IsaFake(pio_addr=0x801fc0003f0) + + fake_ppc = IsaFake(pio_addr=0x801fc0003bc) + + fake_OROM = IsaFake(pio_addr=0x800000a0000, pio_size=0x60000) + + fake_pnp_addr = IsaFake(pio_addr=0x801fc000279) + fake_pnp_write = IsaFake(pio_addr=0x801fc000a79) + fake_pnp_read0 = IsaFake(pio_addr=0x801fc000203) + fake_pnp_read1 = IsaFake(pio_addr=0x801fc000243) + fake_pnp_read2 = IsaFake(pio_addr=0x801fc000283) + fake_pnp_read3 = IsaFake(pio_addr=0x801fc0002c3) + fake_pnp_read4 = IsaFake(pio_addr=0x801fc000303) + fake_pnp_read5 = IsaFake(pio_addr=0x801fc000343) + fake_pnp_read6 = IsaFake(pio_addr=0x801fc000383) + fake_pnp_read7 = IsaFake(pio_addr=0x801fc0003c3) + + fake_ata0 = IsaFake(pio_addr=0x801fc0001f0) + fake_ata1 = IsaFake(pio_addr=0x801fc000170) + + fb = BadDevice(pio_addr=0x801fc0003d0, devicename='FrameBuffer') + io = TsunamiIO(pio_addr=0x801fc000000) + uart = Uart8250(pio_addr=0x801fc0003f8) + ethernet = NSGigE(configdata=NSGigEPciData(), + pci_bus=0, pci_dev=1, pci_func=0) + etherint = NSGigEInt(device=Parent.ethernet) +# ethernet = Sinic(configdata=SinicPciData(), +# pci_bus=0, pci_dev=1, pci_func=0) +# etherint = SinicInt(device=Parent.ethernet) + console = AlphaConsole(pio_addr=0x80200000000, disk=Parent.simple_disk) +# bridge = PciFake(configdata=BridgePciData(), pci_bus=0, pci_dev=2, pci_func=0) + +#class FreeBSDTsunami(BaseTsunami): +# disk0 = FreeBSDRootDisk(delay='0us', driveID='master') +# ide = IdeController(disks=[Parent.disk0], +# configdata=IdeControllerPciData(), +# pci_func=0, pci_dev=0, pci_bus=0) + +class LinuxTsunami(BaseTsunami): + disk0 = LinuxRootDisk(driveID='master') + disk1 = SpecwebFilesetDisk(driveID='slave') + disk2 = LinuxSwapDisk(driveID='master') + ide = IdeController(disks=[Parent.disk0, Parent.disk1, Parent.disk2], + configdata=IdeControllerPciData(), + pci_func=0, pci_dev=0, pci_bus=0) + +class LinuxAlphaSystem(LinuxAlphaSystem): + magicbus = Bus(bus_id=0) + magicbus2 = Bus(bus_id=1) + bridge = Bridge() + physmem = PhysicalMemory(range = AddrRange('128MB')) + c0a = Connector(side_a=Parent.magicbus, side_b=Parent.bridge, side_b_name="side_a") + c0b = Connector(side_a=Parent.magicbus2, side_b=Parent.bridge, side_b_name="side_b") + c1 = Connector(side_a=Parent.physmem, side_b=Parent.magicbus2) + tsunami = LinuxTsunami() + c2 = Connector(side_a=Parent.tsunami.cchip, side_a_name='pio', side_b=Parent.magicbus) + c3 = Connector(side_a=Parent.tsunami.pchip, side_a_name='pio', side_b=Parent.magicbus) + c4 = Connector(side_a=Parent.tsunami.pciconfig, side_a_name='pio', side_b=Parent.magicbus) + c5 = Connector(side_a=Parent.tsunami.fake_sm_chip, side_a_name='pio', side_b=Parent.magicbus) + c6 = Connector(side_a=Parent.tsunami.ethernet, side_a_name='pio', side_b=Parent.magicbus) + c6a = Connector(side_a=Parent.tsunami.ethernet, side_a_name='dma', side_b=Parent.magicbus) + c7 = Connector(side_a=Parent.tsunami.fake_uart1, side_a_name='pio', side_b=Parent.magicbus) + c8 = Connector(side_a=Parent.tsunami.fake_uart2, side_a_name='pio', side_b=Parent.magicbus) + c9 = Connector(side_a=Parent.tsunami.fake_uart3, side_a_name='pio', side_b=Parent.magicbus) + c10 = Connector(side_a=Parent.tsunami.fake_uart4, side_a_name='pio', side_b=Parent.magicbus) + c11 = Connector(side_a=Parent.tsunami.ide, side_a_name='pio', side_b=Parent.magicbus) + c13 = Connector(side_a=Parent.tsunami.ide, side_a_name='dma', side_b=Parent.magicbus) + c12 = Connector(side_a=Parent.tsunami.fake_ppc, side_a_name='pio', side_b=Parent.magicbus) + c14 = Connector(side_a=Parent.tsunami.fake_OROM, side_a_name='pio', side_b=Parent.magicbus) + c16 = Connector(side_a=Parent.tsunami.fake_pnp_addr, side_a_name='pio', side_b=Parent.magicbus) + c17 = Connector(side_a=Parent.tsunami.fake_pnp_write, side_a_name='pio', side_b=Parent.magicbus) + c18 = Connector(side_a=Parent.tsunami.fake_pnp_read0, side_a_name='pio', side_b=Parent.magicbus) + c19 = Connector(side_a=Parent.tsunami.fake_pnp_read1, side_a_name='pio', side_b=Parent.magicbus) + c20 = Connector(side_a=Parent.tsunami.fake_pnp_read2, side_a_name='pio', side_b=Parent.magicbus) + c21 = Connector(side_a=Parent.tsunami.fake_pnp_read3, side_a_name='pio', side_b=Parent.magicbus) + c22 = Connector(side_a=Parent.tsunami.fake_pnp_read4, side_a_name='pio', side_b=Parent.magicbus) + c23 = Connector(side_a=Parent.tsunami.fake_pnp_read5, side_a_name='pio', side_b=Parent.magicbus) + c24 = Connector(side_a=Parent.tsunami.fake_pnp_read6, side_a_name='pio', side_b=Parent.magicbus) + c25 = Connector(side_a=Parent.tsunami.fake_pnp_read7, side_a_name='pio', side_b=Parent.magicbus) + c27 = Connector(side_a=Parent.tsunami.fake_ata0, side_a_name='pio', side_b=Parent.magicbus) + c28 = Connector(side_a=Parent.tsunami.fake_ata1, side_a_name='pio', side_b=Parent.magicbus) + c30 = Connector(side_a=Parent.tsunami.fb, side_a_name='pio', side_b=Parent.magicbus) + c31 = Connector(side_a=Parent.tsunami.io, side_a_name='pio', side_b=Parent.magicbus) + c32 = Connector(side_a=Parent.tsunami.uart, side_a_name='pio', side_b=Parent.magicbus) + c33 = Connector(side_a=Parent.tsunami.console, side_a_name='pio', side_b=Parent.magicbus) + raw_image = RawDiskImage(image_file=disk('linux-latest.img'), + read_only=True) + simple_disk = SimpleDisk(disk=Parent.raw_image) + intrctrl = IntrControl() + cpu = AtomicSimpleCPU(mem=Parent.magicbus2) + sim_console = SimConsole(listener=ConsoleListener(port=3456)) + kernel = binary('vmlinux') + pal = binary('ts_osfpal') + console = binary('console') + boot_osflags = 'root=/dev/hda1 console=ttyS0' +# readfile = os.path.join(test_base, 'halt.sh') + + +BaseCPU.itb = AlphaITB() +BaseCPU.dtb = AlphaDTB() +BaseCPU.system = Parent.any + +class TsunamiRoot(System): + pass + + +def DualRoot(ClientSystem, ServerSystem): + self = Root() + self.client = ClientSystem() + self.server = ServerSystem() + + self.etherdump = EtherDump(file='ethertrace') + self.etherlink = EtherLink(int1 = Parent.client.tsunami.etherint[0], + int2 = Parent.server.tsunami.etherint[0], + dump = Parent.etherdump) + self.clock = '5GHz' + return self + +root = DualRoot(ClientSystem = LinuxAlphaSystem(readfile=script('netperf-stream-nt-client.rcS')), + ServerSystem = LinuxAlphaSystem(readfile=script('netperf-server.rcS'))) + diff --git a/configs/test/hello b/configs/test/hello Binary files differnew file mode 100755 index 000000000..59c0d195c --- /dev/null +++ b/configs/test/hello diff --git a/configs/test/hello_mips b/configs/test/hello_mips Binary files differnew file mode 100755 index 000000000..a3db001ec --- /dev/null +++ b/configs/test/hello_mips diff --git a/configs/test/hello_sparc b/configs/test/hello_sparc Binary files differnew file mode 100755 index 000000000..e254ae33f --- /dev/null +++ b/configs/test/hello_sparc diff --git a/configs/test/test.py b/configs/test/test.py new file mode 100644 index 000000000..75e832f5e --- /dev/null +++ b/configs/test/test.py @@ -0,0 +1,12 @@ +from m5 import * + +class HelloWorld(AlphaLiveProcess): + executable = '../configs/test/hello' + cmd = 'hello' + +magicbus = Bus() +mem = PhysicalMemory() +cpu = AtomicSimpleCPU(workload=HelloWorld(), mem=magicbus) +system = System(physmem=mem, cpu=cpu) +system.c1 = Connector(side_a=mem, side_b=magicbus) +root = Root(system=system) diff --git a/cpu/SConscript b/cpu/SConscript deleted file mode 100644 index 3840b9d41..000000000 --- a/cpu/SConscript +++ /dev/null @@ -1,167 +0,0 @@ -# -*- mode:python -*- - -# Copyright (c) 2006 The Regents of The University of Michigan -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer; -# redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution; -# neither the name of the copyright holders nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -import os -import os.path - -# Import build environment variable from SConstruct. -Import('env') - -################################################################# -# -# Generate StaticInst execute() method signatures. -# -# There must be one signature for each CPU model compiled in. -# Since the set of compiled-in models is flexible, we generate a -# header containing the appropriate set of signatures on the fly. -# -################################################################# - -# CPU model-specific data is contained in cpu_models.py -# Convert to SCons File node to get path handling -models_db = File('cpu_models.py') -# slurp in contents of file -execfile(models_db.srcnode().abspath) - -# Template for execute() signature. -exec_sig_template = ''' -virtual Fault execute(%s *xc, Trace::InstRecord *traceData) const = 0; -''' - -mem_ini_sig_template = ''' -virtual Fault initiateAcc(%s *xc, Trace::InstRecord *traceData) const { panic("Not defined!"); }; -''' - -mem_comp_sig_template = ''' -virtual Fault completeAcc(uint8_t *data, %s *xc, Trace::InstRecord *traceData) const { panic("Not defined!"); return NoFault; }; -''' - -# Generate header. -def gen_cpu_exec_signatures(target, source, env): - f = open(str(target[0]), 'w') - print >> f, ''' -#ifndef __CPU_STATIC_INST_EXEC_SIGS_HH__ -#define __CPU_STATIC_INST_EXEC_SIGS_HH__ -''' - for cpu in env['CPU_MODELS']: - xc_type = CpuModel.dict[cpu].strings['CPU_exec_context'] - print >> f, exec_sig_template % xc_type - print >> f, mem_ini_sig_template % xc_type - print >> f, mem_comp_sig_template % xc_type - print >> f, ''' -#endif // __CPU_STATIC_INST_EXEC_SIGS_HH__ -''' - -# Generate string that gets printed when header is rebuilt -def gen_sigs_string(target, source, env): - return "Generating static_inst_exec_sigs.hh: " \ - + ', '.join(env['CPU_MODELS']) - -# Add command to generate header to environment. -env.Command('static_inst_exec_sigs.hh', models_db, - Action(gen_cpu_exec_signatures, gen_sigs_string, - varlist = ['CPU_MODELS'])) - -################################################################# -# -# Include CPU-model-specific files based on set of models -# specified in CPU_MODELS build option. -# -################################################################# - -sources = [] - -if 'SimpleCPU' in env['CPU_MODELS']: - sources += Split('simple/cpu.cc') - -if 'FastCPU' in env['CPU_MODELS']: - sources += Split('fast/cpu.cc') - -if 'AlphaFullCPU' in env['CPU_MODELS']: - sources += Split(''' - o3/2bit_local_pred.cc - o3/alpha_dyn_inst.cc - o3/alpha_cpu.cc - o3/alpha_cpu_builder.cc - o3/bpred_unit.cc - o3/btb.cc - o3/commit.cc - o3/decode.cc - o3/fetch.cc - o3/free_list.cc - o3/fu_pool.cc - o3/cpu.cc - o3/iew.cc - o3/inst_queue.cc - o3/lsq_unit.cc - o3/lsq.cc - o3/mem_dep_unit.cc - o3/ras.cc - o3/rename.cc - o3/rename_map.cc - o3/rob.cc - o3/scoreboard.cc - o3/store_set.cc - o3/tournament_pred.cc - ''') - -if 'OzoneSimpleCPU' in env['CPU_MODELS']: - sources += Split(''' - ozone/cpu.cc - ozone/cpu_builder.cc - ozone/dyn_inst.cc - ozone/front_end.cc - ozone/inorder_back_end.cc - ozone/inst_queue.cc - ozone/rename_table.cc - ''') - -if 'OzoneCPU' in env['CPU_MODELS']: - sources += Split(''' - ozone/back_end.cc - ozone/lsq_unit.cc - ozone/lw_back_end.cc - ozone/lw_lsq.cc - ''') - -if 'CheckerCPU' in env['CPU_MODELS']: - sources += Split(''' - checker/cpu.cc - checker/cpu_builder.cc - checker/o3_cpu_builder.cc - ''') - -# FullCPU sources are included from m5/SConscript since they're not -# below this point in the file hierarchy. - -# Convert file names to SCons File objects. This takes care of the -# path relative to the top of the directory tree. -sources = [File(s) for s in sources] - -Return('sources') - diff --git a/cpu/base.cc b/cpu/base.cc deleted file mode 100644 index de03b9eab..000000000 --- a/cpu/base.cc +++ /dev/null @@ -1,378 +0,0 @@ -/* - * Copyright (c) 2002-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <iostream> -#include <string> -#include <sstream> - -#include "base/cprintf.hh" -#include "base/loader/symtab.hh" -#include "base/misc.hh" -#include "base/output.hh" -#include "cpu/base.hh" -#include "cpu/exec_context.hh" -#include "cpu/profile.hh" -#include "cpu/sampler/sampler.hh" -#include "sim/param.hh" -#include "sim/process.hh" -#include "sim/sim_events.hh" -#include "sim/system.hh" - -#include "base/trace.hh" - -using namespace std; - -vector<BaseCPU *> BaseCPU::cpuList; - -// This variable reflects the max number of threads in any CPU. Be -// careful to only use it once all the CPUs that you care about have -// been initialized -int maxThreadsPerCPU = 1; - -#if FULL_SYSTEM -BaseCPU::BaseCPU(Params *p) - : SimObject(p->name), clock(p->clock), checkInterrupts(true), - params(p), number_of_threads(p->numberOfThreads), system(p->system) -#else -BaseCPU::BaseCPU(Params *p) - : SimObject(p->name), clock(p->clock), params(p), - number_of_threads(p->numberOfThreads) -#endif -{ - DPRINTF(FullCPU, "BaseCPU: Creating object, mem address %#x.\n", this); - - // add self to global list of CPUs - cpuList.push_back(this); - - DPRINTF(FullCPU, "BaseCPU: CPU added to cpuList, mem address %#x.\n", - this); - - if (number_of_threads > maxThreadsPerCPU) - maxThreadsPerCPU = number_of_threads; - - // allocate per-thread instruction-based event queues - comInstEventQueue = new EventQueue *[number_of_threads]; - for (int i = 0; i < number_of_threads; ++i) - comInstEventQueue[i] = new EventQueue("instruction-based event queue"); - - // - // set up instruction-count-based termination events, if any - // - if (p->max_insts_any_thread != 0) - for (int i = 0; i < number_of_threads; ++i) - new SimExitEvent(comInstEventQueue[i], p->max_insts_any_thread, - "a thread reached the max instruction count"); - - if (p->max_insts_all_threads != 0) { - // allocate & initialize shared downcounter: each event will - // decrement this when triggered; simulation will terminate - // when counter reaches 0 - int *counter = new int; - *counter = number_of_threads; - for (int i = 0; i < number_of_threads; ++i) - new CountedExitEvent(comInstEventQueue[i], - "all threads reached the max instruction count", - p->max_insts_all_threads, *counter); - } - - // allocate per-thread load-based event queues - comLoadEventQueue = new EventQueue *[number_of_threads]; - for (int i = 0; i < number_of_threads; ++i) - comLoadEventQueue[i] = new EventQueue("load-based event queue"); - - // - // set up instruction-count-based termination events, if any - // - if (p->max_loads_any_thread != 0) - for (int i = 0; i < number_of_threads; ++i) - new SimExitEvent(comLoadEventQueue[i], p->max_loads_any_thread, - "a thread reached the max load count"); - - if (p->max_loads_all_threads != 0) { - // allocate & initialize shared downcounter: each event will - // decrement this when triggered; simulation will terminate - // when counter reaches 0 - int *counter = new int; - *counter = number_of_threads; - for (int i = 0; i < number_of_threads; ++i) - new CountedExitEvent(comLoadEventQueue[i], - "all threads reached the max load count", - p->max_loads_all_threads, *counter); - } - -#if FULL_SYSTEM - memset(interrupts, 0, sizeof(interrupts)); - intstatus = 0; -#endif - - functionTracingEnabled = false; - if (p->functionTrace) { - functionTraceStream = simout.find(csprintf("ftrace.%s", name())); - currentFunctionStart = currentFunctionEnd = 0; - functionEntryTick = p->functionTraceStart; - - if (p->functionTraceStart == 0) { - functionTracingEnabled = true; - } else { - Event *e = - new EventWrapper<BaseCPU, &BaseCPU::enableFunctionTrace>(this, - true); - e->schedule(p->functionTraceStart); - } - } -#if FULL_SYSTEM - profileEvent = NULL; - if (params->profile) - profileEvent = new ProfileEvent(this, params->profile); -#endif - -} - -BaseCPU::Params::Params() -{ -#if FULL_SYSTEM - profile = false; -#endif - checker = NULL; -} - -void -BaseCPU::enableFunctionTrace() -{ - functionTracingEnabled = true; -} - -BaseCPU::~BaseCPU() -{ -} - -void -BaseCPU::init() -{ - if (!params->deferRegistration) - registerExecContexts(); -} - -void -BaseCPU::startup() -{ -#if FULL_SYSTEM - if (!params->deferRegistration && profileEvent) - profileEvent->schedule(curTick); -#endif -} - - -void -BaseCPU::regStats() -{ - using namespace Stats; - - numCycles - .name(name() + ".numCycles") - .desc("number of cpu cycles simulated") - ; - - int size = execContexts.size(); - if (size > 1) { - for (int i = 0; i < size; ++i) { - stringstream namestr; - ccprintf(namestr, "%s.ctx%d", name(), i); - execContexts[i]->regStats(namestr.str()); - } - } else if (size == 1) - execContexts[0]->regStats(name()); - -#if FULL_SYSTEM -#endif -} - - -void -BaseCPU::registerExecContexts() -{ - for (int i = 0; i < execContexts.size(); ++i) { - ExecContext *xc = execContexts[i]; - - if (xc->status() == ExecContext::Suspended) { -#if FULL_SYSTEM - int id = params->cpu_id; - if (id != -1) - id += i; - - xc->setCpuId(system->registerExecContext(xc, id)); -#else - xc->setCpuId(xc->getProcessPtr()->registerExecContext(xc)); -#endif - } - } -} - - -void -BaseCPU::switchOut(Sampler *sampler) -{ - panic("This CPU doesn't support sampling!"); -} - -void -BaseCPU::takeOverFrom(BaseCPU *oldCPU) -{ - assert(execContexts.size() == oldCPU->execContexts.size()); - - for (int i = 0; i < execContexts.size(); ++i) { - ExecContext *newXC = execContexts[i]; - ExecContext *oldXC = oldCPU->execContexts[i]; - - newXC->takeOverFrom(oldXC); - assert(newXC->readCpuId() == oldXC->readCpuId()); -#if FULL_SYSTEM - system->replaceExecContext(newXC, newXC->readCpuId()); -#else - assert(newXC->getProcessPtr() == oldXC->getProcessPtr()); - newXC->getProcessPtr()->replaceExecContext(newXC, newXC->readCpuId()); -#endif - } - -#if FULL_SYSTEM - for (int i = 0; i < TheISA::NumInterruptLevels; ++i) - interrupts[i] = oldCPU->interrupts[i]; - intstatus = oldCPU->intstatus; - - for (int i = 0; i < execContexts.size(); ++i) - execContexts[i]->profileClear(); - - if (profileEvent) - profileEvent->schedule(curTick); -#endif -} - - -#if FULL_SYSTEM -BaseCPU::ProfileEvent::ProfileEvent(BaseCPU *_cpu, int _interval) - : Event(&mainEventQueue), cpu(_cpu), interval(_interval) -{ } - -void -BaseCPU::ProfileEvent::process() -{ - for (int i = 0, size = cpu->execContexts.size(); i < size; ++i) { - ExecContext *xc = cpu->execContexts[i]; - xc->profileSample(); - } - - schedule(curTick + interval); -} - -void -BaseCPU::post_interrupt(int int_num, int index) -{ - DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index); - - if (int_num < 0 || int_num >= TheISA::NumInterruptLevels) - panic("int_num out of bounds\n"); - - if (index < 0 || index >= sizeof(uint64_t) * 8) - panic("int_num out of bounds\n"); - - checkInterrupts = true; - interrupts[int_num] |= 1 << index; - intstatus |= (ULL(1) << int_num); -} - -void -BaseCPU::clear_interrupt(int int_num, int index) -{ - DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index); - - if (int_num < 0 || int_num >= TheISA::NumInterruptLevels) - panic("int_num out of bounds\n"); - - if (index < 0 || index >= sizeof(uint64_t) * 8) - panic("int_num out of bounds\n"); - - interrupts[int_num] &= ~(1 << index); - if (interrupts[int_num] == 0) - intstatus &= ~(ULL(1) << int_num); -} - -void -BaseCPU::clear_interrupts() -{ - DPRINTF(Interrupt, "Interrupts all cleared\n"); - - memset(interrupts, 0, sizeof(interrupts)); - intstatus = 0; -} - - -void -BaseCPU::serialize(std::ostream &os) -{ - SERIALIZE_ARRAY(interrupts, TheISA::NumInterruptLevels); - SERIALIZE_SCALAR(intstatus); -} - -void -BaseCPU::unserialize(Checkpoint *cp, const std::string §ion) -{ - UNSERIALIZE_ARRAY(interrupts, TheISA::NumInterruptLevels); - UNSERIALIZE_SCALAR(intstatus); -} - -#endif // FULL_SYSTEM - -void -BaseCPU::traceFunctionsInternal(Addr pc) -{ - if (!debugSymbolTable) - return; - - // if pc enters different function, print new function symbol and - // update saved range. Otherwise do nothing. - if (pc < currentFunctionStart || pc >= currentFunctionEnd) { - string sym_str; - bool found = debugSymbolTable->findNearestSymbol(pc, sym_str, - currentFunctionStart, - currentFunctionEnd); - - if (!found) { - // no symbol found: use addr as label - sym_str = csprintf("0x%x", pc); - currentFunctionStart = pc; - currentFunctionEnd = pc + 1; - } - - ccprintf(*functionTraceStream, " (%d)\n%d: %s", - curTick - functionEntryTick, curTick, sym_str); - functionEntryTick = curTick; - } -} - - -DEFINE_SIM_OBJECT_CLASS_NAME("BaseCPU", BaseCPU) diff --git a/cpu/base.hh b/cpu/base.hh deleted file mode 100644 index dd776859d..000000000 --- a/cpu/base.hh +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Copyright (c) 2002-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_BASE_HH__ -#define __CPU_BASE_HH__ - -#include <vector> - -#include "base/statistics.hh" -#include "config/full_system.hh" -#include "cpu/sampler/sampler.hh" -#include "sim/eventq.hh" -#include "sim/sim_object.hh" -#include "arch/isa_traits.hh" - -class BranchPred; -class CheckerCPU; -class ExecContext; -class System; - -class BaseCPU : public SimObject -{ - protected: - // CPU's clock period in terms of the number of ticks of curTime. - Tick clock; - - public: - inline Tick frequency() const { return Clock::Frequency / clock; } - inline Tick cycles(int numCycles) const { return clock * numCycles; } - inline Tick curCycle() const { return curTick / clock; } - -#if FULL_SYSTEM - protected: - uint64_t interrupts[TheISA::NumInterruptLevels]; - uint64_t intstatus; - - public: - virtual void post_interrupt(int int_num, int index); - virtual void clear_interrupt(int int_num, int index); - virtual void clear_interrupts(); - bool checkInterrupts; - - bool check_interrupt(int int_num) const { - if (int_num > TheISA::NumInterruptLevels) - panic("int_num out of bounds\n"); - - return interrupts[int_num] != 0; - } - - bool check_interrupts() const { return intstatus != 0; } - uint64_t intr_status() const { return intstatus; } - - class ProfileEvent : public Event - { - private: - BaseCPU *cpu; - int interval; - - public: - ProfileEvent(BaseCPU *cpu, int interval); - void process(); - }; - ProfileEvent *profileEvent; -#endif - - protected: - std::vector<ExecContext *> execContexts; - - public: - - /// Notify the CPU that the indicated context is now active. The - /// delay parameter indicates the number of ticks to wait before - /// executing (typically 0 or 1). - virtual void activateContext(int thread_num, int delay) {} - - /// Notify the CPU that the indicated context is now suspended. - virtual void suspendContext(int thread_num) {} - - /// Notify the CPU that the indicated context is now deallocated. - virtual void deallocateContext(int thread_num) {} - - /// Notify the CPU that the indicated context is now halted. - virtual void haltContext(int thread_num) {} - - public: - struct Params - { - std::string name; - int numberOfThreads; - bool deferRegistration; - Counter max_insts_any_thread; - Counter max_insts_all_threads; - Counter max_loads_any_thread; - Counter max_loads_all_threads; - Tick clock; - bool functionTrace; - Tick functionTraceStart; -#if FULL_SYSTEM - System *system; - int cpu_id; - Tick profile; -#endif - BaseCPU *checker; - - Params(); - }; - - const Params *params; - - BaseCPU(Params *params); - virtual ~BaseCPU(); - - virtual void init(); - virtual void startup(); - virtual void regStats(); - - virtual void activateWhenReady(int tid) {}; - - void registerExecContexts(); - - /// Prepare for another CPU to take over execution. When it is - /// is ready (drained pipe) it signals the sampler. - virtual void switchOut(Sampler *); - - /// Take over execution from the given CPU. Used for warm-up and - /// sampling. - virtual void takeOverFrom(BaseCPU *); - - /** - * Number of threads we're actually simulating (<= SMT_MAX_THREADS). - * This is a constant for the duration of the simulation. - */ - int number_of_threads; - - /** - * Vector of per-thread instruction-based event queues. Used for - * scheduling events based on number of instructions committed by - * a particular thread. - */ - EventQueue **comInstEventQueue; - - /** - * Vector of per-thread load-based event queues. Used for - * scheduling events based on number of loads committed by - *a particular thread. - */ - EventQueue **comLoadEventQueue; - -#if FULL_SYSTEM - System *system; - - /** - * Serialize this object to the given output stream. - * @param os The stream to serialize to. - */ - virtual void serialize(std::ostream &os); - - /** - * Reconstruct the state of this object from a checkpoint. - * @param cp The checkpoint use. - * @param section The section name of this object - */ - virtual void unserialize(Checkpoint *cp, const std::string §ion); - -#endif - - /** - * Return pointer to CPU's branch predictor (NULL if none). - * @return Branch predictor pointer. - */ - virtual BranchPred *getBranchPred() { return NULL; }; - - virtual Counter totalInstructions() const { return 0; } - - // Function tracing - private: - bool functionTracingEnabled; - std::ostream *functionTraceStream; - Addr currentFunctionStart; - Addr currentFunctionEnd; - Tick functionEntryTick; - void enableFunctionTrace(); - void traceFunctionsInternal(Addr pc); - - protected: - void traceFunctions(Addr pc) - { - if (functionTracingEnabled) - traceFunctionsInternal(pc); - } - - private: - static std::vector<BaseCPU *> cpuList; //!< Static global cpu list - - public: - static int numSimulatedCPUs() { return cpuList.size(); } - static Counter numSimulatedInstructions() - { - Counter total = 0; - - int size = cpuList.size(); - for (int i = 0; i < size; ++i) - total += cpuList[i]->totalInstructions(); - - return total; - } - - public: - // Number of CPU cycles simulated - Stats::Scalar<> numCycles; -}; - -#endif // __CPU_BASE_HH__ diff --git a/cpu/cpu_exec_context.cc b/cpu/cpu_exec_context.cc deleted file mode 100644 index e30295ef8..000000000 --- a/cpu/cpu_exec_context.cc +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Copyright (c) 2001-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <string> - -#include "cpu/base.hh" -#include "cpu/cpu_exec_context.hh" -#include "cpu/exec_context.hh" - -#if FULL_SYSTEM -#include "base/callback.hh" -#include "base/cprintf.hh" -#include "base/output.hh" -#include "base/trace.hh" -#include "cpu/profile.hh" -#include "cpu/quiesce_event.hh" -#include "kern/kernel_stats.hh" -#include "sim/serialize.hh" -#include "sim/sim_exit.hh" -#include "sim/system.hh" -#include "arch/stacktrace.hh" -#else -#include "sim/process.hh" -#endif - -using namespace std; - -// constructor -#if FULL_SYSTEM -CPUExecContext::CPUExecContext(BaseCPU *_cpu, int _thread_num, System *_sys, - AlphaITB *_itb, AlphaDTB *_dtb, - FunctionalMemory *_mem, - bool use_kernel_stats) - : _status(ExecContext::Unallocated), cpu(_cpu), thread_num(_thread_num), - cpu_id(-1), lastActivate(0), lastSuspend(0), mem(_mem), itb(_itb), - dtb(_dtb), system(_sys), memctrl(_sys->memctrl), physmem(_sys->physmem), - profile(NULL), func_exe_inst(0), storeCondFailures(0) -{ - proxy = new ProxyExecContext<CPUExecContext>(this); - - quiesceEvent = new EndQuiesceEvent(proxy); - - memset(®s, 0, sizeof(RegFile)); - - if (cpu->params->profile) { - profile = new FunctionProfile(system->kernelSymtab); - Callback *cb = - new MakeCallback<CPUExecContext, - &CPUExecContext::dumpFuncProfile>(this); - registerExitCallback(cb); - } - - // let's fill with a dummy node for now so we don't get a segfault - // on the first cycle when there's no node available. - static ProfileNode dummyNode; - profileNode = &dummyNode; - profilePC = 3; - - if (use_kernel_stats) { - kernelStats = new Kernel::Statistics(system); - } else { - kernelStats = NULL; - } -} -#else -CPUExecContext::CPUExecContext(BaseCPU *_cpu, int _thread_num, - Process *_process, int _asid) - : _status(ExecContext::Unallocated), - cpu(_cpu), thread_num(_thread_num), cpu_id(-1), lastActivate(0), - lastSuspend(0), process(_process), mem(process->getMemory()), asid(_asid), - func_exe_inst(0), storeCondFailures(0) -{ - memset(®s, 0, sizeof(RegFile)); - proxy = new ProxyExecContext<CPUExecContext>(this); -} - -CPUExecContext::CPUExecContext(BaseCPU *_cpu, int _thread_num, - FunctionalMemory *_mem, int _asid) - : cpu(_cpu), thread_num(_thread_num), process(0), mem(_mem), asid(_asid), - func_exe_inst(0), storeCondFailures(0) -{ - memset(®s, 0, sizeof(RegFile)); - proxy = new ProxyExecContext<CPUExecContext>(this); -} - -CPUExecContext::CPUExecContext(RegFile *regFile) - : cpu(NULL), thread_num(-1), process(NULL), mem(NULL), asid(-1), - func_exe_inst(0), storeCondFailures(0) -{ - regs = *regFile; - proxy = new ProxyExecContext<CPUExecContext>(this); -} - -#endif - -CPUExecContext::~CPUExecContext() -{ - delete proxy; -} - -#if FULL_SYSTEM -void -CPUExecContext::dumpFuncProfile() -{ - std::ostream *os = simout.create(csprintf("profile.%s.dat", cpu->name())); - profile->dump(proxy, *os); -} - -void -CPUExecContext::profileClear() -{ - if (profile) - profile->clear(); -} - -void -CPUExecContext::profileSample() -{ - if (profile) - profile->sample(profileNode, profilePC); -} - -#endif - -void -CPUExecContext::takeOverFrom(ExecContext *oldContext) -{ - // some things should already be set up - assert(mem == oldContext->getMemPtr()); -#if FULL_SYSTEM - assert(system == oldContext->getSystemPtr()); -#else - assert(process == oldContext->getProcessPtr()); -#endif - - // copy over functional state - _status = oldContext->status(); - copyArchRegs(oldContext); - cpu_id = oldContext->readCpuId(); -#if !FULL_SYSTEM - func_exe_inst = oldContext->readFuncExeInst(); -#else - EndQuiesceEvent *quiesce = oldContext->getQuiesceEvent(); - if (quiesce) { - // Point the quiesce event's XC at this XC so that it wakes up - // the proper CPU. - quiesce->xc = proxy; - } - if (quiesceEvent) { - quiesceEvent->xc = proxy; - } -#endif - - storeCondFailures = 0; - - oldContext->setStatus(ExecContext::Unallocated); -} - -void -CPUExecContext::serialize(ostream &os) -{ - SERIALIZE_ENUM(_status); - regs.serialize(os); - // thread_num and cpu_id are deterministic from the config - SERIALIZE_SCALAR(func_exe_inst); - SERIALIZE_SCALAR(inst); - -#if FULL_SYSTEM - Tick quiesceEndTick = 0; - if (quiesceEvent->scheduled()) - quiesceEndTick = quiesceEvent->when(); - SERIALIZE_SCALAR(quiesceEndTick); - if (kernelStats) - kernelStats->serialize(os); -#endif -} - - -void -CPUExecContext::unserialize(Checkpoint *cp, const std::string §ion) -{ - UNSERIALIZE_ENUM(_status); - regs.unserialize(cp, section); - // thread_num and cpu_id are deterministic from the config - UNSERIALIZE_SCALAR(func_exe_inst); - UNSERIALIZE_SCALAR(inst); - -#if FULL_SYSTEM - Tick quiesceEndTick; - UNSERIALIZE_SCALAR(quiesceEndTick); - if (quiesceEndTick) - quiesceEvent->schedule(quiesceEndTick); - if (kernelStats) - kernelStats->unserialize(cp, section); -#endif -} - - -void -CPUExecContext::activate(int delay) -{ - if (status() == ExecContext::Active) - return; - - lastActivate = curTick; - - if (status() == ExecContext::Unallocated) { - cpu->activateWhenReady(thread_num); - return; - } - - _status = ExecContext::Active; - - // status() == Suspended - cpu->activateContext(thread_num, delay); -} - -void -CPUExecContext::suspend() -{ - if (status() == ExecContext::Suspended) - return; - - lastActivate = curTick; - lastSuspend = curTick; -/* -#if FULL_SYSTEM - // Don't change the status from active if there are pending interrupts - if (cpu->check_interrupts()) { - assert(status() == ExecContext::Active); - return; - } -#endif -*/ - _status = ExecContext::Suspended; - cpu->suspendContext(thread_num); -} - -void -CPUExecContext::deallocate() -{ - if (status() == ExecContext::Unallocated) - return; - - _status = ExecContext::Unallocated; - cpu->deallocateContext(thread_num); -} - -void -CPUExecContext::halt() -{ - if (status() == ExecContext::Halted) - return; - - _status = ExecContext::Halted; - cpu->haltContext(thread_num); -} - - -void -CPUExecContext::regStats(const string &name) -{ -#if FULL_SYSTEM - if (kernelStats) - kernelStats->regStats(name + ".kern"); -#endif -} - -void -CPUExecContext::copyArchRegs(ExecContext *xc) -{ - // First loop through the integer registers. - for (int i = 0; i < AlphaISA::NumIntRegs; ++i) { - setIntReg(i, xc->readIntReg(i)); - } - - // Then loop through the floating point registers. - for (int i = 0; i < AlphaISA::NumFloatRegs; ++i) { - setFloatRegDouble(i, xc->readFloatRegDouble(i)); - setFloatRegInt(i, xc->readFloatRegInt(i)); - } - - // Copy misc. registers - regs.miscRegs.copyMiscRegs(xc); - - // Lastly copy PC/NPC - setPC(xc->readPC()); - setNextPC(xc->readNextPC()); -} - diff --git a/cpu/cpu_exec_context.hh b/cpu/cpu_exec_context.hh deleted file mode 100644 index 061fe450a..000000000 --- a/cpu/cpu_exec_context.hh +++ /dev/null @@ -1,524 +0,0 @@ -/* - * Copyright (c) 2001-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_CPU_EXEC_CONTEXT_HH__ -#define __CPU_CPU_EXEC_CONTEXT_HH__ - -#include "arch/isa_traits.hh" -#include "config/full_system.hh" -#include "cpu/exec_context.hh" -#include "mem/functional/functional.hh" -#include "mem/mem_req.hh" -#include "sim/byteswap.hh" -#include "sim/eventq.hh" -#include "sim/host.hh" -#include "sim/serialize.hh" - -// forward declaration: see functional_memory.hh -class FunctionalMemory; -class PhysicalMemory; -class BaseCPU; - -#if FULL_SYSTEM - -#include "sim/system.hh" -#include "arch/tlb.hh" - -class FunctionProfile; -class ProfileNode; -class MemoryController; - -namespace Kernel { - class Statistics; -}; - -#else // !FULL_SYSTEM - -#include "sim/process.hh" - -#endif // FULL_SYSTEM - -// -// The CPUExecContext object represents a functional context for -// instruction execution. It incorporates everything required for -// architecture-level functional simulation of a single thread. -// - -class CPUExecContext -{ - protected: - typedef TheISA::RegFile RegFile; - typedef TheISA::MachInst MachInst; - typedef TheISA::MiscRegFile MiscRegFile; - typedef TheISA::MiscReg MiscReg; - public: - typedef ExecContext::Status Status; - - private: - Status _status; - - public: - Status status() const { return _status; } - - void setStatus(Status newStatus) { _status = newStatus; } - - /// Set the status to Active. Optional delay indicates number of - /// cycles to wait before beginning execution. - void activate(int delay = 1); - - /// Set the status to Suspended. - void suspend(); - - /// Set the status to Unallocated. - void deallocate(); - - /// Set the status to Halted. - void halt(); - - protected: - RegFile regs; // correct-path register context - - public: - // pointer to CPU associated with this context - BaseCPU *cpu; - - ProxyExecContext<CPUExecContext> *proxy; - - // Current instruction - MachInst inst; - - // Index of hardware thread context on the CPU that this represents. - int thread_num; - - // ID of this context w.r.t. the System or Process object to which - // it belongs. For full-system mode, this is the system CPU ID. - int cpu_id; - - Tick lastActivate; - Tick lastSuspend; - -#if FULL_SYSTEM - FunctionalMemory *mem; - AlphaITB *itb; - AlphaDTB *dtb; - System *system; - - // the following two fields are redundant, since we can always - // look them up through the system pointer, but we'll leave them - // here for now for convenience - MemoryController *memctrl; - PhysicalMemory *physmem; - - FunctionProfile *profile; - ProfileNode *profileNode; - Addr profilePC; - void dumpFuncProfile(); - - EndQuiesceEvent *quiesceEvent; - - EndQuiesceEvent *getQuiesceEvent() { return quiesceEvent; } - - Tick readLastActivate() { return lastActivate; } - - Tick readLastSuspend() { return lastSuspend; } - - void profileClear(); - - void profileSample(); - - Kernel::Statistics *getKernelStats() { return kernelStats; } - - Kernel::Statistics *kernelStats; -#else - Process *process; - - FunctionalMemory *mem; // functional storage for process address space - - // Address space ID. Note that this is used for TIMING cache - // simulation only; all functional memory accesses should use - // one of the FunctionalMemory pointers above. - short asid; - -#endif - - /** - * Temporary storage to pass the source address from copy_load to - * copy_store. - * @todo Remove this temporary when we have a better way to do it. - */ - Addr copySrcAddr; - /** - * Temp storage for the physical source address of a copy. - * @todo Remove this temporary when we have a better way to do it. - */ - Addr copySrcPhysAddr; - - - /* - * number of executed instructions, for matching with syscall trace - * points in EIO files. - */ - Counter func_exe_inst; - - // - // Count failed store conditionals so we can warn of apparent - // application deadlock situations. - unsigned storeCondFailures; - - // constructor: initialize context from given process structure -#if FULL_SYSTEM - CPUExecContext(BaseCPU *_cpu, int _thread_num, System *_system, - AlphaITB *_itb, AlphaDTB *_dtb, FunctionalMemory *_mem, - bool use_kernel_stats = true); -#else - CPUExecContext(BaseCPU *_cpu, int _thread_num, Process *_process, int _asid); - CPUExecContext(BaseCPU *_cpu, int _thread_num, FunctionalMemory *_mem, - int _asid); - // Constructor to use XC to pass reg file around. Not used for anything - // else. - CPUExecContext(RegFile *regFile); -#endif - virtual ~CPUExecContext(); - - virtual void takeOverFrom(ExecContext *oldContext); - - void regStats(const std::string &name); - - void serialize(std::ostream &os); - void unserialize(Checkpoint *cp, const std::string §ion); - - BaseCPU *getCpuPtr() { return cpu; } - - ExecContext *getProxy() { return proxy; } - - int getThreadNum() { return thread_num; } - -#if FULL_SYSTEM - System *getSystemPtr() { return system; } - - PhysicalMemory *getPhysMemPtr() { return physmem; } - - AlphaITB *getITBPtr() { return itb; } - - AlphaDTB *getDTBPtr() { return dtb; } - - bool validInstAddr(Addr addr) { return true; } - bool validDataAddr(Addr addr) { return true; } - int getInstAsid() { return regs.instAsid(); } - int getDataAsid() { return regs.dataAsid(); } - - Fault translateInstReq(MemReqPtr &req) - { - return itb->translate(req); - } - - Fault translateDataReadReq(MemReqPtr &req) - { - return dtb->translate(req, false); - } - - Fault translateDataWriteReq(MemReqPtr &req) - { - return dtb->translate(req, true); - } - -#else - Process *getProcessPtr() { return process; } - - bool validInstAddr(Addr addr) - { return process->validInstAddr(addr); } - - bool validDataAddr(Addr addr) - { return process->validDataAddr(addr); } - - int getInstAsid() { return asid; } - int getDataAsid() { return asid; } - - Fault dummyTranslation(MemReqPtr &req) - { -#if 0 - assert((req->vaddr >> 48 & 0xffff) == 0); -#endif - - // put the asid in the upper 16 bits of the paddr - req->paddr = req->vaddr & ~((Addr)0xffff << sizeof(Addr) * 8 - 16); - req->paddr = req->paddr | (Addr)req->asid << sizeof(Addr) * 8 - 16; - return NoFault; - } - Fault translateInstReq(MemReqPtr &req) - { - return dummyTranslation(req); - } - Fault translateDataReadReq(MemReqPtr &req) - { - return dummyTranslation(req); - } - Fault translateDataWriteReq(MemReqPtr &req) - { - return dummyTranslation(req); - } - -#endif - - template <class T> - Fault read(MemReqPtr &req, T &data) - { -#if FULL_SYSTEM && defined(TARGET_ALPHA) - if (req->flags & LOCKED) { - req->xc->setMiscReg(TheISA::Lock_Addr_DepTag, req->paddr); - req->xc->setMiscReg(TheISA::Lock_Flag_DepTag, true); - } -#endif - - Fault error; - error = mem->read(req, data); - data = LittleEndianGuest::gtoh(data); - return error; - } - - template <class T> - Fault write(MemReqPtr &req, T &data) - { -#if FULL_SYSTEM && defined(TARGET_ALPHA) - ExecContext *xc; - - // If this is a store conditional, act appropriately - if (req->flags & LOCKED) { - xc = req->xc; - - if (req->flags & UNCACHEABLE) { - // Don't update result register (see stq_c in isa_desc) - req->result = 2; - xc->setStCondFailures(0);//Needed? [RGD] - } else { - bool lock_flag = xc->readMiscReg(TheISA::Lock_Flag_DepTag); - Addr lock_addr = xc->readMiscReg(TheISA::Lock_Addr_DepTag); - req->result = lock_flag; - if (!lock_flag || - ((lock_addr & ~0xf) != (req->paddr & ~0xf))) { - xc->setMiscReg(TheISA::Lock_Flag_DepTag, false); - xc->setStCondFailures(xc->readStCondFailures() + 1); - if (((xc->readStCondFailures()) % 100000) == 0) { - std::cerr << "Warning: " - << xc->readStCondFailures() - << " consecutive store conditional failures " - << "on cpu " << req->xc->readCpuId() - << std::endl; - } - return NoFault; - } - else xc->setStCondFailures(0); - } - } - - // Need to clear any locked flags on other proccessors for - // this address. Only do this for succsful Store Conditionals - // and all other stores (WH64?). Unsuccessful Store - // Conditionals would have returned above, and wouldn't fall - // through. - for (int i = 0; i < system->execContexts.size(); i++){ - xc = system->execContexts[i]; - if ((xc->readMiscReg(TheISA::Lock_Addr_DepTag) & ~0xf) == - (req->paddr & ~0xf)) { - xc->setMiscReg(TheISA::Lock_Flag_DepTag, false); - } - } - -#endif - return mem->write(req, (T)LittleEndianGuest::htog(data)); - } - - virtual bool misspeculating(); - - - MachInst getInst() { return inst; } - - void setInst(MachInst new_inst) - { - inst = new_inst; - } - - Fault instRead(MemReqPtr &req) - { - return mem->read(req, inst); - } - - void setCpuId(int id) { cpu_id = id; } - - int readCpuId() { return cpu_id; } - - FunctionalMemory *getMemPtr() { return mem; } - - void copyArchRegs(ExecContext *xc); - - // - // New accessors for new decoder. - // - uint64_t readIntReg(int reg_idx) - { - return regs.intRegFile[reg_idx]; - } - - float readFloatRegSingle(int reg_idx) - { - return (float)regs.floatRegFile.d[reg_idx]; - } - - double readFloatRegDouble(int reg_idx) - { - return regs.floatRegFile.d[reg_idx]; - } - - uint64_t readFloatRegInt(int reg_idx) - { - return regs.floatRegFile.q[reg_idx]; - } - - void setIntReg(int reg_idx, uint64_t val) - { - regs.intRegFile[reg_idx] = val; - } - - void setFloatRegSingle(int reg_idx, float val) - { - regs.floatRegFile.d[reg_idx] = (double)val; - } - - void setFloatRegDouble(int reg_idx, double val) - { - regs.floatRegFile.d[reg_idx] = val; - } - - void setFloatRegInt(int reg_idx, uint64_t val) - { - regs.floatRegFile.q[reg_idx] = val; - } - - uint64_t readPC() - { - return regs.pc; - } - - void setPC(uint64_t val) - { - regs.pc = val; - } - - uint64_t readNextPC() - { - return regs.npc; - } - - void setNextPC(uint64_t val) - { - regs.npc = val; - } - - uint64_t readNextNPC() - { - return regs.nnpc; - } - - void setNextNPC(uint64_t val) - { - regs.nnpc = val; - } - - - MiscReg readMiscReg(int misc_reg) - { - return regs.miscRegs.readReg(misc_reg); - } - - MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault) - { - return regs.miscRegs.readRegWithEffect(misc_reg, fault, proxy); - } - - Fault setMiscReg(int misc_reg, const MiscReg &val) - { - return regs.miscRegs.setReg(misc_reg, val); - } - - Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val) - { - return regs.miscRegs.setRegWithEffect(misc_reg, val, proxy); - } - - unsigned readStCondFailures() { return storeCondFailures; } - - void setStCondFailures(unsigned sc_failures) - { storeCondFailures = sc_failures; } - - void clearArchRegs() { memset(®s, 0, sizeof(regs)); } - -#if FULL_SYSTEM - int readIntrFlag() { return regs.intrflag; } - void setIntrFlag(int val) { regs.intrflag = val; } - Fault hwrei(); - bool inPalMode() { return AlphaISA::PcPAL(regs.pc); } - bool simPalCheck(int palFunc); -#endif - -#if !FULL_SYSTEM - TheISA::IntReg getSyscallArg(int i) - { - return regs.intRegFile[TheISA::ArgumentReg0 + i]; - } - - // used to shift args for indirect syscall - void setSyscallArg(int i, TheISA::IntReg val) - { - regs.intRegFile[TheISA::ArgumentReg0 + i] = val; - } - - void setSyscallReturn(SyscallReturn return_value) - { - TheISA::setSyscallReturn(return_value, ®s); - } - - void syscall() - { - process->syscall(proxy); - } - - Counter readFuncExeInst() { return func_exe_inst; } - - void setFuncExeInst(Counter new_val) { func_exe_inst = new_val; } -#endif -}; - - -// for non-speculative execution context, spec_mode is always false -inline bool -CPUExecContext::misspeculating() -{ - return false; -} - -#endif // __CPU_CPU_EXEC_CONTEXT_HH__ diff --git a/cpu/cpu_models.py b/cpu/cpu_models.py deleted file mode 100644 index 2b1ae6277..000000000 --- a/cpu/cpu_models.py +++ /dev/null @@ -1,80 +0,0 @@ -# Copyright (c) 2003-2006 The Regents of The University of Michigan -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer; -# redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution; -# neither the name of the copyright holders nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -################ -# CpuModel class -# -# The CpuModel class encapsulates everything the ISA parser needs to -# know about a particular CPU model. - -class CpuModel: - # Dict of available CPU model objects. Accessible as CpuModel.dict. - dict = {} - - # Constructor. Automatically adds models to CpuModel.dict. - def __init__(self, name, filename, includes, strings): - self.name = name - self.filename = filename # filename for output exec code - self.includes = includes # include files needed in exec file - # The 'strings' dict holds all the per-CPU symbols we can - # substitute into templates etc. - self.strings = strings - # Add self to dict - CpuModel.dict[name] = self - - -# -# Define CPU models. -# -# Parameters are: -# - name of model -# - filename for generated ISA execution file -# - includes needed for generated ISA execution file -# - substitution strings for ISA description templates -# - -CpuModel('SimpleCPU', 'simple_cpu_exec.cc', - '#include "cpu/simple/cpu.hh"', - { 'CPU_exec_context': 'SimpleCPU' }) -CpuModel('FastCPU', 'fast_cpu_exec.cc', - '#include "cpu/fast/cpu.hh"', - { 'CPU_exec_context': 'FastCPU' }) -CpuModel('FullCPU', 'full_cpu_exec.cc', - '#include "encumbered/cpu/full/dyn_inst.hh"', - { 'CPU_exec_context': 'DynInst' }) -CpuModel('AlphaFullCPU', 'alpha_o3_exec.cc', - '#include "cpu/o3/alpha_dyn_inst.hh"', - { 'CPU_exec_context': 'AlphaDynInst<AlphaSimpleImpl>' }) -CpuModel('OzoneSimpleCPU', 'ozone_simple_exec.cc', - '#include "cpu/ozone/dyn_inst.hh"', - { 'CPU_exec_context': 'OzoneDynInst<SimpleImpl>' }) -CpuModel('OzoneCPU', 'ozone_exec.cc', - '#include "cpu/ozone/dyn_inst.hh"', - { 'CPU_exec_context': 'OzoneDynInst<OzoneImpl>' }) -CpuModel('CheckerCPU', 'checker_cpu_exec.cc', - '#include "cpu/checker/cpu.hh"', - { 'CPU_exec_context': 'CheckerCPU' }) - diff --git a/cpu/exec_context.hh b/cpu/exec_context.hh deleted file mode 100644 index e1f1016e5..000000000 --- a/cpu/exec_context.hh +++ /dev/null @@ -1,382 +0,0 @@ -/* - * Copyright (c) 2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_EXEC_CONTEXT_HH__ -#define __CPU_EXEC_CONTEXT_HH__ - -#include "config/full_system.hh" -#include "mem/mem_req.hh" -#include "sim/faults.hh" -#include "sim/host.hh" -#include "sim/serialize.hh" -#include "sim/byteswap.hh" - -// forward declaration: see functional_memory.hh -// @todo: Figure out a more architecture independent way to obtain the ITB and -// DTB pointers. -class AlphaDTB; -class AlphaITB; -class BaseCPU; -class EndQuiesceEvent; -class Event; -class FunctionalMemory; -class PhysicalMemory; -class Process; -class System; -namespace Kernel { - class Statistics; -}; - -class ExecContext -{ - protected: - typedef TheISA::RegFile RegFile; - typedef TheISA::MachInst MachInst; - typedef TheISA::IntReg IntReg; - typedef TheISA::MiscRegFile MiscRegFile; - typedef TheISA::MiscReg MiscReg; - public: - enum Status - { - /// Initialized but not running yet. All CPUs start in - /// this state, but most transition to Active on cycle 1. - /// In MP or SMT systems, non-primary contexts will stay - /// in this state until a thread is assigned to them. - Unallocated, - - /// Running. Instructions should be executed only when - /// the context is in this state. - Active, - - /// Temporarily inactive. Entered while waiting for - /// synchronization, etc. - Suspended, - - /// Permanently shut down. Entered when target executes - /// m5exit pseudo-instruction. When all contexts enter - /// this state, the simulation will terminate. - Halted - }; - - virtual ~ExecContext() { }; - - virtual BaseCPU *getCpuPtr() = 0; - - virtual void setCpuId(int id) = 0; - - virtual int readCpuId() = 0; - - virtual FunctionalMemory *getMemPtr() = 0; - -#if FULL_SYSTEM - virtual System *getSystemPtr() = 0; - - virtual PhysicalMemory *getPhysMemPtr() = 0; - - virtual AlphaITB *getITBPtr() = 0; - - virtual AlphaDTB * getDTBPtr() = 0; - - virtual Kernel::Statistics *getKernelStats() = 0; -#else - virtual Process *getProcessPtr() = 0; -#endif - - virtual Status status() const = 0; - - virtual void setStatus(Status new_status) = 0; - - /// Set the status to Active. Optional delay indicates number of - /// cycles to wait before beginning execution. - virtual void activate(int delay = 1) = 0; - - /// Set the status to Suspended. - virtual void suspend() = 0; - - /// Set the status to Unallocated. - virtual void deallocate() = 0; - - /// Set the status to Halted. - virtual void halt() = 0; - -#if FULL_SYSTEM - virtual void dumpFuncProfile() = 0; -#endif - - virtual void takeOverFrom(ExecContext *old_context) = 0; - - virtual void regStats(const std::string &name) = 0; - - virtual void serialize(std::ostream &os) = 0; - virtual void unserialize(Checkpoint *cp, const std::string §ion) = 0; - -#if FULL_SYSTEM - virtual EndQuiesceEvent *getQuiesceEvent() = 0; - - // Not necessarily the best location for these... - // Having an extra function just to read these is obnoxious - virtual Tick readLastActivate() = 0; - virtual Tick readLastSuspend() = 0; - - virtual void profileClear() = 0; - virtual void profileSample() = 0; -#endif - - virtual int getThreadNum() = 0; - - // Also somewhat obnoxious. Really only used for the TLB fault. - // However, may be quite useful in SPARC. - virtual TheISA::MachInst getInst() = 0; - - virtual void copyArchRegs(ExecContext *xc) = 0; - - virtual void clearArchRegs() = 0; - - // - // New accessors for new decoder. - // - virtual uint64_t readIntReg(int reg_idx) = 0; - - virtual float readFloatRegSingle(int reg_idx) = 0; - - virtual double readFloatRegDouble(int reg_idx) = 0; - - virtual uint64_t readFloatRegInt(int reg_idx) = 0; - - virtual void setIntReg(int reg_idx, uint64_t val) = 0; - - virtual void setFloatRegSingle(int reg_idx, float val) = 0; - - virtual void setFloatRegDouble(int reg_idx, double val) = 0; - - virtual void setFloatRegInt(int reg_idx, uint64_t val) = 0; - - virtual uint64_t readPC() = 0; - - virtual void setPC(uint64_t val) = 0; - - virtual uint64_t readNextPC() = 0; - - virtual void setNextPC(uint64_t val) = 0; - - virtual MiscReg readMiscReg(int misc_reg) = 0; - - virtual MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault) = 0; - - virtual Fault setMiscReg(int misc_reg, const MiscReg &val) = 0; - - virtual Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val) = 0; - - // Also not necessarily the best location for these two. Hopefully will go - // away once we decide upon where st cond failures goes. - virtual unsigned readStCondFailures() = 0; - - virtual void setStCondFailures(unsigned sc_failures) = 0; - -#if FULL_SYSTEM - virtual bool inPalMode() = 0; -#endif - - // Only really makes sense for old CPU model. Still could be useful though. - virtual bool misspeculating() = 0; - -#if !FULL_SYSTEM - virtual IntReg getSyscallArg(int i) = 0; - - // used to shift args for indirect syscall - virtual void setSyscallArg(int i, IntReg val) = 0; - - virtual void setSyscallReturn(SyscallReturn return_value) = 0; - -// virtual void syscall() = 0; - - // Same with st cond failures. - virtual Counter readFuncExeInst() = 0; -#endif -}; - -template <class XC> -class ProxyExecContext : public ExecContext -{ - public: - ProxyExecContext(XC *actual_xc) - { actualXC = actual_xc; } - - private: - XC *actualXC; - - public: - - BaseCPU *getCpuPtr() { return actualXC->getCpuPtr(); } - - void setCpuId(int id) { actualXC->setCpuId(id); } - - int readCpuId() { return actualXC->readCpuId(); } - - FunctionalMemory *getMemPtr() { return actualXC->getMemPtr(); } - -#if FULL_SYSTEM - System *getSystemPtr() { return actualXC->getSystemPtr(); } - - PhysicalMemory *getPhysMemPtr() { return actualXC->getPhysMemPtr(); } - - AlphaITB *getITBPtr() { return actualXC->getITBPtr(); } - - AlphaDTB *getDTBPtr() { return actualXC->getDTBPtr(); } - - Kernel::Statistics *getKernelStats() { return actualXC->getKernelStats(); } -#else - Process *getProcessPtr() { return actualXC->getProcessPtr(); } -#endif - - Status status() const { return actualXC->status(); } - - void setStatus(Status new_status) { actualXC->setStatus(new_status); } - - /// Set the status to Active. Optional delay indicates number of - /// cycles to wait before beginning execution. - void activate(int delay = 1) { actualXC->activate(delay); } - - /// Set the status to Suspended. - void suspend() { actualXC->suspend(); } - - /// Set the status to Unallocated. - void deallocate() { actualXC->deallocate(); } - - /// Set the status to Halted. - void halt() { actualXC->halt(); } - -#if FULL_SYSTEM - void dumpFuncProfile() { actualXC->dumpFuncProfile(); } -#endif - - void takeOverFrom(ExecContext *oldContext) - { actualXC->takeOverFrom(oldContext); } - - void regStats(const std::string &name) { actualXC->regStats(name); } - - void serialize(std::ostream &os) { actualXC->serialize(os); } - void unserialize(Checkpoint *cp, const std::string §ion) - { actualXC->unserialize(cp, section); } - -#if FULL_SYSTEM - EndQuiesceEvent *getQuiesceEvent() { return actualXC->getQuiesceEvent(); } - - Tick readLastActivate() { return actualXC->readLastActivate(); } - Tick readLastSuspend() { return actualXC->readLastSuspend(); } - - void profileClear() { return actualXC->profileClear(); } - void profileSample() { return actualXC->profileSample(); } -#endif - - int getThreadNum() { return actualXC->getThreadNum(); } - - // @todo: Do I need this? - MachInst getInst() { return actualXC->getInst(); } - - // @todo: Do I need this? - void copyArchRegs(ExecContext *xc) { actualXC->copyArchRegs(xc); } - - void clearArchRegs() { actualXC->clearArchRegs(); } - - // - // New accessors for new decoder. - // - uint64_t readIntReg(int reg_idx) - { return actualXC->readIntReg(reg_idx); } - - float readFloatRegSingle(int reg_idx) - { return actualXC->readFloatRegSingle(reg_idx); } - - double readFloatRegDouble(int reg_idx) - { return actualXC->readFloatRegDouble(reg_idx); } - - uint64_t readFloatRegInt(int reg_idx) - { return actualXC->readFloatRegInt(reg_idx); } - - void setIntReg(int reg_idx, uint64_t val) - { actualXC->setIntReg(reg_idx, val); } - - void setFloatRegSingle(int reg_idx, float val) - { actualXC->setFloatRegSingle(reg_idx, val); } - - void setFloatRegDouble(int reg_idx, double val) - { actualXC->setFloatRegDouble(reg_idx, val); } - - void setFloatRegInt(int reg_idx, uint64_t val) - { actualXC->setFloatRegInt(reg_idx, val); } - - uint64_t readPC() { return actualXC->readPC(); } - - void setPC(uint64_t val) { actualXC->setPC(val); } - - uint64_t readNextPC() { return actualXC->readNextPC(); } - - void setNextPC(uint64_t val) { actualXC->setNextPC(val); } - - MiscReg readMiscReg(int misc_reg) - { return actualXC->readMiscReg(misc_reg); } - - MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault) - { return actualXC->readMiscRegWithEffect(misc_reg, fault); } - - Fault setMiscReg(int misc_reg, const MiscReg &val) - { return actualXC->setMiscReg(misc_reg, val); } - - Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val) - { return actualXC->setMiscRegWithEffect(misc_reg, val); } - - unsigned readStCondFailures() - { return actualXC->readStCondFailures(); } - - void setStCondFailures(unsigned sc_failures) - { actualXC->setStCondFailures(sc_failures); } -#if FULL_SYSTEM - bool inPalMode() { return actualXC->inPalMode(); } -#endif - - // @todo: Fix this! - bool misspeculating() { return actualXC->misspeculating(); } - -#if !FULL_SYSTEM - IntReg getSyscallArg(int i) { return actualXC->getSyscallArg(i); } - - // used to shift args for indirect syscall - void setSyscallArg(int i, IntReg val) - { actualXC->setSyscallArg(i, val); } - - void setSyscallReturn(SyscallReturn return_value) - { actualXC->setSyscallReturn(return_value); } - -// void syscall() { actualXC->syscall(); } - - Counter readFuncExeInst() { return actualXC->readFuncExeInst(); } -#endif -}; - -#endif diff --git a/cpu/exetrace.cc b/cpu/exetrace.cc deleted file mode 100644 index d5eacd839..000000000 --- a/cpu/exetrace.cc +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Copyright (c) 2001-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <fstream> -#include <iomanip> - -#include "sim/param.hh" -#include "encumbered/cpu/full/dyn_inst.hh" -#include "encumbered/cpu/full/spec_state.hh" -#include "encumbered/cpu/full/issue.hh" -#include "cpu/exetrace.hh" -#include "base/loader/symtab.hh" -#include "cpu/base.hh" -#include "cpu/static_inst.hh" - -using namespace std; - - -//////////////////////////////////////////////////////////////////////// -// -// Methods for the InstRecord object -// - - -void -Trace::InstRecord::dump(ostream &outs) -{ - if (flags[INTEL_FORMAT]) { -#if FULL_SYSTEM - bool is_trace_system = (cpu->system->name() == trace_system); -#else - bool is_trace_system = true; -#endif - if (is_trace_system) { - ccprintf(outs, "%7d ) ", cycle); - outs << "0x" << hex << PC << ":\t"; - if (staticInst->isLoad()) { - outs << "<RD 0x" << hex << addr; - outs << ">"; - } else if (staticInst->isStore()) { - outs << "<WR 0x" << hex << addr; - outs << ">"; - } - outs << endl; - } - } else { - if (flags[PRINT_CYCLE]) - ccprintf(outs, "%7d: ", cycle); - - outs << cpu->name() << " "; - - if (flags[TRACE_MISSPEC]) - outs << (misspeculating ? "-" : "+") << " "; - - if (flags[PRINT_THREAD_NUM]) - outs << "T" << thread << " : "; - - - std::string sym_str; - Addr sym_addr; - if (debugSymbolTable - && debugSymbolTable->findNearestSymbol(PC, sym_str, sym_addr) - && flags[PC_SYMBOL]) { - if (PC != sym_addr) - sym_str += csprintf("+%d", PC - sym_addr); - outs << "@" << sym_str << " : "; - } - else { - outs << "0x" << hex << PC << " : "; - } - - // - // Print decoded instruction - // - -#if defined(__GNUC__) && (__GNUC__ < 3) - // There's a bug in gcc 2.x library that prevents setw() - // from working properly on strings - string mc(staticInst->disassemble(PC, debugSymbolTable)); - while (mc.length() < 26) - mc += " "; - outs << mc; -#else - outs << setw(26) << left << staticInst->disassemble(PC, debugSymbolTable); -#endif - - outs << " : "; - - if (flags[PRINT_OP_CLASS]) { - outs << opClassStrings[staticInst->opClass()] << " : "; - } - - if (flags[PRINT_RESULT_DATA] && data_status != DataInvalid) { - outs << " D="; -#if 0 - if (data_status == DataDouble) - ccprintf(outs, "%f", data.as_double); - else - ccprintf(outs, "%#018x", data.as_int); -#else - ccprintf(outs, "%#018x", data.as_int); -#endif - } - - if (flags[PRINT_EFF_ADDR] && addr_valid) - outs << " A=0x" << hex << addr; - - if (flags[PRINT_INT_REGS] && regs_valid) { - for (int i = 0; i < 32;) - for (int j = i + 1; i <= j; i++) - ccprintf(outs, "r%02d = %#018x%s", i, iregs->regs[i], - ((i == j) ? "\n" : " ")); - outs << "\n"; - } - - if (flags[PRINT_FETCH_SEQ] && fetch_seq_valid) - outs << " FetchSeq=" << dec << fetch_seq; - - if (flags[PRINT_CP_SEQ] && cp_seq_valid) - outs << " CPSeq=" << dec << cp_seq; - - // - // End of line... - // - outs << endl; - } -} - - -vector<bool> Trace::InstRecord::flags(NUM_BITS); -string Trace::InstRecord::trace_system; - -//////////////////////////////////////////////////////////////////////// -// -// Parameter space for per-cycle execution address tracing options. -// Derive from ParamContext so we can override checkParams() function. -// -class ExecutionTraceParamContext : public ParamContext -{ - public: - ExecutionTraceParamContext(const string &_iniSection) - : ParamContext(_iniSection) - { - } - - void checkParams(); // defined at bottom of file -}; - -ExecutionTraceParamContext exeTraceParams("exetrace"); - -Param<bool> exe_trace_spec(&exeTraceParams, "speculative", - "capture speculative instructions", true); - -Param<bool> exe_trace_print_cycle(&exeTraceParams, "print_cycle", - "print cycle number", true); -Param<bool> exe_trace_print_opclass(&exeTraceParams, "print_opclass", - "print op class", true); -Param<bool> exe_trace_print_thread(&exeTraceParams, "print_thread", - "print thread number", true); -Param<bool> exe_trace_print_effaddr(&exeTraceParams, "print_effaddr", - "print effective address", true); -Param<bool> exe_trace_print_data(&exeTraceParams, "print_data", - "print result data", true); -Param<bool> exe_trace_print_iregs(&exeTraceParams, "print_iregs", - "print all integer regs", false); -Param<bool> exe_trace_print_fetchseq(&exeTraceParams, "print_fetchseq", - "print fetch sequence number", false); -Param<bool> exe_trace_print_cp_seq(&exeTraceParams, "print_cpseq", - "print correct-path sequence number", false); -Param<bool> exe_trace_pc_symbol(&exeTraceParams, "pc_symbol", - "Use symbols for the PC if available", true); -Param<bool> exe_trace_intel_format(&exeTraceParams, "intel_format", - "print trace in intel compatible format", false); -Param<string> exe_trace_system(&exeTraceParams, "trace_system", - "print trace of which system (client or server)", - "client"); - - -// -// Helper function for ExecutionTraceParamContext::checkParams() just -// to get us into the InstRecord namespace -// -void -Trace::InstRecord::setParams() -{ - flags[TRACE_MISSPEC] = exe_trace_spec; - - flags[PRINT_CYCLE] = exe_trace_print_cycle; - flags[PRINT_OP_CLASS] = exe_trace_print_opclass; - flags[PRINT_THREAD_NUM] = exe_trace_print_thread; - flags[PRINT_RESULT_DATA] = exe_trace_print_effaddr; - flags[PRINT_EFF_ADDR] = exe_trace_print_data; - flags[PRINT_INT_REGS] = exe_trace_print_iregs; - flags[PRINT_FETCH_SEQ] = exe_trace_print_fetchseq; - flags[PRINT_CP_SEQ] = exe_trace_print_cp_seq; - flags[PC_SYMBOL] = exe_trace_pc_symbol; - flags[INTEL_FORMAT] = exe_trace_intel_format; - trace_system = exe_trace_system; -} - -void -ExecutionTraceParamContext::checkParams() -{ - Trace::InstRecord::setParams(); -} - diff --git a/cpu/exetrace.hh b/cpu/exetrace.hh deleted file mode 100644 index 2f70e26e7..000000000 --- a/cpu/exetrace.hh +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright (c) 2001-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __EXETRACE_HH__ -#define __EXETRACE_HH__ - -#include <fstream> -#include <vector> - -#include "sim/host.hh" -#include "cpu/inst_seq.hh" // for InstSeqNum -#include "base/trace.hh" -#include "cpu/exec_context.hh" -#include "cpu/static_inst.hh" - -class BaseCPU; - - -namespace Trace { - -class InstRecord : public Record -{ - protected: - typedef TheISA::IntRegFile IntRegFile; - - // The following fields are initialized by the constructor and - // thus guaranteed to be valid. - BaseCPU *cpu; - // need to make this ref-counted so it doesn't go away before we - // dump the record - StaticInstPtr staticInst; - Addr PC; - bool misspeculating; - unsigned thread; - - // The remaining fields are only valid for particular instruction - // types (e.g, addresses for memory ops) or when particular - // options are enabled (e.g., tracing full register contents). - // Each data field has an associated valid flag to indicate - // whether the data field is valid. - Addr addr; - bool addr_valid; - - union { - uint64_t as_int; - double as_double; - } data; - enum { - DataInvalid = 0, - DataInt8 = 1, // set to equal number of bytes - DataInt16 = 2, - DataInt32 = 4, - DataInt64 = 8, - DataDouble = 3 - } data_status; - - InstSeqNum fetch_seq; - bool fetch_seq_valid; - - InstSeqNum cp_seq; - bool cp_seq_valid; - - struct iRegFile { - IntRegFile regs; - }; - iRegFile *iregs; - bool regs_valid; - - public: - InstRecord(Tick _cycle, BaseCPU *_cpu, - const StaticInstPtr &_staticInst, - Addr _pc, bool spec, int _thread) - : Record(_cycle), cpu(_cpu), staticInst(_staticInst), PC(_pc), - misspeculating(spec), thread(_thread) - { - data_status = DataInvalid; - addr_valid = false; - regs_valid = false; - - fetch_seq_valid = false; - cp_seq_valid = false; - } - - virtual ~InstRecord() { } - - virtual void dump(std::ostream &outs); - - void setAddr(Addr a) { addr = a; addr_valid = true; } - - void setData(uint64_t d) { data.as_int = d; data_status = DataInt64; } - void setData(uint32_t d) { data.as_int = d; data_status = DataInt32; } - void setData(uint16_t d) { data.as_int = d; data_status = DataInt16; } - void setData(uint8_t d) { data.as_int = d; data_status = DataInt8; } - - void setData(int64_t d) { setData((uint64_t)d); } - void setData(int32_t d) { setData((uint32_t)d); } - void setData(int16_t d) { setData((uint16_t)d); } - void setData(int8_t d) { setData((uint8_t)d); } - - void setData(double d) { data.as_double = d; data_status = DataDouble; } - - void setFetchSeq(InstSeqNum seq) - { fetch_seq = seq; fetch_seq_valid = true; } - - void setCPSeq(InstSeqNum seq) - { cp_seq = seq; cp_seq_valid = true; } - - void setRegs(const IntRegFile ®s); - - void finalize() { theLog.append(this); } - - enum InstExecFlagBits { - TRACE_MISSPEC = 0, - PRINT_CYCLE, - PRINT_OP_CLASS, - PRINT_THREAD_NUM, - PRINT_RESULT_DATA, - PRINT_EFF_ADDR, - PRINT_INT_REGS, - PRINT_FETCH_SEQ, - PRINT_CP_SEQ, - PC_SYMBOL, - INTEL_FORMAT, - NUM_BITS - }; - - static std::vector<bool> flags; - static std::string trace_system; - - static void setParams(); - - static bool traceMisspec() { return flags[TRACE_MISSPEC]; } -}; - - -inline void -InstRecord::setRegs(const IntRegFile ®s) -{ - if (!iregs) - iregs = new iRegFile; - - memcpy(&iregs->regs, regs, sizeof(IntRegFile)); - regs_valid = true; -} - -inline -InstRecord * -getInstRecord(Tick cycle, ExecContext *xc, BaseCPU *cpu, - const StaticInstPtr staticInst, - Addr pc, int thread = 0) -{ - if (DTRACE(InstExec) && - (InstRecord::traceMisspec() || !xc->misspeculating())) { - return new InstRecord(cycle, cpu, staticInst, pc, - xc->misspeculating(), thread); - } - - return NULL; -} - - -} - -#endif // __EXETRACE_HH__ diff --git a/cpu/memtest/memtest.cc b/cpu/memtest/memtest.cc deleted file mode 100644 index 94b66b70b..000000000 --- a/cpu/memtest/memtest.cc +++ /dev/null @@ -1,441 +0,0 @@ -/* - * Copyright (c) 2002-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -// FIX ME: make trackBlkAddr use blocksize from actual cache, not hard coded - -#include <iomanip> -#include <set> -#include <sstream> -#include <string> -#include <vector> - -#include "base/misc.hh" -#include "base/statistics.hh" -#include "cpu/cpu_exec_context.hh" -#include "cpu/memtest/memtest.hh" -#include "mem/cache/base_cache.hh" -#include "sim/builder.hh" -#include "sim/sim_events.hh" -#include "sim/stats.hh" - -using namespace std; -using namespace TheISA; - -int TESTER_ALLOCATOR=0; - -MemTest::MemTest(const string &name, - MemInterface *_cache_interface, - FunctionalMemory *main_mem, - FunctionalMemory *check_mem, - unsigned _memorySize, - unsigned _percentReads, - unsigned _percentCopies, - unsigned _percentUncacheable, - unsigned _progressInterval, - unsigned _percentSourceUnaligned, - unsigned _percentDestUnaligned, - Addr _traceAddr, - Counter _max_loads) - : SimObject(name), - tickEvent(this), - cacheInterface(_cache_interface), - mainMem(main_mem), - checkMem(check_mem), - size(_memorySize), - percentReads(_percentReads), - percentCopies(_percentCopies), - percentUncacheable(_percentUncacheable), - progressInterval(_progressInterval), - nextProgressMessage(_progressInterval), - percentSourceUnaligned(_percentSourceUnaligned), - percentDestUnaligned(percentDestUnaligned), - maxLoads(_max_loads) -{ - vector<string> cmd; - cmd.push_back("/bin/ls"); - vector<string> null_vec; - cpuXC = new CPUExecContext(NULL, 0, mainMem, 0); - - blockSize = cacheInterface->getBlockSize(); - blockAddrMask = blockSize - 1; - traceBlockAddr = blockAddr(_traceAddr); - - //setup data storage with interesting values - uint8_t *data1 = new uint8_t[size]; - uint8_t *data2 = new uint8_t[size]; - uint8_t *data3 = new uint8_t[size]; - memset(data1, 1, size); - memset(data2, 2, size); - memset(data3, 3, size); - curTick = 0; - - baseAddr1 = 0x100000; - baseAddr2 = 0x400000; - uncacheAddr = 0x800000; - - // set up intial memory contents here - mainMem->prot_write(baseAddr1, data1, size); - checkMem->prot_write(baseAddr1, data1, size); - mainMem->prot_write(baseAddr2, data2, size); - checkMem->prot_write(baseAddr2, data2, size); - mainMem->prot_write(uncacheAddr, data3, size); - checkMem->prot_write(uncacheAddr, data3, size); - - delete [] data1; - delete [] data2; - delete [] data3; - - // set up counters - noResponseCycles = 0; - numReads = 0; - tickEvent.schedule(0); - - id = TESTER_ALLOCATOR++; -} - -static void -printData(ostream &os, uint8_t *data, int nbytes) -{ - os << hex << setfill('0'); - // assume little-endian: print bytes from highest address to lowest - for (uint8_t *dp = data + nbytes - 1; dp >= data; --dp) { - os << setw(2) << (unsigned)*dp; - } - os << dec; -} - -void -MemTest::completeRequest(MemReqPtr &req, uint8_t *data) -{ - //Remove the address from the list of outstanding - std::set<unsigned>::iterator removeAddr = outstandingAddrs.find(req->paddr); - assert(removeAddr != outstandingAddrs.end()); - outstandingAddrs.erase(removeAddr); - - switch (req->cmd) { - case Read: - if (memcmp(req->data, data, req->size) != 0) { - cerr << name() << ": on read of 0x" << hex << req->paddr - << " (0x" << hex << blockAddr(req->paddr) << ")" - << "@ cycle " << dec << curTick - << ", cache returns 0x"; - printData(cerr, req->data, req->size); - cerr << ", expected 0x"; - printData(cerr, data, req->size); - cerr << endl; - fatal(""); - } - - numReads++; - numReadsStat++; - - if (numReads == nextProgressMessage) { - ccprintf(cerr, "%s: completed %d read accesses @%d\n", - name(), numReads, curTick); - nextProgressMessage += progressInterval; - } - - if (numReads >= maxLoads) - SimExit(curTick, "Maximum number of loads reached!"); - break; - - case Write: - numWritesStat++; - break; - - case Copy: - //Also remove dest from outstanding list - removeAddr = outstandingAddrs.find(req->dest); - assert(removeAddr != outstandingAddrs.end()); - outstandingAddrs.erase(removeAddr); - numCopiesStat++; - break; - - default: - panic("invalid command"); - } - - if (blockAddr(req->paddr) == traceBlockAddr) { - cerr << name() << ": completed " - << (req->cmd.isWrite() ? "write" : "read") - << " access of " - << dec << req->size << " bytes at address 0x" - << hex << req->paddr - << " (0x" << hex << blockAddr(req->paddr) << ")" - << ", value = 0x"; - printData(cerr, req->data, req->size); - cerr << " @ cycle " << dec << curTick; - - cerr << endl; - } - - noResponseCycles = 0; - delete [] data; -} - - -void -MemTest::regStats() -{ - using namespace Stats; - - - numReadsStat - .name(name() + ".num_reads") - .desc("number of read accesses completed") - ; - - numWritesStat - .name(name() + ".num_writes") - .desc("number of write accesses completed") - ; - - numCopiesStat - .name(name() + ".num_copies") - .desc("number of copy accesses completed") - ; -} - -void -MemTest::tick() -{ - if (!tickEvent.scheduled()) - tickEvent.schedule(curTick + cycles(1)); - - if (++noResponseCycles >= 500000) { - cerr << name() << ": deadlocked at cycle " << curTick << endl; - fatal(""); - } - - if (cacheInterface->isBlocked()) { - return; - } - - //make new request - unsigned cmd = random() % 100; - unsigned offset = random() % size; - unsigned base = random() % 2; - uint64_t data = random(); - unsigned access_size = random() % 4; - unsigned cacheable = random() % 100; - - //If we aren't doing copies, use id as offset, and do a false sharing - //mem tester - if (percentCopies == 0) { - //We can eliminate the lower bits of the offset, and then use the id - //to offset within the blks - offset &= ~63; //Not the low order bits - offset += id; - access_size = 0; - } - - MemReqPtr req = new MemReq(); - - if (cacheable < percentUncacheable) { - req->flags |= UNCACHEABLE; - req->paddr = uncacheAddr + offset; - } else { - req->paddr = ((base) ? baseAddr1 : baseAddr2) + offset; - } - // bool probe = (random() % 2 == 1) && !req->isUncacheable(); - bool probe = false; - - req->size = 1 << access_size; - req->data = new uint8_t[req->size]; - req->paddr &= ~(req->size - 1); - req->time = curTick; - req->xc = cpuXC->getProxy(); - - if (cmd < percentReads) { - // read - - //For now we only allow one outstanding request per addreess per tester - //This means we assume CPU does write forwarding to reads that alias something - //in the cpu store buffer. - if (outstandingAddrs.find(req->paddr) != outstandingAddrs.end()) return; - else outstandingAddrs.insert(req->paddr); - - req->cmd = Read; - uint8_t *result = new uint8_t[8]; - checkMem->access(Read, req->paddr, result, req->size); - if (blockAddr(req->paddr) == traceBlockAddr) { - cerr << name() - << ": initiating read " - << ((probe) ? "probe of " : "access of ") - << dec << req->size << " bytes from addr 0x" - << hex << req->paddr - << " (0x" << hex << blockAddr(req->paddr) << ")" - << " at cycle " - << dec << curTick << endl; - } - if (probe) { - cacheInterface->probeAndUpdate(req); - completeRequest(req, result); - } else { - req->completionEvent = new MemCompleteEvent(req, result, this); - cacheInterface->access(req); - } - } else if (cmd < (100 - percentCopies)){ - // write - - //For now we only allow one outstanding request per addreess per tester - //This means we assume CPU does write forwarding to reads that alias something - //in the cpu store buffer. - if (outstandingAddrs.find(req->paddr) != outstandingAddrs.end()) return; - else outstandingAddrs.insert(req->paddr); - - req->cmd = Write; - memcpy(req->data, &data, req->size); - checkMem->access(Write, req->paddr, req->data, req->size); - if (blockAddr(req->paddr) == traceBlockAddr) { - cerr << name() << ": initiating write " - << ((probe)?"probe of ":"access of ") - << dec << req->size << " bytes (value = 0x"; - printData(cerr, req->data, req->size); - cerr << ") to addr 0x" - << hex << req->paddr - << " (0x" << hex << blockAddr(req->paddr) << ")" - << " at cycle " - << dec << curTick << endl; - } - if (probe) { - cacheInterface->probeAndUpdate(req); - completeRequest(req, NULL); - } else { - req->completionEvent = new MemCompleteEvent(req, NULL, this); - cacheInterface->access(req); - } - } else { - // copy - unsigned source_align = random() % 100; - unsigned dest_align = random() % 100; - unsigned offset2 = random() % size; - - Addr source = ((base) ? baseAddr1 : baseAddr2) + offset; - Addr dest = ((base) ? baseAddr2 : baseAddr1) + offset2; - if (outstandingAddrs.find(source) != outstandingAddrs.end()) return; - else outstandingAddrs.insert(source); - if (outstandingAddrs.find(dest) != outstandingAddrs.end()) return; - else outstandingAddrs.insert(dest); - - if (source_align >= percentSourceUnaligned) { - source = blockAddr(source); - } - if (dest_align >= percentDestUnaligned) { - dest = blockAddr(dest); - } - req->cmd = Copy; - req->flags &= ~UNCACHEABLE; - req->paddr = source; - req->dest = dest; - delete [] req->data; - req->data = new uint8_t[blockSize]; - req->size = blockSize; - if (source == traceBlockAddr || dest == traceBlockAddr) { - cerr << name() - << ": initiating copy of " - << dec << req->size << " bytes from addr 0x" - << hex << source - << " (0x" << hex << blockAddr(source) << ")" - << " to addr 0x" - << hex << dest - << " (0x" << hex << blockAddr(dest) << ")" - << " at cycle " - << dec << curTick << endl; - } - cacheInterface->access(req); - uint8_t result[blockSize]; - checkMem->access(Read, source, &result, blockSize); - checkMem->access(Write, dest, &result, blockSize); - } -} - - -void -MemCompleteEvent::process() -{ - tester->completeRequest(req, data); - delete this; -} - - -const char * -MemCompleteEvent::description() -{ - return "memory access completion"; -} - - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(MemTest) - - SimObjectParam<BaseCache *> cache; - SimObjectParam<FunctionalMemory *> main_mem; - SimObjectParam<FunctionalMemory *> check_mem; - Param<unsigned> memory_size; - Param<unsigned> percent_reads; - Param<unsigned> percent_copies; - Param<unsigned> percent_uncacheable; - Param<unsigned> progress_interval; - Param<unsigned> percent_source_unaligned; - Param<unsigned> percent_dest_unaligned; - Param<Addr> trace_addr; - Param<Counter> max_loads; - -END_DECLARE_SIM_OBJECT_PARAMS(MemTest) - - -BEGIN_INIT_SIM_OBJECT_PARAMS(MemTest) - - INIT_PARAM(cache, "L1 cache"), - INIT_PARAM(main_mem, "hierarchical memory"), - INIT_PARAM(check_mem, "check memory"), - INIT_PARAM(memory_size, "memory size"), - INIT_PARAM(percent_reads, "target read percentage"), - INIT_PARAM(percent_copies, "target copy percentage"), - INIT_PARAM(percent_uncacheable, "target uncacheable percentage"), - INIT_PARAM(progress_interval, "progress report interval (in accesses)"), - INIT_PARAM(percent_source_unaligned, - "percent of copy source address that are unaligned"), - INIT_PARAM(percent_dest_unaligned, - "percent of copy dest address that are unaligned"), - INIT_PARAM(trace_addr, "address to trace"), - INIT_PARAM(max_loads, "terminate when we have reached this load count") - -END_INIT_SIM_OBJECT_PARAMS(MemTest) - - -CREATE_SIM_OBJECT(MemTest) -{ - return new MemTest(getInstanceName(), cache->getInterface(), main_mem, - check_mem, memory_size, percent_reads, percent_copies, - percent_uncacheable, progress_interval, - percent_source_unaligned, percent_dest_unaligned, - trace_addr, max_loads); -} - -REGISTER_SIM_OBJECT("MemTest", MemTest) diff --git a/cpu/o3/alpha_cpu.hh b/cpu/o3/alpha_cpu.hh deleted file mode 100644 index 5c89e3462..000000000 --- a/cpu/o3/alpha_cpu.hh +++ /dev/null @@ -1,430 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_ALPHA_FULL_CPU_HH__ -#define __CPU_O3_ALPHA_FULL_CPU_HH__ - -#include "arch/isa_traits.hh" -#include "cpu/exec_context.hh" -#include "cpu/o3/cpu.hh" -#include "sim/byteswap.hh" - -class EndQuiesceEvent; -namespace Kernel { - class Statistics; -}; - -template <class Impl> -class AlphaFullCPU : public FullO3CPU<Impl> -{ - protected: - typedef TheISA::IntReg IntReg; - typedef TheISA::MiscReg MiscReg; - typedef TheISA::RegFile RegFile; - typedef TheISA::MiscRegFile MiscRegFile; - - public: - typedef O3ThreadState<Impl> ImplState; - typedef O3ThreadState<Impl> Thread; - typedef typename Impl::Params Params; - - /** Constructs an AlphaFullCPU with the given parameters. */ - AlphaFullCPU(Params *params); - - class AlphaXC : public ExecContext - { - public: - AlphaFullCPU<Impl> *cpu; - - O3ThreadState<Impl> *thread; - - virtual BaseCPU *getCpuPtr() { return cpu; } - - virtual void setCpuId(int id) { cpu->cpu_id = id; } - - virtual int readCpuId() { return cpu->cpu_id; } - - virtual FunctionalMemory *getMemPtr() { return thread->mem; } - -#if FULL_SYSTEM - virtual System *getSystemPtr() { return cpu->system; } - - virtual PhysicalMemory *getPhysMemPtr() { return cpu->physmem; } - - virtual AlphaITB *getITBPtr() { return cpu->itb; } - - virtual AlphaDTB * getDTBPtr() { return cpu->dtb; } - - virtual Kernel::Statistics *getKernelStats() - { return thread->kernelStats; } -#else - virtual Process *getProcessPtr() { return thread->process; } -#endif - - virtual Status status() const { return thread->status(); } - - virtual void setStatus(Status new_status) - { thread->setStatus(new_status); } - - /// Set the status to Active. Optional delay indicates number of - /// cycles to wait before beginning execution. - virtual void activate(int delay = 1); - - /// Set the status to Suspended. - virtual void suspend(); - - /// Set the status to Unallocated. - virtual void deallocate(); - - /// Set the status to Halted. - virtual void halt(); - -#if FULL_SYSTEM - virtual void dumpFuncProfile(); -#endif - - virtual void takeOverFrom(ExecContext *old_context); - - virtual void regStats(const std::string &name); - - virtual void serialize(std::ostream &os); - virtual void unserialize(Checkpoint *cp, const std::string §ion); - -#if FULL_SYSTEM - virtual EndQuiesceEvent *getQuiesceEvent(); - - virtual Tick readLastActivate(); - virtual Tick readLastSuspend(); - - virtual void profileClear(); - virtual void profileSample(); -#endif - - virtual int getThreadNum() { return thread->tid; } - - virtual TheISA::MachInst getInst(); - - virtual void copyArchRegs(ExecContext *xc); - - virtual void clearArchRegs(); - - virtual uint64_t readIntReg(int reg_idx); - - virtual float readFloatRegSingle(int reg_idx); - - virtual double readFloatRegDouble(int reg_idx); - - virtual uint64_t readFloatRegInt(int reg_idx); - - virtual void setIntReg(int reg_idx, uint64_t val); - - virtual void setFloatRegSingle(int reg_idx, float val); - - virtual void setFloatRegDouble(int reg_idx, double val); - - virtual void setFloatRegInt(int reg_idx, uint64_t val); - - virtual uint64_t readPC() - { return cpu->readPC(thread->tid); } - - virtual void setPC(uint64_t val); - - virtual uint64_t readNextPC() - { return cpu->readNextPC(thread->tid); } - - virtual void setNextPC(uint64_t val); - - virtual MiscReg readMiscReg(int misc_reg) - { return cpu->readMiscReg(misc_reg, thread->tid); } - - virtual MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault) - { return cpu->readMiscRegWithEffect(misc_reg, fault, thread->tid); } - - virtual Fault setMiscReg(int misc_reg, const MiscReg &val); - - virtual Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val); - - // @todo: Figure out where these store cond failures should go. - virtual unsigned readStCondFailures() - { return thread->storeCondFailures; } - - virtual void setStCondFailures(unsigned sc_failures) - { thread->storeCondFailures = sc_failures; } - -#if FULL_SYSTEM - virtual bool inPalMode() - { return TheISA::PcPAL(cpu->readPC(thread->tid)); } -#endif - - // Only really makes sense for old CPU model. Lots of code - // outside the CPU still checks this function, so it will - // always return false to keep everything working. - virtual bool misspeculating() { return false; } - -#if !FULL_SYSTEM - virtual IntReg getSyscallArg(int i); - - virtual void setSyscallArg(int i, IntReg val); - - virtual void setSyscallReturn(SyscallReturn return_value); - - virtual void syscall() { return cpu->syscall(thread->tid); } - - virtual Counter readFuncExeInst() { return thread->funcExeInst; } -#endif - }; - -#if FULL_SYSTEM - /** ITB pointer. */ - AlphaITB *itb; - /** DTB pointer. */ - AlphaDTB *dtb; -#endif - - /** Registers statistics. */ - void regStats(); - -#if FULL_SYSTEM - /** Translates instruction requestion. */ - Fault translateInstReq(MemReqPtr &req) - { - return itb->translate(req); - } - - /** Translates data read request. */ - Fault translateDataReadReq(MemReqPtr &req) - { - return dtb->translate(req, false); - } - - /** Translates data write request. */ - Fault translateDataWriteReq(MemReqPtr &req) - { - return dtb->translate(req, true); - } - -#else - Fault dummyTranslation(MemReqPtr &req) - { -#if 0 - assert((req->vaddr >> 48 & 0xffff) == 0); -#endif - - // put the asid in the upper 16 bits of the paddr - req->paddr = req->vaddr & ~((Addr)0xffff << sizeof(Addr) * 8 - 16); - req->paddr = req->paddr | (Addr)req->asid << sizeof(Addr) * 8 - 16; - return NoFault; - } - - /** Translates instruction requestion in syscall emulation mode. */ - Fault translateInstReq(MemReqPtr &req) - { - return dummyTranslation(req); - } - - /** Translates data read request in syscall emulation mode. */ - Fault translateDataReadReq(MemReqPtr &req) - { - return dummyTranslation(req); - } - - /** Translates data write request in syscall emulation mode. */ - Fault translateDataWriteReq(MemReqPtr &req) - { - return dummyTranslation(req); - } - -#endif - MiscReg readMiscReg(int misc_reg, unsigned tid); - - MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault, unsigned tid); - - Fault setMiscReg(int misc_reg, const MiscReg &val, unsigned tid); - - Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val, unsigned tid); - - void squashFromXC(unsigned tid); - -#if FULL_SYSTEM - void post_interrupt(int int_num, int index); - - int readIntrFlag(); - /** Sets the interrupt flags. */ - void setIntrFlag(int val); - /** HW return from error interrupt. */ - Fault hwrei(unsigned tid); - /** Returns if a specific PC is a PAL mode PC. */ - bool inPalMode(uint64_t PC) - { return AlphaISA::PcPAL(PC); } - - /** Traps to handle given fault. */ - void trap(Fault fault, unsigned tid); - bool simPalCheck(int palFunc, unsigned tid); - - /** Processes any interrupts. */ - void processInterrupts(); - - /** Halts the CPU. */ - void halt() { panic("Halt not implemented!\n"); } -#endif - - -#if !FULL_SYSTEM - /** Executes a syscall. - * @todo: Determine if this needs to be virtual. - */ - void syscall(int thread_num); - /** Gets a syscall argument. */ - IntReg getSyscallArg(int i, int tid); - - /** Used to shift args for indirect syscall. */ - void setSyscallArg(int i, IntReg val, int tid); - - /** Sets the return value of a syscall. */ - void setSyscallReturn(SyscallReturn return_value, int tid); -#endif - - /** Read from memory function. */ - template <class T> - Fault read(MemReqPtr &req, T &data) - { -#if 0 -#if FULL_SYSTEM && defined(TARGET_ALPHA) - if (req->flags & LOCKED) { - req->xc->setMiscReg(TheISA::Lock_Addr_DepTag, req->paddr); - req->xc->setMiscReg(TheISA::Lock_Flag_DepTag, true); - } -#endif -#endif - Fault error; - -#if FULL_SYSTEM - // @todo: Fix this LL/SC hack. - if (req->flags & LOCKED) { - lockAddr = req->paddr; - lockFlag = true; - } -#endif - - error = this->mem->read(req, data); - data = gtoh(data); - return error; - } - - /** CPU read function, forwards read to LSQ. */ - template <class T> - Fault read(MemReqPtr &req, T &data, int load_idx) - { - return this->iew.ldstQueue.read(req, data, load_idx); - } - - /** Write to memory function. */ - template <class T> - Fault write(MemReqPtr &req, T &data) - { -#if 0 -#if FULL_SYSTEM && defined(TARGET_ALPHA) - ExecContext *xc; - - // If this is a store conditional, act appropriately - if (req->flags & LOCKED) { - xc = req->xc; - - if (req->flags & UNCACHEABLE) { - // Don't update result register (see stq_c in isa_desc) - req->result = 2; - xc->setStCondFailures(0);//Needed? [RGD] - } else { - bool lock_flag = xc->readMiscReg(TheISA::Lock_Flag_DepTag); - Addr lock_addr = xc->readMiscReg(TheISA::Lock_Addr_DepTag); - req->result = lock_flag; - if (!lock_flag || - ((lock_addr & ~0xf) != (req->paddr & ~0xf))) { - xc->setMiscReg(TheISA::Lock_Flag_DepTag, false); - xc->setStCondFailures(xc->readStCondFailures() + 1); - if (((xc->readStCondFailures()) % 100000) == 0) { - std::cerr << "Warning: " - << xc->readStCondFailures() - << " consecutive store conditional failures " - << "on cpu " << req->xc->readCpuId() - << std::endl; - } - return NoFault; - } - else xc->setStCondFailures(0); - } - } - - // Need to clear any locked flags on other proccessors for - // this address. Only do this for succsful Store Conditionals - // and all other stores (WH64?). Unsuccessful Store - // Conditionals would have returned above, and wouldn't fall - // through. - for (int i = 0; i < this->system->execContexts.size(); i++){ - xc = this->system->execContexts[i]; - if ((xc->readMiscReg(TheISA::Lock_Addr_DepTag) & ~0xf) == - (req->paddr & ~0xf)) { - xc->setMiscReg(TheISA::Lock_Flag_DepTag, false); - } - } - -#endif -#endif - -#if FULL_SYSTEM - // @todo: Fix this LL/SC hack. - if (req->flags & LOCKED) { - if (req->flags & UNCACHEABLE) { - req->result = 2; - } else { - if (this->lockFlag) { - req->result = 1; - } else { - req->result = 0; - return NoFault; - } - } - } -#endif - - return this->mem->write(req, (T)htog(data)); - } - - /** CPU write function, forwards write to LSQ. */ - template <class T> - Fault write(MemReqPtr &req, T &data, int store_idx) - { - return this->iew.ldstQueue.write(req, data, store_idx); - } - - Addr lockAddr; - - bool lockFlag; -}; - -#endif // __CPU_O3_ALPHA_FULL_CPU_HH__ diff --git a/cpu/o3/alpha_cpu_impl.hh b/cpu/o3/alpha_cpu_impl.hh deleted file mode 100644 index 91cd3d9e6..000000000 --- a/cpu/o3/alpha_cpu_impl.hh +++ /dev/null @@ -1,776 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "arch/alpha/faults.hh" -#include "base/cprintf.hh" -#include "base/statistics.hh" -#include "base/timebuf.hh" -#include "cpu/checker/exec_context.hh" -#include "mem/mem_interface.hh" -#include "sim/sim_events.hh" -#include "sim/stats.hh" - -#include "cpu/o3/alpha_cpu.hh" -#include "cpu/o3/alpha_params.hh" -#include "cpu/o3/comm.hh" -#include "cpu/o3/thread_state.hh" - -#if FULL_SYSTEM -#include "arch/alpha/osfpal.hh" -#include "arch/isa_traits.hh" -#include "cpu/quiesce_event.hh" -#include "kern/kernel_stats.hh" -#endif - -using namespace TheISA; - -template <class Impl> -AlphaFullCPU<Impl>::AlphaFullCPU(Params *params) -#if FULL_SYSTEM - : FullO3CPU<Impl>(params), itb(params->itb), dtb(params->dtb) -#else - : FullO3CPU<Impl>(params) -#endif -{ - DPRINTF(FullCPU, "AlphaFullCPU: Creating AlphaFullCPU object.\n"); - - this->thread.resize(this->numThreads); - - for (int i = 0; i < this->numThreads; ++i) { -#if FULL_SYSTEM - assert(this->numThreads == 1); - this->thread[i] = new Thread(this, 0, params->mem); - this->thread[i]->setStatus(ExecContext::Suspended); -#else - if (i < params->workload.size()) { - DPRINTF(FullCPU, "FullCPU: Workload[%i]'s starting PC is %#x, " - "process is %#x", - i, params->workload[i]->prog_entry, this->thread[i]); - this->thread[i] = new Thread(this, i, params->workload[i], i); - assert(params->workload[i]->getMemory() != NULL); - - this->thread[i]->setStatus(ExecContext::Suspended); - //usedTids[i] = true; - //threadMap[i] = i; - } else { - //Allocate Empty execution context so M5 can use later - //when scheduling threads to CPU - Process* dummy_proc = NULL; - - this->thread[i] = new Thread(this, i, dummy_proc, i); - //usedTids[i] = false; - } -#endif // !FULL_SYSTEM - - this->thread[i]->numInst = 0; - - ExecContext *xc_proxy; - - AlphaXC *alpha_xc_proxy = new AlphaXC; - - if (params->checker) { - xc_proxy = new CheckerExecContext<AlphaXC>(alpha_xc_proxy, this->checker); - } else { - xc_proxy = alpha_xc_proxy; - } - - alpha_xc_proxy->cpu = this; - alpha_xc_proxy->thread = this->thread[i]; - -#if FULL_SYSTEM - this->thread[i]->quiesceEvent = - new EndQuiesceEvent(xc_proxy); - this->thread[i]->lastActivate = 0; - this->thread[i]->lastSuspend = 0; -#endif - this->thread[i]->xcProxy = xc_proxy; - - this->execContexts.push_back(xc_proxy); - } - - - for (int i=0; i < this->numThreads; i++) { - this->thread[i]->funcExeInst = 0; - } - - // Sets CPU pointers. These must be set at this level because the CPU - // pointers are defined to be the highest level of CPU class. - this->fetch.setCPU(this); - this->decode.setCPU(this); - this->rename.setCPU(this); - this->iew.setCPU(this); - this->commit.setCPU(this); - - this->rob.setCPU(this); - this->regFile.setCPU(this); - - lockAddr = 0; - lockFlag = false; -} - -template <class Impl> -void -AlphaFullCPU<Impl>::regStats() -{ - // Register stats for everything that has stats. - this->fullCPURegStats(); - this->fetch.regStats(); - this->decode.regStats(); - this->rename.regStats(); - this->iew.regStats(); - this->commit.regStats(); -} - -#if FULL_SYSTEM -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::dumpFuncProfile() -{ - // Currently not supported -} -#endif - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::takeOverFrom(ExecContext *old_context) -{ - // some things should already be set up - assert(getMemPtr() == old_context->getMemPtr()); -#if FULL_SYSTEM - assert(getSystemPtr() == old_context->getSystemPtr()); -#else - assert(getProcessPtr() == old_context->getProcessPtr()); -#endif - - // copy over functional state - setStatus(old_context->status()); - copyArchRegs(old_context); - setCpuId(old_context->readCpuId()); -#if !FULL_SYSTEM - thread->funcExeInst = old_context->readFuncExeInst(); -#else - EndQuiesceEvent *other_quiesce = old_context->getQuiesceEvent(); - if (other_quiesce) { - // Point the quiesce event's XC at this XC so that it wakes up - // the proper CPU. - other_quiesce->xc = this; - } - if (thread->quiesceEvent) { - thread->quiesceEvent->xc = this; - } - - // Transfer kernel stats from one CPU to the other. - thread->kernelStats = old_context->getKernelStats(); -// storeCondFailures = 0; - cpu->lockFlag = false; -#endif - - old_context->setStatus(ExecContext::Unallocated); - - thread->inSyscall = false; - thread->trapPending = false; -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::activate(int delay) -{ - DPRINTF(FullCPU, "Calling activate on AlphaXC\n"); - - if (thread->status() == ExecContext::Active) - return; - -#if FULL_SYSTEM - thread->lastActivate = curTick; -#endif - - if (thread->status() == ExecContext::Unallocated) { - cpu->activateWhenReady(thread->tid); - return; - } - - thread->setStatus(ExecContext::Active); - - // status() == Suspended - cpu->activateContext(thread->tid, delay); -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::suspend() -{ - DPRINTF(FullCPU, "Calling suspend on AlphaXC\n"); - - if (thread->status() == ExecContext::Suspended) - return; - -#if FULL_SYSTEM - thread->lastActivate = curTick; - thread->lastSuspend = curTick; -#endif -/* -#if FULL_SYSTEM - // Don't change the status from active if there are pending interrupts - if (cpu->check_interrupts()) { - assert(status() == ExecContext::Active); - return; - } -#endif -*/ - thread->setStatus(ExecContext::Suspended); - cpu->suspendContext(thread->tid); -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::deallocate() -{ - DPRINTF(FullCPU, "Calling deallocate on AlphaXC\n"); - - if (thread->status() == ExecContext::Unallocated) - return; - - thread->setStatus(ExecContext::Unallocated); - cpu->deallocateContext(thread->tid); -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::halt() -{ - DPRINTF(FullCPU, "Calling halt on AlphaXC\n"); - - if (thread->status() == ExecContext::Halted) - return; - - thread->setStatus(ExecContext::Halted); - cpu->haltContext(thread->tid); -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::regStats(const std::string &name) -{ -#if FULL_SYSTEM - thread->kernelStats = new Kernel::Statistics(cpu->system); - thread->kernelStats->regStats(name + ".kern"); -#endif -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::serialize(std::ostream &os) -{ -#if FULL_SYSTEM - if (thread->kernelStats) - thread->kernelStats->serialize(os); -#endif - -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::unserialize(Checkpoint *cp, const std::string §ion) -{ -#if FULL_SYSTEM - if (thread->kernelStats) - thread->kernelStats->unserialize(cp, section); -#endif - -} - -#if FULL_SYSTEM -template <class Impl> -EndQuiesceEvent * -AlphaFullCPU<Impl>::AlphaXC::getQuiesceEvent() -{ - return thread->quiesceEvent; -} - -template <class Impl> -Tick -AlphaFullCPU<Impl>::AlphaXC::readLastActivate() -{ - return thread->lastActivate; -} - -template <class Impl> -Tick -AlphaFullCPU<Impl>::AlphaXC::readLastSuspend() -{ - return thread->lastSuspend; -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::profileClear() -{} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::profileSample() -{} -#endif - -template <class Impl> -TheISA::MachInst -AlphaFullCPU<Impl>::AlphaXC:: getInst() -{ - return thread->inst; -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::copyArchRegs(ExecContext *xc) -{ - // This function will mess things up unless the ROB is empty and - // there are no instructions in the pipeline. - unsigned tid = thread->tid; - PhysRegIndex renamed_reg; - - // First loop through the integer registers. - for (int i = 0; i < AlphaISA::NumIntRegs; ++i) { - renamed_reg = cpu->renameMap[tid].lookup(i); - - DPRINTF(FullCPU, "FullCPU: Copying over register %i, had data %lli, " - "now has data %lli.\n", - renamed_reg, cpu->readIntReg(renamed_reg), - xc->readIntReg(i)); - - cpu->setIntReg(renamed_reg, xc->readIntReg(i)); - } - - // Then loop through the floating point registers. - for (int i = 0; i < AlphaISA::NumFloatRegs; ++i) { - renamed_reg = cpu->renameMap[tid].lookup(i + AlphaISA::FP_Base_DepTag); - cpu->setFloatRegDouble(renamed_reg, - xc->readFloatRegDouble(i)); - cpu->setFloatRegInt(renamed_reg, - xc->readFloatRegInt(i)); - } - - // Copy the misc regs. - cpu->regFile.miscRegs[tid].copyMiscRegs(xc); - - // Then finally set the PC and the next PC. - cpu->setPC(xc->readPC(), tid); - cpu->setNextPC(xc->readNextPC(), tid); -#if !FULL_SYSTEM - this->thread->funcExeInst = xc->readFuncExeInst(); -#endif -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::clearArchRegs() -{} - -template <class Impl> -uint64_t -AlphaFullCPU<Impl>::AlphaXC::readIntReg(int reg_idx) -{ - DPRINTF(Fault, "Reading int register through the XC!\n"); - return cpu->readArchIntReg(reg_idx, thread->tid); -} - -template <class Impl> -float -AlphaFullCPU<Impl>::AlphaXC::readFloatRegSingle(int reg_idx) -{ - DPRINTF(Fault, "Reading float register through the XC!\n"); - return cpu->readArchFloatRegSingle(reg_idx, thread->tid); -} - -template <class Impl> -double -AlphaFullCPU<Impl>::AlphaXC::readFloatRegDouble(int reg_idx) -{ - DPRINTF(Fault, "Reading float register through the XC!\n"); - return cpu->readArchFloatRegDouble(reg_idx, thread->tid); -} - -template <class Impl> -uint64_t -AlphaFullCPU<Impl>::AlphaXC::readFloatRegInt(int reg_idx) -{ - DPRINTF(Fault, "Reading floatint register through the XC!\n"); - return cpu->readArchFloatRegInt(reg_idx, thread->tid); -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::setIntReg(int reg_idx, uint64_t val) -{ - DPRINTF(Fault, "Setting int register through the XC!\n"); - cpu->setArchIntReg(reg_idx, val, thread->tid); - - if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromXC(thread->tid); - } -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::setFloatRegSingle(int reg_idx, float val) -{ - DPRINTF(Fault, "Setting float register through the XC!\n"); - cpu->setArchFloatRegSingle(reg_idx, val, thread->tid); - - if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromXC(thread->tid); - } -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::setFloatRegDouble(int reg_idx, double val) -{ - DPRINTF(Fault, "Setting float register through the XC!\n"); - cpu->setArchFloatRegDouble(reg_idx, val, thread->tid); - - if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromXC(thread->tid); - } -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::setFloatRegInt(int reg_idx, uint64_t val) -{ - DPRINTF(Fault, "Setting floatint register through the XC!\n"); - cpu->setArchFloatRegInt(reg_idx, val, thread->tid); - - if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromXC(thread->tid); - } -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::setPC(uint64_t val) -{ - cpu->setPC(val, thread->tid); - - if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromXC(thread->tid); - } -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::setNextPC(uint64_t val) -{ - cpu->setNextPC(val, thread->tid); - - if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromXC(thread->tid); - } -} - -template <class Impl> -Fault -AlphaFullCPU<Impl>::AlphaXC::setMiscReg(int misc_reg, const MiscReg &val) -{ - DPRINTF(Fault, "Setting misc register through the XC!\n"); - - Fault ret_fault = cpu->setMiscReg(misc_reg, val, thread->tid); - - if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromXC(thread->tid); - } - - return ret_fault; -} - -template <class Impl> -Fault -AlphaFullCPU<Impl>::AlphaXC::setMiscRegWithEffect(int misc_reg, const MiscReg &val) -{ - DPRINTF(Fault, "Setting misc register through the XC!\n"); - - Fault ret_fault = cpu->setMiscRegWithEffect(misc_reg, val, thread->tid); - - if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromXC(thread->tid); - } - - return ret_fault; -} - -#if !FULL_SYSTEM - -template <class Impl> -TheISA::IntReg -AlphaFullCPU<Impl>::AlphaXC::getSyscallArg(int i) -{ - return cpu->getSyscallArg(i, thread->tid); -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::setSyscallArg(int i, IntReg val) -{ - cpu->setSyscallArg(i, val, thread->tid); -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::setSyscallReturn(SyscallReturn return_value) -{ - cpu->setSyscallReturn(return_value, thread->tid); -} - -#endif // FULL_SYSTEM - -template <class Impl> -MiscReg -AlphaFullCPU<Impl>::readMiscReg(int misc_reg, unsigned tid) -{ - return this->regFile.readMiscReg(misc_reg, tid); -} - -template <class Impl> -MiscReg -AlphaFullCPU<Impl>::readMiscRegWithEffect(int misc_reg, Fault &fault, - unsigned tid) -{ - return this->regFile.readMiscRegWithEffect(misc_reg, fault, tid); -} - -template <class Impl> -Fault -AlphaFullCPU<Impl>::setMiscReg(int misc_reg, const MiscReg &val, unsigned tid) -{ - return this->regFile.setMiscReg(misc_reg, val, tid); -} - -template <class Impl> -Fault -AlphaFullCPU<Impl>::setMiscRegWithEffect(int misc_reg, const MiscReg &val, - unsigned tid) -{ - return this->regFile.setMiscRegWithEffect(misc_reg, val, tid); -} - -template <class Impl> -void -AlphaFullCPU<Impl>::squashFromXC(unsigned tid) -{ - this->thread[tid]->inSyscall = true; - this->commit.generateXCEvent(tid); -} - -#if FULL_SYSTEM - -template <class Impl> -void -AlphaFullCPU<Impl>::post_interrupt(int int_num, int index) -{ - BaseCPU::post_interrupt(int_num, index); - - if (this->thread[0]->status() == ExecContext::Suspended) { - DPRINTF(IPI,"Suspended Processor awoke\n"); -// xcProxies[0]->activate(); - this->execContexts[0]->activate(); - } -} - -template <class Impl> -int -AlphaFullCPU<Impl>::readIntrFlag() -{ - return this->regFile.readIntrFlag(); -} - -template <class Impl> -void -AlphaFullCPU<Impl>::setIntrFlag(int val) -{ - this->regFile.setIntrFlag(val); -} - -template <class Impl> -Fault -AlphaFullCPU<Impl>::hwrei(unsigned tid) -{ - // Need to clear the lock flag upon returning from an interrupt. - this->lockFlag = false; - - this->thread[tid]->kernelStats->hwrei(); - - this->checkInterrupts = true; - - // FIXME: XXX check for interrupts? XXX - return NoFault; -} - -template <class Impl> -bool -AlphaFullCPU<Impl>::simPalCheck(int palFunc, unsigned tid) -{ - if (this->thread[tid]->kernelStats) - this->thread[tid]->kernelStats->callpal(palFunc, - this->execContexts[tid]); - - switch (palFunc) { - case PAL::halt: - halt(); - if (--System::numSystemsRunning == 0) - new SimExitEvent("all cpus halted"); - break; - - case PAL::bpt: - case PAL::bugchk: - if (this->system->breakpoint()) - return false; - break; - } - - return true; -} - -template <class Impl> -void -AlphaFullCPU<Impl>::trap(Fault fault, unsigned tid) -{ - fault->invoke(this->execContexts[tid]); -} - -template <class Impl> -void -AlphaFullCPU<Impl>::processInterrupts() -{ - // Check for interrupts here. For now can copy the code that - // exists within isa_fullsys_traits.hh. Also assume that thread 0 - // is the one that handles the interrupts. - // @todo: Possibly consolidate the interrupt checking code. - // @todo: Allow other threads to handle interrupts. - - // Check if there are any outstanding interrupts - //Handle the interrupts - int ipl = 0; - int summary = 0; - - this->checkInterrupts = false; - - if (this->readMiscReg(IPR_ASTRR, 0)) - panic("asynchronous traps not implemented\n"); - - if (this->readMiscReg(IPR_SIRR, 0)) { - for (int i = INTLEVEL_SOFTWARE_MIN; - i < INTLEVEL_SOFTWARE_MAX; i++) { - if (this->readMiscReg(IPR_SIRR, 0) & (ULL(1) << i)) { - // See table 4-19 of the 21164 hardware reference - ipl = (i - INTLEVEL_SOFTWARE_MIN) + 1; - summary |= (ULL(1) << i); - } - } - } - - uint64_t interrupts = this->intr_status(); - - if (interrupts) { - for (int i = INTLEVEL_EXTERNAL_MIN; - i < INTLEVEL_EXTERNAL_MAX; i++) { - if (interrupts & (ULL(1) << i)) { - // See table 4-19 of the 21164 hardware reference - ipl = i; - summary |= (ULL(1) << i); - } - } - } - - if (ipl && ipl > this->readMiscReg(IPR_IPLR, 0)) { - this->setMiscReg(IPR_ISR, summary, 0); - this->setMiscReg(IPR_INTID, ipl, 0); - if (this->checker) { - this->checker->cpuXCBase()->setMiscReg(IPR_ISR, summary); - this->checker->cpuXCBase()->setMiscReg(IPR_INTID, ipl); - } - this->trap(Fault(new InterruptFault), 0); - DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n", - this->readMiscReg(IPR_IPLR, 0), ipl, summary); - } -} - -#endif // FULL_SYSTEM - -#if !FULL_SYSTEM - -template <class Impl> -void -AlphaFullCPU<Impl>::syscall(int tid) -{ - DPRINTF(FullCPU, "AlphaFullCPU: [tid:%i] Executing syscall().\n\n", tid); - - DPRINTF(Activity,"Activity: syscall() called.\n"); - - // Temporarily increase this by one to account for the syscall - // instruction. - ++(this->thread[tid]->funcExeInst); - - // Execute the actual syscall. - this->thread[tid]->syscall(); - - // Decrease funcExeInst by one as the normal commit will handle - // incrementing it. - --(this->thread[tid]->funcExeInst); -} - -template <class Impl> -TheISA::IntReg -AlphaFullCPU<Impl>::getSyscallArg(int i, int tid) -{ - return this->readArchIntReg(AlphaISA::ArgumentReg0 + i, tid); -} - -template <class Impl> -void -AlphaFullCPU<Impl>::setSyscallArg(int i, IntReg val, int tid) -{ - this->setArchIntReg(AlphaISA::ArgumentReg0 + i, val, tid); -} - -template <class Impl> -void -AlphaFullCPU<Impl>::setSyscallReturn(SyscallReturn return_value, int tid) -{ - // check for error condition. Alpha syscall convention is to - // indicate success/failure in reg a3 (r19) and put the - // return value itself in the standard return value reg (v0). - if (return_value.successful()) { - // no error - this->setArchIntReg(SyscallSuccessReg, 0, tid); - this->setArchIntReg(ReturnValueReg, return_value.value(), tid); - } else { - // got an error, return details - this->setArchIntReg(SyscallSuccessReg, (IntReg) -1, tid); - this->setArchIntReg(ReturnValueReg, -return_value.value(), tid); - } -} -#endif diff --git a/cpu/o3/alpha_dyn_inst.hh b/cpu/o3/alpha_dyn_inst.hh deleted file mode 100644 index 1c5b738aa..000000000 --- a/cpu/o3/alpha_dyn_inst.hh +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_ALPHA_DYN_INST_HH__ -#define __CPU_O3_ALPHA_DYN_INST_HH__ - -#include "cpu/base_dyn_inst.hh" -#include "cpu/inst_seq.hh" -#include "cpu/o3/alpha_cpu.hh" -#include "cpu/o3/alpha_impl.hh" - -/** - * Mostly implementation & ISA specific AlphaDynInst. As with most - * other classes in the new CPU model, it is templated on the Impl to - * allow for passing in of all types, such as the CPU type and the ISA - * type. The AlphaDynInst serves as the primary interface to the CPU - * for instructions that are executing. - */ -template <class Impl> -class AlphaDynInst : public BaseDynInst<Impl> -{ - public: - /** Typedef for the CPU. */ - typedef typename Impl::FullCPU FullCPU; - - /** Binary machine instruction type. */ - typedef TheISA::MachInst MachInst; - /** Extended machine instruction type. */ - typedef TheISA::ExtMachInst ExtMachInst; - /** Logical register index type. */ - typedef TheISA::RegIndex RegIndex; - /** Integer register index type. */ - typedef TheISA::IntReg IntReg; - /** Misc register index type. */ - typedef TheISA::MiscReg MiscReg; - - enum { - MaxInstSrcRegs = TheISA::MaxInstSrcRegs, //< Max source regs - MaxInstDestRegs = TheISA::MaxInstDestRegs, //< Max dest regs - }; - - public: - /** BaseDynInst constructor given a binary instruction. */ - AlphaDynInst(ExtMachInst inst, Addr PC, Addr Pred_PC, InstSeqNum seq_num, - FullCPU *cpu); - - /** BaseDynInst constructor given a static inst pointer. */ - AlphaDynInst(StaticInstPtr &_staticInst); - - /** Executes the instruction.*/ - Fault execute(); - - /** Initiates the access. Only valid for memory operations. */ - Fault initiateAcc(); - - /** Completes the access. Only valid for memory operations. */ - Fault completeAcc(); - - private: - /** Initializes variables. */ - void initVars(); - - public: - MiscReg readMiscReg(int misc_reg) - { - return this->cpu->readMiscReg(misc_reg, this->threadNumber); - } - - MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault) - { - return this->cpu->readMiscRegWithEffect(misc_reg, fault, - this->threadNumber); - } - - Fault setMiscReg(int misc_reg, const MiscReg &val) - { - this->instResult.integer = val; - return this->cpu->setMiscReg(misc_reg, val, this->threadNumber); - } - - Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val) - { - return this->cpu->setMiscRegWithEffect(misc_reg, val, - this->threadNumber); - } - -#if FULL_SYSTEM - /** Calls hardware return from error interrupt. */ - Fault hwrei(); - /** Reads interrupt flag. */ - int readIntrFlag(); - /** Sets interrupt flag. */ - void setIntrFlag(int val); - /** Checks if system is in PAL mode. */ - bool inPalMode(); - /** Traps to handle specified fault. */ - void trap(Fault fault); - bool simPalCheck(int palFunc); -#else - /** Calls a syscall. */ - void syscall(); -#endif - - private: - /** Physical register index of the destination registers of this - * instruction. - */ - PhysRegIndex _destRegIdx[MaxInstDestRegs]; - - /** Physical register index of the source registers of this - * instruction. - */ - PhysRegIndex _srcRegIdx[MaxInstSrcRegs]; - - /** Physical register index of the previous producers of the - * architected destinations. - */ - PhysRegIndex _prevDestRegIdx[MaxInstDestRegs]; - - public: - - // The register accessor methods provide the index of the - // instruction's operand (e.g., 0 or 1), not the architectural - // register index, to simplify the implementation of register - // renaming. We find the architectural register index by indexing - // into the instruction's own operand index table. Note that a - // raw pointer to the StaticInst is provided instead of a - // ref-counted StaticInstPtr to redice overhead. This is fine as - // long as these methods don't copy the pointer into any long-term - // storage (which is pretty hard to imagine they would have reason - // to do). - - uint64_t readIntReg(const StaticInst *si, int idx) - { - return this->cpu->readIntReg(_srcRegIdx[idx]); - } - - float readFloatRegSingle(const StaticInst *si, int idx) - { - return this->cpu->readFloatRegSingle(_srcRegIdx[idx]); - } - - double readFloatRegDouble(const StaticInst *si, int idx) - { - return this->cpu->readFloatRegDouble(_srcRegIdx[idx]); - } - - uint64_t readFloatRegInt(const StaticInst *si, int idx) - { - return this->cpu->readFloatRegInt(_srcRegIdx[idx]); - } - - /** @todo: Make results into arrays so they can handle multiple dest - * registers. - */ - void setIntReg(const StaticInst *si, int idx, uint64_t val) - { - this->cpu->setIntReg(_destRegIdx[idx], val); - BaseDynInst<Impl>::setIntReg(si, idx, val); - } - - void setFloatRegSingle(const StaticInst *si, int idx, float val) - { - this->cpu->setFloatRegSingle(_destRegIdx[idx], val); - BaseDynInst<Impl>::setFloatRegSingle(si, idx, val); - } - - void setFloatRegDouble(const StaticInst *si, int idx, double val) - { - this->cpu->setFloatRegDouble(_destRegIdx[idx], val); - BaseDynInst<Impl>::setFloatRegDouble(si, idx, val); - } - - void setFloatRegInt(const StaticInst *si, int idx, uint64_t val) - { - this->cpu->setFloatRegInt(_destRegIdx[idx], val); - BaseDynInst<Impl>::setFloatRegInt(si, idx, val); - } - - /** Returns the physical register index of the i'th destination - * register. - */ - PhysRegIndex renamedDestRegIdx(int idx) const - { - return _destRegIdx[idx]; - } - - /** Returns the physical register index of the i'th source register. */ - PhysRegIndex renamedSrcRegIdx(int idx) const - { - return _srcRegIdx[idx]; - } - - /** Returns the physical register index of the previous physical register - * that remapped to the same logical register index. - */ - PhysRegIndex prevDestRegIdx(int idx) const - { - return _prevDestRegIdx[idx]; - } - - /** Renames a destination register to a physical register. Also records - * the previous physical register that the logical register mapped to. - */ - void renameDestReg(int idx, - PhysRegIndex renamed_dest, - PhysRegIndex previous_rename) - { - _destRegIdx[idx] = renamed_dest; - _prevDestRegIdx[idx] = previous_rename; - } - - /** Renames a source logical register to the physical register which - * has/will produce that logical register's result. - * @todo: add in whether or not the source register is ready. - */ - void renameSrcReg(int idx, PhysRegIndex renamed_src) - { - _srcRegIdx[idx] = renamed_src; - } - - public: - /** Calculates EA part of a memory instruction. Currently unused, - * though it may be useful in the future if we want to split - * memory operations into EA calculation and memory access parts. - */ - Fault calcEA() - { - return this->staticInst->eaCompInst()->execute(this, this->traceData); - } - - /** Does the memory access part of a memory instruction. Currently unused, - * though it may be useful in the future if we want to split - * memory operations into EA calculation and memory access parts. - */ - Fault memAccess() - { - return this->staticInst->memAccInst()->execute(this, this->traceData); - } -}; - -#endif // __CPU_O3_ALPHA_DYN_INST_HH__ - diff --git a/cpu/o3/cpu.cc b/cpu/o3/cpu.cc deleted file mode 100644 index 8d72bdc41..000000000 --- a/cpu/o3/cpu.cc +++ /dev/null @@ -1,1183 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config/full_system.hh" - -#if FULL_SYSTEM -#include "sim/system.hh" -#else -#include "sim/process.hh" -#endif - -#include "cpu/activity.hh" -#include "cpu/checker/cpu.hh" -#include "cpu/cpu_exec_context.hh" -#include "cpu/exec_context.hh" -#include "cpu/o3/alpha_dyn_inst.hh" -#include "cpu/o3/alpha_impl.hh" -#include "cpu/o3/cpu.hh" - -#include "sim/root.hh" -#include "sim/stat_control.hh" - -using namespace std; - -BaseFullCPU::BaseFullCPU(Params *params) - : BaseCPU(params), cpu_id(0) -{ -} - -void -BaseFullCPU::regStats() -{ - BaseCPU::regStats(); -} - -template <class Impl> -FullO3CPU<Impl>::TickEvent::TickEvent(FullO3CPU<Impl> *c) - : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c) -{ -} - -template <class Impl> -void -FullO3CPU<Impl>::TickEvent::process() -{ - cpu->tick(); -} - -template <class Impl> -const char * -FullO3CPU<Impl>::TickEvent::description() -{ - return "FullO3CPU tick event"; -} - -template <class Impl> -FullO3CPU<Impl>::FullO3CPU(Params *params) - : BaseFullCPU(params), - tickEvent(this), - removeInstsThisCycle(false), - fetch(params), - decode(params), - rename(params), - iew(params), - commit(params), - - regFile(params->numPhysIntRegs, params->numPhysFloatRegs), - - freeList(params->numberOfThreads,//number of activeThreads - TheISA::NumIntRegs, params->numPhysIntRegs, - TheISA::NumFloatRegs, params->numPhysFloatRegs), - - rob(params->numROBEntries, params->squashWidth, - params->smtROBPolicy, params->smtROBThreshold, - params->numberOfThreads), - - scoreboard(params->numberOfThreads,//number of activeThreads - TheISA::NumIntRegs, params->numPhysIntRegs, - TheISA::NumFloatRegs, params->numPhysFloatRegs, - TheISA::NumMiscRegs * number_of_threads, - TheISA::ZeroReg), - - // For now just have these time buffers be pretty big. - // @todo: Make these time buffer sizes parameters or derived - // from latencies - timeBuffer(5, 5), - fetchQueue(5, 5), - decodeQueue(5, 5), - renameQueue(5, 5), - iewQueue(5, 5), - activityRec(NumStages, 10, params->activity), - - globalSeqNum(1), - -#if FULL_SYSTEM - system(params->system), - memCtrl(system->memctrl), - physmem(system->physmem), - mem(params->mem), -#else -// pTable(params->pTable), - mem(params->workload[0]->getMemory()), -#endif // FULL_SYSTEM - switchCount(0), - icacheInterface(params->icacheInterface), - dcacheInterface(params->dcacheInterface), - deferRegistration(params->deferRegistration), - numThreads(number_of_threads) -{ - _status = Idle; - - if (params->checker) { - BaseCPU *temp_checker = params->checker; - checker = dynamic_cast<Checker<DynInstPtr> *>(temp_checker); - checker->setMemory(mem); -#if FULL_SYSTEM - checker->setSystem(params->system); -#endif - } else { - checker = NULL; - } - -#if !FULL_SYSTEM - thread.resize(number_of_threads); - tids.resize(number_of_threads); -#endif - - // The stages also need their CPU pointer setup. However this - // must be done at the upper level CPU because they have pointers - // to the upper level CPU, and not this FullO3CPU. - - // Set up Pointers to the activeThreads list for each stage - fetch.setActiveThreads(&activeThreads); - decode.setActiveThreads(&activeThreads); - rename.setActiveThreads(&activeThreads); - iew.setActiveThreads(&activeThreads); - commit.setActiveThreads(&activeThreads); - - // Give each of the stages the time buffer they will use. - fetch.setTimeBuffer(&timeBuffer); - decode.setTimeBuffer(&timeBuffer); - rename.setTimeBuffer(&timeBuffer); - iew.setTimeBuffer(&timeBuffer); - commit.setTimeBuffer(&timeBuffer); - - // Also setup each of the stages' queues. - fetch.setFetchQueue(&fetchQueue); - decode.setFetchQueue(&fetchQueue); - commit.setFetchQueue(&fetchQueue); - decode.setDecodeQueue(&decodeQueue); - rename.setDecodeQueue(&decodeQueue); - rename.setRenameQueue(&renameQueue); - iew.setRenameQueue(&renameQueue); - iew.setIEWQueue(&iewQueue); - commit.setIEWQueue(&iewQueue); - commit.setRenameQueue(&renameQueue); - - commit.setFetchStage(&fetch); - commit.setIEWStage(&iew); - rename.setIEWStage(&iew); - rename.setCommitStage(&commit); - -#if !FULL_SYSTEM - int active_threads = params->workload.size(); -#else - int active_threads = 1; -#endif - - //Make Sure That this a Valid Architeture - assert(params->numPhysIntRegs >= numThreads * TheISA::NumIntRegs); - assert(params->numPhysFloatRegs >= numThreads * TheISA::NumFloatRegs); - - rename.setScoreboard(&scoreboard); - iew.setScoreboard(&scoreboard); - - // Setup the rename map for whichever stages need it. - PhysRegIndex lreg_idx = 0; - PhysRegIndex freg_idx = params->numPhysIntRegs; //Index to 1 after int regs - - for (int tid=0; tid < numThreads; tid++) { - bool bindRegs = (tid <= active_threads - 1); - - commitRenameMap[tid].init(TheISA::NumIntRegs, - params->numPhysIntRegs, - lreg_idx, //Index for Logical. Regs - - TheISA::NumFloatRegs, - params->numPhysFloatRegs, - freg_idx, //Index for Float Regs - - TheISA::NumMiscRegs, - - TheISA::ZeroReg, - TheISA::ZeroReg, - - tid, - false); - - renameMap[tid].init(TheISA::NumIntRegs, - params->numPhysIntRegs, - lreg_idx, //Index for Logical. Regs - - TheISA::NumFloatRegs, - params->numPhysFloatRegs, - freg_idx, //Index for Float Regs - - TheISA::NumMiscRegs, - - TheISA::ZeroReg, - TheISA::ZeroReg, - - tid, - bindRegs); - } - - rename.setRenameMap(renameMap); - commit.setRenameMap(commitRenameMap); - - // Give renameMap & rename stage access to the freeList; - for (int i=0; i < numThreads; i++) { - renameMap[i].setFreeList(&freeList); - } - rename.setFreeList(&freeList); - - // Setup the page table for whichever stages need it. -#if !FULL_SYSTEM -// fetch.setPageTable(pTable); -// iew.setPageTable(pTable); -#endif - - // Setup the ROB for whichever stages need it. - commit.setROB(&rob); - - lastRunningCycle = curTick; - - contextSwitch = false; -} - -template <class Impl> -FullO3CPU<Impl>::~FullO3CPU() -{ -} - -template <class Impl> -void -FullO3CPU<Impl>::fullCPURegStats() -{ - BaseFullCPU::regStats(); - - // Register any of the FullCPU's stats here. - timesIdled - .name(name() + ".timesIdled") - .desc("Number of times that the entire CPU went into an idle state and" - " unscheduled itself") - .prereq(timesIdled); - - idleCycles - .name(name() + ".idleCycles") - .desc("Total number of cycles that the CPU has spent unscheduled due " - "to idling") - .prereq(idleCycles); - - // Number of Instructions simulated - // -------------------------------- - // Should probably be in Base CPU but need templated - // MaxThreads so put in here instead - committedInsts - .init(numThreads) - .name(name() + ".committedInsts") - .desc("Number of Instructions Simulated"); - - totalCommittedInsts - .name(name() + ".committedInsts_total") - .desc("Number of Instructions Simulated"); - - cpi - .name(name() + ".cpi") - .desc("CPI: Cycles Per Instruction") - .precision(6); - cpi = simTicks / committedInsts; - - totalCpi - .name(name() + ".cpi_total") - .desc("CPI: Total CPI of All Threads") - .precision(6); - totalCpi = simTicks / totalCommittedInsts; - - ipc - .name(name() + ".ipc") - .desc("IPC: Instructions Per Cycle") - .precision(6); - ipc = committedInsts / simTicks; - - totalIpc - .name(name() + ".ipc_total") - .desc("IPC: Total IPC of All Threads") - .precision(6); - totalIpc = totalCommittedInsts / simTicks; - -} - -template <class Impl> -void -FullO3CPU<Impl>::tick() -{ - DPRINTF(FullCPU, "\n\nFullCPU: Ticking main, FullO3CPU.\n"); - - ++numCycles; - -// activity = false; - - //Tick each of the stages - fetch.tick(); - - decode.tick(); - - rename.tick(); - - iew.tick(); - - commit.tick(); - -#if !FULL_SYSTEM - doContextSwitch(); -#endif - - // Now advance the time buffers - timeBuffer.advance(); - - fetchQueue.advance(); - decodeQueue.advance(); - renameQueue.advance(); - iewQueue.advance(); - - activityRec.advance(); - - if (removeInstsThisCycle) { - cleanUpRemovedInsts(); - } - - if (!tickEvent.scheduled()) { - if (_status == SwitchedOut) { - // increment stat - lastRunningCycle = curTick; - } else if (!activityRec.active()) { - lastRunningCycle = curTick; - timesIdled++; - } else { - tickEvent.schedule(curTick + cycles(1)); - } - } - -#if !FULL_SYSTEM - updateThreadPriority(); -#endif - -} - -template <class Impl> -void -FullO3CPU<Impl>::init() -{ - if (!deferRegistration) { - registerExecContexts(); - } - - // Set inSyscall so that the CPU doesn't squash when initially - // setting up registers. - for (int i = 0; i < number_of_threads; ++i) - thread[i]->inSyscall = true; - - for (int tid=0; tid < number_of_threads; tid++) { -#if FULL_SYSTEM - ExecContext *src_xc = execContexts[tid]; -#else - ExecContext *src_xc = thread[tid]->getXCProxy(); -#endif - // Threads start in the Suspended State - if (src_xc->status() != ExecContext::Suspended) { - continue; - } - -#if FULL_SYSTEM - TheISA::initCPU(src_xc, src_xc->readCpuId()); -#endif - } - - // Clear inSyscall. - for (int i = 0; i < number_of_threads; ++i) - thread[i]->inSyscall = false; - - // Initialize stages. - fetch.initStage(); - iew.initStage(); - rename.initStage(); - commit.initStage(); - - commit.setThreads(thread); -} - -template <class Impl> -void -FullO3CPU<Impl>::insertThread(unsigned tid) -{ - DPRINTF(FullCPU,"[tid:%i] Initializing thread data"); - // Will change now that the PC and thread state is internal to the CPU - // and not in the CPUExecContext. -#if 0 -#if FULL_SYSTEM - ExecContext *src_xc = system->execContexts[tid]; -#else - CPUExecContext *src_xc = thread[tid]; -#endif - - //Bind Int Regs to Rename Map - for (int ireg = 0; ireg < TheISA::NumIntRegs; ireg++) { - PhysRegIndex phys_reg = freeList.getIntReg(); - - renameMap[tid].setEntry(ireg,phys_reg); - scoreboard.setReg(phys_reg); - } - - //Bind Float Regs to Rename Map - for (int freg = 0; freg < TheISA::NumFloatRegs; freg++) { - PhysRegIndex phys_reg = freeList.getFloatReg(); - - renameMap[tid].setEntry(freg,phys_reg); - scoreboard.setReg(phys_reg); - } - - //Copy Thread Data Into RegFile - this->copyFromXC(tid); - - //Set PC/NPC - regFile.pc[tid] = src_xc->readPC(); - regFile.npc[tid] = src_xc->readNextPC(); - - src_xc->setStatus(ExecContext::Active); - - activateContext(tid,1); - - //Reset ROB/IQ/LSQ Entries - commit.rob->resetEntries(); - iew.resetEntries(); -#endif -} - -template <class Impl> -void -FullO3CPU<Impl>::removeThread(unsigned tid) -{ - DPRINTF(FullCPU,"[tid:%i] Removing thread data"); -#if 0 - //Unbind Int Regs from Rename Map - for (int ireg = 0; ireg < TheISA::NumIntRegs; ireg++) { - PhysRegIndex phys_reg = renameMap[tid].lookup(ireg); - - scoreboard.unsetReg(phys_reg); - freeList.addReg(phys_reg); - } - - //Unbind Float Regs from Rename Map - for (int freg = 0; freg < TheISA::NumFloatRegs; freg++) { - PhysRegIndex phys_reg = renameMap[tid].lookup(freg); - - scoreboard.unsetReg(phys_reg); - freeList.addReg(phys_reg); - } - - //Copy Thread Data From RegFile - /* Fix Me: - * Do we really need to do this if we are removing a thread - * in the sense that it's finished (exiting)? If the thread is just - * being suspended we might... - */ -// this->copyToXC(tid); - - //Squash Throughout Pipeline - fetch.squash(0,tid); - decode.squash(tid); - rename.squash(tid); - - assert(iew.ldstQueue.getCount(tid) == 0); - - //Reset ROB/IQ/LSQ Entries - if (activeThreads.size() >= 1) { - commit.rob->resetEntries(); - iew.resetEntries(); - } -#endif -} - - -template <class Impl> -void -FullO3CPU<Impl>::activateWhenReady(int tid) -{ - DPRINTF(FullCPU,"[tid:%i]: Checking if resources are available for incoming" - "(e.g. PhysRegs/ROB/IQ/LSQ) \n", - tid); - - bool ready = true; - - if (freeList.numFreeIntRegs() >= TheISA::NumIntRegs) { - DPRINTF(FullCPU,"[tid:%i] Suspending thread due to not enough " - "Phys. Int. Regs.\n", - tid); - ready = false; - } else if (freeList.numFreeFloatRegs() >= TheISA::NumFloatRegs) { - DPRINTF(FullCPU,"[tid:%i] Suspending thread due to not enough " - "Phys. Float. Regs.\n", - tid); - ready = false; - } else if (commit.rob->numFreeEntries() >= - commit.rob->entryAmount(activeThreads.size() + 1)) { - DPRINTF(FullCPU,"[tid:%i] Suspending thread due to not enough " - "ROB entries.\n", - tid); - ready = false; - } else if (iew.instQueue.numFreeEntries() >= - iew.instQueue.entryAmount(activeThreads.size() + 1)) { - DPRINTF(FullCPU,"[tid:%i] Suspending thread due to not enough " - "IQ entries.\n", - tid); - ready = false; - } else if (iew.ldstQueue.numFreeEntries() >= - iew.ldstQueue.entryAmount(activeThreads.size() + 1)) { - DPRINTF(FullCPU,"[tid:%i] Suspending thread due to not enough " - "LSQ entries.\n", - tid); - ready = false; - } - - if (ready) { - insertThread(tid); - - contextSwitch = false; - - cpuWaitList.remove(tid); - } else { - suspendContext(tid); - - //blocks fetch - contextSwitch = true; - - //do waitlist - cpuWaitList.push_back(tid); - } -} - -template <class Impl> -void -FullO3CPU<Impl>::activateContext(int tid, int delay) -{ - // Needs to set each stage to running as well. - list<unsigned>::iterator isActive = find( - activeThreads.begin(), activeThreads.end(), tid); - - if (isActive == activeThreads.end()) { - //May Need to Re-code this if the delay variable is the - //delay needed for thread to activate - DPRINTF(FullCPU, "Adding Thread %i to active threads list\n", - tid); - - activeThreads.push_back(tid); - } - - assert(_status == Idle || _status == SwitchedOut); - - scheduleTickEvent(delay); - - // Be sure to signal that there's some activity so the CPU doesn't - // deschedule itself. - activityRec.activity(); - fetch.wakeFromQuiesce(); - - _status = Running; -} - -template <class Impl> -void -FullO3CPU<Impl>::suspendContext(int tid) -{ - DPRINTF(FullCPU,"[tid: %i]: Suspended ...\n", tid); - unscheduleTickEvent(); - _status = Idle; -/* - //Remove From Active List, if Active - list<unsigned>::iterator isActive = find( - activeThreads.begin(), activeThreads.end(), tid); - - if (isActive != activeThreads.end()) { - DPRINTF(FullCPU,"[tid:%i]: Removing from active threads list\n", - tid); - activeThreads.erase(isActive); - } -*/ -} - -template <class Impl> -void -FullO3CPU<Impl>::deallocateContext(int tid) -{ - DPRINTF(FullCPU,"[tid:%i]: Deallocating ...", tid); -/* - //Remove From Active List, if Active - list<unsigned>::iterator isActive = find( - activeThreads.begin(), activeThreads.end(), tid); - - if (isActive != activeThreads.end()) { - DPRINTF(FullCPU,"[tid:%i]: Removing from active threads list\n", - tid); - activeThreads.erase(isActive); - - removeThread(tid); - } -*/ -} - -template <class Impl> -void -FullO3CPU<Impl>::haltContext(int tid) -{ - DPRINTF(FullCPU,"[tid:%i]: Halted ...", tid); -/* - //Remove From Active List, if Active - list<unsigned>::iterator isActive = find( - activeThreads.begin(), activeThreads.end(), tid); - - if (isActive != activeThreads.end()) { - DPRINTF(FullCPU,"[tid:%i]: Removing from active threads list\n", - tid); - activeThreads.erase(isActive); - - removeThread(tid); - } -*/ -} - -template <class Impl> -void -FullO3CPU<Impl>::switchOut(Sampler *_sampler) -{ - sampler = _sampler; - switchCount = 0; - fetch.switchOut(); - decode.switchOut(); - rename.switchOut(); - iew.switchOut(); - commit.switchOut(); - - // Wake the CPU and record activity so everything can drain out if - // the CPU is currently idle. - wakeCPU(); - activityRec.activity(); -} - -template <class Impl> -void -FullO3CPU<Impl>::signalSwitched() -{ - if (++switchCount == NumStages) { - fetch.doSwitchOut(); - rename.doSwitchOut(); - commit.doSwitchOut(); - instList.clear(); - while (!removeList.empty()) { - removeList.pop(); - } - - if (checker) - checker->switchOut(sampler); - - if (tickEvent.scheduled()) - tickEvent.squash(); - sampler->signalSwitched(); - _status = SwitchedOut; - } - assert(switchCount <= 5); -} - -template <class Impl> -void -FullO3CPU<Impl>::takeOverFrom(BaseCPU *oldCPU) -{ - // Flush out any old data from the time buffers. - for (int i = 0; i < 10; ++i) { - timeBuffer.advance(); - fetchQueue.advance(); - decodeQueue.advance(); - renameQueue.advance(); - iewQueue.advance(); - } - - activityRec.reset(); - - BaseCPU::takeOverFrom(oldCPU); - - fetch.takeOverFrom(); - decode.takeOverFrom(); - rename.takeOverFrom(); - iew.takeOverFrom(); - commit.takeOverFrom(); - - assert(!tickEvent.scheduled()); - - // @todo: Figure out how to properly select the tid to put onto - // the active threads list. - int tid = 0; - - list<unsigned>::iterator isActive = find( - activeThreads.begin(), activeThreads.end(), tid); - - if (isActive == activeThreads.end()) { - //May Need to Re-code this if the delay variable is the delay - //needed for thread to activate - DPRINTF(FullCPU, "Adding Thread %i to active threads list\n", - tid); - - activeThreads.push_back(tid); - } - - // Set all statuses to active, schedule the CPU's tick event. - // @todo: Fix up statuses so this is handled properly - for (int i = 0; i < execContexts.size(); ++i) { - ExecContext *xc = execContexts[i]; - if (xc->status() == ExecContext::Active && _status != Running) { - _status = Running; - tickEvent.schedule(curTick); - } - } - if (!tickEvent.scheduled()) - tickEvent.schedule(curTick); -} - -template <class Impl> -uint64_t -FullO3CPU<Impl>::readIntReg(int reg_idx) -{ - return regFile.readIntReg(reg_idx); -} - -template <class Impl> -float -FullO3CPU<Impl>::readFloatRegSingle(int reg_idx) -{ - return regFile.readFloatRegSingle(reg_idx); -} - -template <class Impl> -double -FullO3CPU<Impl>::readFloatRegDouble(int reg_idx) -{ - return regFile.readFloatRegDouble(reg_idx); -} - -template <class Impl> -uint64_t -FullO3CPU<Impl>::readFloatRegInt(int reg_idx) -{ - return regFile.readFloatRegInt(reg_idx); -} - -template <class Impl> -void -FullO3CPU<Impl>::setIntReg(int reg_idx, uint64_t val) -{ - regFile.setIntReg(reg_idx, val); -} - -template <class Impl> -void -FullO3CPU<Impl>::setFloatRegSingle(int reg_idx, float val) -{ - regFile.setFloatRegSingle(reg_idx, val); -} - -template <class Impl> -void -FullO3CPU<Impl>::setFloatRegDouble(int reg_idx, double val) -{ - regFile.setFloatRegDouble(reg_idx, val); -} - -template <class Impl> -void -FullO3CPU<Impl>::setFloatRegInt(int reg_idx, uint64_t val) -{ - regFile.setFloatRegInt(reg_idx, val); -} - -template <class Impl> -uint64_t -FullO3CPU<Impl>::readArchIntReg(int reg_idx, unsigned tid) -{ - PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx); - - return regFile.readIntReg(phys_reg); -} - -template <class Impl> -float -FullO3CPU<Impl>::readArchFloatRegSingle(int reg_idx, unsigned tid) -{ - int idx = reg_idx + TheISA::FP_Base_DepTag; - PhysRegIndex phys_reg = commitRenameMap[tid].lookup(idx); - - return regFile.readFloatRegSingle(phys_reg); -} - -template <class Impl> -double -FullO3CPU<Impl>::readArchFloatRegDouble(int reg_idx, unsigned tid) -{ - int idx = reg_idx + TheISA::FP_Base_DepTag; - PhysRegIndex phys_reg = commitRenameMap[tid].lookup(idx); - - return regFile.readFloatRegDouble(phys_reg); -} - -template <class Impl> -uint64_t -FullO3CPU<Impl>::readArchFloatRegInt(int reg_idx, unsigned tid) -{ - int idx = reg_idx + TheISA::FP_Base_DepTag; - PhysRegIndex phys_reg = commitRenameMap[tid].lookup(idx); - - return regFile.readFloatRegInt(phys_reg); -} - -template <class Impl> -void -FullO3CPU<Impl>::setArchIntReg(int reg_idx, uint64_t val, unsigned tid) -{ - PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx); - - regFile.setIntReg(phys_reg, val); -} - -template <class Impl> -void -FullO3CPU<Impl>::setArchFloatRegSingle(int reg_idx, float val, unsigned tid) -{ - PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx); - - regFile.setFloatRegSingle(phys_reg, val); -} - -template <class Impl> -void -FullO3CPU<Impl>::setArchFloatRegDouble(int reg_idx, double val, unsigned tid) -{ - PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx); - - regFile.setFloatRegDouble(phys_reg, val); -} - -template <class Impl> -void -FullO3CPU<Impl>::setArchFloatRegInt(int reg_idx, uint64_t val, unsigned tid) -{ - PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx); - - regFile.setFloatRegInt(phys_reg, val); -} - -template <class Impl> -uint64_t -FullO3CPU<Impl>::readPC(unsigned tid) -{ - return commit.readPC(tid); -} - -template <class Impl> -void -FullO3CPU<Impl>::setPC(Addr new_PC,unsigned tid) -{ - commit.setPC(new_PC, tid); -} - -template <class Impl> -uint64_t -FullO3CPU<Impl>::readNextPC(unsigned tid) -{ - return commit.readNextPC(tid); -} - -template <class Impl> -void -FullO3CPU<Impl>::setNextPC(uint64_t val,unsigned tid) -{ - commit.setNextPC(val, tid); -} - -template <class Impl> -typename FullO3CPU<Impl>::ListIt -FullO3CPU<Impl>::addInst(DynInstPtr &inst) -{ - instList.push_back(inst); - - return --(instList.end()); -} - -template <class Impl> -void -FullO3CPU<Impl>::instDone(unsigned tid) -{ - // Keep an instruction count. - thread[tid]->numInst++; - thread[tid]->numInsts++; - committedInsts[tid]++; - totalCommittedInsts++; - - // Check for instruction-count-based events. - comInstEventQueue[tid]->serviceEvents(thread[tid]->numInst); -} - -template <class Impl> -void -FullO3CPU<Impl>::addToRemoveList(DynInstPtr &inst) -{ - removeInstsThisCycle = true; - - removeList.push(inst->getInstListIt()); -} - -template <class Impl> -void -FullO3CPU<Impl>::removeFrontInst(DynInstPtr &inst) -{ - DPRINTF(FullCPU, "FullCPU: Removing committed instruction [tid:%i] PC %#x " - "[sn:%lli]\n", - inst->threadNumber, inst->readPC(), inst->seqNum); - - removeInstsThisCycle = true; - - // Remove the front instruction. - removeList.push(inst->getInstListIt()); -} - -template <class Impl> -void -FullO3CPU<Impl>::removeInstsNotInROB(unsigned tid) -{ - DPRINTF(FullCPU, "FullCPU: Thread %i: Deleting instructions from instruction" - " list.\n", tid); - - ListIt end_it; - - bool rob_empty = false; - - if (instList.empty()) { - return; - } else if (rob.isEmpty(/*tid*/)) { - DPRINTF(FullCPU, "FullCPU: ROB is empty, squashing all insts.\n"); - end_it = instList.begin(); - rob_empty = true; - } else { - end_it = (rob.readTailInst(tid))->getInstListIt(); - DPRINTF(FullCPU, "FullCPU: ROB is not empty, squashing insts not in ROB.\n"); - } - - removeInstsThisCycle = true; - - ListIt inst_it = instList.end(); - - inst_it--; - - // Walk through the instruction list, removing any instructions - // that were inserted after the given instruction iterator, end_it. - while (inst_it != end_it) { - assert(!instList.empty()); - - squashInstIt(inst_it, tid); - - inst_it--; - } - - // If the ROB was empty, then we actually need to remove the first - // instruction as well. - if (rob_empty) { - squashInstIt(inst_it, tid); - } -} - -template <class Impl> -void -FullO3CPU<Impl>::removeInstsUntil(const InstSeqNum &seq_num, - unsigned tid) -{ - assert(!instList.empty()); - - removeInstsThisCycle = true; - - ListIt inst_iter = instList.end(); - - inst_iter--; - - DPRINTF(FullCPU, "FullCPU: Deleting instructions from instruction " - "list that are from [tid:%i] and above [sn:%lli] (end=%lli).\n", - tid, seq_num, (*inst_iter)->seqNum); - - while ((*inst_iter)->seqNum > seq_num) { - - bool break_loop = (inst_iter == instList.begin()); - - squashInstIt(inst_iter, tid); - - inst_iter--; - - if (break_loop) - break; - } -} - -template <class Impl> -inline void -FullO3CPU<Impl>::squashInstIt(const ListIt &instIt, const unsigned &tid) -{ - if ((*instIt)->threadNumber == tid) { - DPRINTF(FullCPU, "FullCPU: Squashing instruction, " - "[tid:%i] [sn:%lli] PC %#x\n", - (*instIt)->threadNumber, - (*instIt)->seqNum, - (*instIt)->readPC()); - - // Mark it as squashed. - (*instIt)->setSquashed(); - - // @todo: Formulate a consistent method for deleting - // instructions from the instruction list - // Remove the instruction from the list. - removeList.push(instIt); - } -} - -template <class Impl> -void -FullO3CPU<Impl>::cleanUpRemovedInsts() -{ - while (!removeList.empty()) { - DPRINTF(FullCPU, "FullCPU: Removing instruction, " - "[tid:%i] [sn:%lli] PC %#x\n", - (*removeList.front())->threadNumber, - (*removeList.front())->seqNum, - (*removeList.front())->readPC()); - - instList.erase(removeList.front()); - - removeList.pop(); - } - - removeInstsThisCycle = false; -} -/* -template <class Impl> -void -FullO3CPU<Impl>::removeAllInsts() -{ - instList.clear(); -} -*/ -template <class Impl> -void -FullO3CPU<Impl>::dumpInsts() -{ - int num = 0; - - ListIt inst_list_it = instList.begin(); - - cprintf("Dumping Instruction List\n"); - - while (inst_list_it != instList.end()) { - cprintf("Instruction:%i\nPC:%#x\n[tid:%i]\n[sn:%lli]\nIssued:%i\n" - "Squashed:%i\n\n", - num, (*inst_list_it)->readPC(), (*inst_list_it)->threadNumber, - (*inst_list_it)->seqNum, (*inst_list_it)->isIssued(), - (*inst_list_it)->isSquashed()); - inst_list_it++; - ++num; - } -} -/* -template <class Impl> -void -FullO3CPU<Impl>::wakeDependents(DynInstPtr &inst) -{ - iew.wakeDependents(inst); -} -*/ -template <class Impl> -void -FullO3CPU<Impl>::wakeCPU() -{ - if (activityRec.active() || tickEvent.scheduled()) { - DPRINTF(Activity, "CPU already running.\n"); - return; - } - - DPRINTF(Activity, "Waking up CPU\n"); - - idleCycles += (curTick - 1) - lastRunningCycle; - - tickEvent.schedule(curTick); -} - -template <class Impl> -int -FullO3CPU<Impl>::getFreeTid() -{ - for (int i=0; i < numThreads; i++) { - if (!tids[i]) { - tids[i] = true; - return i; - } - } - - return -1; -} - -template <class Impl> -void -FullO3CPU<Impl>::doContextSwitch() -{ - if (contextSwitch) { - - //ADD CODE TO DEACTIVE THREAD HERE (???) - - for (int tid=0; tid < cpuWaitList.size(); tid++) { - activateWhenReady(tid); - } - - if (cpuWaitList.size() == 0) - contextSwitch = true; - } -} - -template <class Impl> -void -FullO3CPU<Impl>::updateThreadPriority() -{ - if (activeThreads.size() > 1) - { - //DEFAULT TO ROUND ROBIN SCHEME - //e.g. Move highest priority to end of thread list - list<unsigned>::iterator list_begin = activeThreads.begin(); - list<unsigned>::iterator list_end = activeThreads.end(); - - unsigned high_thread = *list_begin; - - activeThreads.erase(list_begin); - - activeThreads.push_back(high_thread); - } -} - -// Forward declaration of FullO3CPU. -template class FullO3CPU<AlphaSimpleImpl>; diff --git a/cpu/o3/cpu.hh b/cpu/o3/cpu.hh deleted file mode 100644 index 8db65d501..000000000 --- a/cpu/o3/cpu.hh +++ /dev/null @@ -1,521 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_CPU_HH__ -#define __CPU_O3_CPU_HH__ - -#include <iostream> -#include <list> -#include <queue> -#include <set> -#include <vector> - -#include "base/statistics.hh" -#include "base/timebuf.hh" -#include "config/full_system.hh" -#include "cpu/activity.hh" -#include "cpu/base.hh" -#include "cpu/cpu_exec_context.hh" -#include "cpu/o3/comm.hh" -#include "cpu/o3/cpu_policy.hh" -#include "cpu/o3/scoreboard.hh" -#include "cpu/o3/thread_state.hh" -#include "sim/process.hh" - -template <class> -class Checker; -class ExecContext; -class MemInterface; -class Process; - -class BaseFullCPU : public BaseCPU -{ - //Stuff that's pretty ISA independent will go here. - public: - typedef BaseCPU::Params Params; - - BaseFullCPU(Params *params); - - void regStats(); - - protected: - int cpu_id; -}; - -template <class Impl> -class FullO3CPU : public BaseFullCPU -{ - public: - // Typedefs from the Impl here. - typedef typename Impl::CPUPol CPUPolicy; - typedef typename Impl::Params Params; - typedef typename Impl::DynInstPtr DynInstPtr; - - typedef O3ThreadState<Impl> Thread; - - typedef typename std::list<DynInstPtr>::iterator ListIt; - - public: - enum Status { - Running, - Idle, - Halted, - Blocked, - SwitchedOut - }; - - /** Overall CPU status. */ - Status _status; - - private: - class TickEvent : public Event - { - private: - /** Pointer to the CPU. */ - FullO3CPU<Impl> *cpu; - - public: - /** Constructs a tick event. */ - TickEvent(FullO3CPU<Impl> *c); - - /** Processes a tick event, calling tick() on the CPU. */ - void process(); - /** Returns the description of the tick event. */ - const char *description(); - }; - - /** The tick event used for scheduling CPU ticks. */ - TickEvent tickEvent; - - /** Schedule tick event, regardless of its current state. */ - void scheduleTickEvent(int delay) - { - if (tickEvent.squashed()) - tickEvent.reschedule(curTick + cycles(delay)); - else if (!tickEvent.scheduled()) - tickEvent.schedule(curTick + cycles(delay)); - } - - /** Unschedule tick event, regardless of its current state. */ - void unscheduleTickEvent() - { - if (tickEvent.scheduled()) - tickEvent.squash(); - } - - public: - /** Constructs a CPU with the given parameters. */ - FullO3CPU(Params *params); - /** Destructor. */ - ~FullO3CPU(); - - /** Registers statistics. */ - void fullCPURegStats(); - - /** Ticks CPU, calling tick() on each stage, and checking the overall - * activity to see if the CPU should deschedule itself. - */ - void tick(); - - /** Initialize the CPU */ - void init(); - - /** Setup CPU to insert a thread's context */ - void insertThread(unsigned tid); - - /** Remove all of a thread's context from CPU */ - void removeThread(unsigned tid); - - /** Count the Total Instructions Committed in the CPU. */ - virtual Counter totalInstructions() const - { - Counter total(0); - - for (int i=0; i < thread.size(); i++) - total += thread[i]->numInst; - - return total; - } - - /** Add Thread to Active Threads List. */ - void activateContext(int tid, int delay); - - /** Remove Thread from Active Threads List */ - void suspendContext(int tid); - - /** Remove Thread from Active Threads List && - * Remove Thread Context from CPU. - */ - void deallocateContext(int tid); - - /** Remove Thread from Active Threads List && - * Remove Thread Context from CPU. - */ - void haltContext(int tid); - - /** Activate a Thread When CPU Resources are Available. */ - void activateWhenReady(int tid); - - /** Add or Remove a Thread Context in the CPU. */ - void doContextSwitch(); - - /** Update The Order In Which We Process Threads. */ - void updateThreadPriority(); - - /** Executes a syscall on this cycle. - * --------------------------------------- - * Note: this is a virtual function. CPU-Specific - * functionality defined in derived classes - */ - virtual void syscall(int tid) { panic("Unimplemented!"); } - - /** Check if there are any system calls pending. */ - void checkSyscalls(); - - /** Switches out this CPU. - */ - void switchOut(Sampler *sampler); - - void signalSwitched(); - - /** Takes over from another CPU. - */ - void takeOverFrom(BaseCPU *oldCPU); - - /** Get the current instruction sequence number, and increment it. */ - InstSeqNum getAndIncrementInstSeq() - { return globalSeqNum++; } - -#if FULL_SYSTEM - /** Check if this address is a valid instruction address. */ - bool validInstAddr(Addr addr) { return true; } - - /** Check if this address is a valid data address. */ - bool validDataAddr(Addr addr) { return true; } - - /** Get instruction asid. */ - int getInstAsid(unsigned tid) - { return regFile.miscRegs[tid].getInstAsid(); } - - /** Get data asid. */ - int getDataAsid(unsigned tid) - { return regFile.miscRegs[tid].getDataAsid(); } -#else - /** Check if this address is a valid instruction address. */ - bool validInstAddr(Addr addr,unsigned tid) - { return thread[tid]->validInstAddr(addr); } - - /** Check if this address is a valid data address. */ - bool validDataAddr(Addr addr,unsigned tid) - { return thread[tid]->validDataAddr(addr); } - - /** Get instruction asid. */ - int getInstAsid(unsigned tid) - { return thread[tid]->asid; } - - /** Get data asid. */ - int getDataAsid(unsigned tid) - { return thread[tid]->asid; } - -#endif - - // - // New accessors for new decoder. - // - uint64_t readIntReg(int reg_idx); - - float readFloatRegSingle(int reg_idx); - - double readFloatRegDouble(int reg_idx); - - uint64_t readFloatRegInt(int reg_idx); - - void setIntReg(int reg_idx, uint64_t val); - - void setFloatRegSingle(int reg_idx, float val); - - void setFloatRegDouble(int reg_idx, double val); - - void setFloatRegInt(int reg_idx, uint64_t val); - - uint64_t readArchIntReg(int reg_idx, unsigned tid); - - float readArchFloatRegSingle(int reg_idx, unsigned tid); - - double readArchFloatRegDouble(int reg_idx, unsigned tid); - - uint64_t readArchFloatRegInt(int reg_idx, unsigned tid); - - void setArchIntReg(int reg_idx, uint64_t val, unsigned tid); - - void setArchFloatRegSingle(int reg_idx, float val, unsigned tid); - - void setArchFloatRegDouble(int reg_idx, double val, unsigned tid); - - void setArchFloatRegInt(int reg_idx, uint64_t val, unsigned tid); - - uint64_t readPC(unsigned tid); - - void setPC(Addr new_PC,unsigned tid); - - uint64_t readNextPC(unsigned tid); - - void setNextPC(uint64_t val,unsigned tid); - - /** Function to add instruction onto the head of the list of the - * instructions. Used when new instructions are fetched. - */ - ListIt addInst(DynInstPtr &inst); - - /** Function to tell the CPU that an instruction has completed. */ - void instDone(unsigned tid); - - /** Add Instructions to the CPU Remove List*/ - void addToRemoveList(DynInstPtr &inst); - - /** Remove an instruction from the front end of the list. There's - * no restriction on location of the instruction. - */ - void removeFrontInst(DynInstPtr &inst); - - /** Remove all instructions that are not currently in the ROB. */ - void removeInstsNotInROB(unsigned tid); - - /** Remove all instructions younger than the given sequence number. */ - void removeInstsUntil(const InstSeqNum &seq_num,unsigned tid); - - inline void squashInstIt(const ListIt &instIt, const unsigned &tid); - - void cleanUpRemovedInsts(); - - /** Remove all instructions from the list. */ -// void removeAllInsts(); - - void dumpInsts(); - - /** Basically a wrapper function so that instructions executed at - * commit can tell the instruction queue that they have - * completed. Eventually this hack should be removed. - */ -// void wakeDependents(DynInstPtr &inst); - - public: - /** List of all the instructions in flight. */ - std::list<DynInstPtr> instList; - - /** List of all the instructions that will be removed at the end of this - * cycle. - */ - std::queue<ListIt> removeList; - -#ifdef DEBUG - std::set<InstSeqNum> snList; -#endif - - /** Records if instructions need to be removed this cycle due to - * being retired or squashed. - */ - bool removeInstsThisCycle; - - protected: - /** The fetch stage. */ - typename CPUPolicy::Fetch fetch; - - /** The decode stage. */ - typename CPUPolicy::Decode decode; - - /** The dispatch stage. */ - typename CPUPolicy::Rename rename; - - /** The issue/execute/writeback stages. */ - typename CPUPolicy::IEW iew; - - /** The commit stage. */ - typename CPUPolicy::Commit commit; - - /** The register file. */ - typename CPUPolicy::RegFile regFile; - - /** The free list. */ - typename CPUPolicy::FreeList freeList; - - /** The rename map. */ - typename CPUPolicy::RenameMap renameMap[Impl::MaxThreads]; - - /** The commit rename map. */ - typename CPUPolicy::RenameMap commitRenameMap[Impl::MaxThreads]; - - /** The re-order buffer. */ - typename CPUPolicy::ROB rob; - - /** Active Threads List */ - std::list<unsigned> activeThreads; - - /** Integer Register Scoreboard */ - Scoreboard scoreboard; - - public: - /** Enum to give each stage a specific index, so when calling - * activateStage() or deactivateStage(), they can specify which stage - * is being activated/deactivated. - */ - enum StageIdx { - FetchIdx, - DecodeIdx, - RenameIdx, - IEWIdx, - CommitIdx, - NumStages }; - - /** Typedefs from the Impl to get the structs that each of the - * time buffers should use. - */ - typedef typename CPUPolicy::TimeStruct TimeStruct; - - typedef typename CPUPolicy::FetchStruct FetchStruct; - - typedef typename CPUPolicy::DecodeStruct DecodeStruct; - - typedef typename CPUPolicy::RenameStruct RenameStruct; - - typedef typename CPUPolicy::IEWStruct IEWStruct; - - /** The main time buffer to do backwards communication. */ - TimeBuffer<TimeStruct> timeBuffer; - - /** The fetch stage's instruction queue. */ - TimeBuffer<FetchStruct> fetchQueue; - - /** The decode stage's instruction queue. */ - TimeBuffer<DecodeStruct> decodeQueue; - - /** The rename stage's instruction queue. */ - TimeBuffer<RenameStruct> renameQueue; - - /** The IEW stage's instruction queue. */ - TimeBuffer<IEWStruct> iewQueue; - - public: - ActivityRecorder activityRec; - - void activityThisCycle() { activityRec.activity(); } - - void activateStage(const StageIdx idx) - { activityRec.activateStage(idx); } - - void deactivateStage(const StageIdx idx) - { activityRec.deactivateStage(idx); } - - /** Wakes the CPU, rescheduling the CPU if it's not already active. */ - void wakeCPU(); - - /** Gets a free thread id. Use if thread ids change across system. */ - int getFreeTid(); - - public: - /** Temporary function to get pointer to exec context. */ - ExecContext *xcBase(unsigned tid) - { - return thread[tid]->getXCProxy(); - } - - /** The global sequence number counter. */ - InstSeqNum globalSeqNum; - - Checker<DynInstPtr> *checker; - -#if FULL_SYSTEM - /** Pointer to the system. */ - System *system; - - /** Pointer to the memory controller. */ - MemoryController *memCtrl; - /** Pointer to physical memory. */ - PhysicalMemory *physmem; -#endif - - /** Pointer to memory. */ - FunctionalMemory *mem; - - Sampler *sampler; - - int switchCount; - - // List of all ExecContexts. - std::vector<Thread *> thread; - -#if 0 - /** Page table pointer. */ - PageTable *pTable; -#endif - - /** Pointer to the icache interface. */ - MemInterface *icacheInterface; - /** Pointer to the dcache interface. */ - MemInterface *dcacheInterface; - - /** Whether or not the CPU should defer its registration. */ - bool deferRegistration; - - /** Is there a context switch pending? */ - bool contextSwitch; - - /** Threads Scheduled to Enter CPU */ - std::list<int> cpuWaitList; - - /** The cycle that the CPU was last running, used for statistics. */ - Tick lastRunningCycle; - - /** Number of Threads CPU can process */ - unsigned numThreads; - - /** Mapping for system thread id to cpu id */ - std::map<unsigned,unsigned> threadMap; - - /** Available thread ids in the cpu*/ - std::vector<unsigned> tids; - - /** Stat for total number of times the CPU is descheduled. */ - Stats::Scalar<> timesIdled; - /** Stat for total number of cycles the CPU spends descheduled. */ - Stats::Scalar<> idleCycles; - /** Stat for the number of committed instructions per thread. */ - Stats::Vector<> committedInsts; - /** Stat for the total number of committed instructions. */ - Stats::Scalar<> totalCommittedInsts; - /** Stat for the CPI per thread. */ - Stats::Formula cpi; - /** Stat for the total CPI. */ - Stats::Formula totalCpi; - /** Stat for the IPC per thread. */ - Stats::Formula ipc; - /** Stat for the total IPC. */ - Stats::Formula totalIpc; -}; - -#endif // __CPU_O3_CPU_HH__ diff --git a/cpu/o3/regfile.hh b/cpu/o3/regfile.hh deleted file mode 100644 index ed1238d36..000000000 --- a/cpu/o3/regfile.hh +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_REGFILE_HH__ -#define __CPU_O3_REGFILE_HH__ - -#include "arch/isa_traits.hh" -#include "arch/faults.hh" -#include "base/trace.hh" -#include "config/full_system.hh" -#include "cpu/o3/comm.hh" - -#if FULL_SYSTEM -#include "kern/kernel_stats.hh" - -#endif - -#include <vector> - -/** - * Simple physical register file class. - * This really only depends on the ISA, and not the Impl. Things that are - * in the ifdef FULL_SYSTEM are pretty dependent on the ISA, and probably - * should go in the AlphaFullCPU. - */ -template <class Impl> -class PhysRegFile -{ - protected: - typedef TheISA::IntReg IntReg; - typedef TheISA::FloatReg FloatReg; - typedef TheISA::MiscRegFile MiscRegFile; - typedef TheISA::MiscReg MiscReg; - // Note that most of the definitions of the IntReg, FloatReg, etc. exist - // within the Impl/ISA class and not within this PhysRegFile class. - - // Will make these registers public for now, but they probably should - // be private eventually with some accessor functions. - public: - typedef typename Impl::FullCPU FullCPU; - - /** - * Constructs a physical register file with the specified amount of - * integer and floating point registers. - */ - PhysRegFile(unsigned _numPhysicalIntRegs, - unsigned _numPhysicalFloatRegs); - - //Everything below should be pretty well identical to the normal - //register file that exists within AlphaISA class. - //The duplication is unfortunate but it's better than having - //different ways to access certain registers. - - //Add these in later when everything else is in place -// void serialize(std::ostream &os); -// void unserialize(Checkpoint *cp, const std::string §ion); - - /** Reads an integer register. */ - uint64_t readIntReg(PhysRegIndex reg_idx) - { - assert(reg_idx < numPhysicalIntRegs); - - DPRINTF(IEW, "RegFile: Access to int register %i, has data " - "%i\n", int(reg_idx), intRegFile[reg_idx]); - return intRegFile[reg_idx]; - } - - /** Reads a floating point register (single precision). */ - float readFloatRegSingle(PhysRegIndex reg_idx) - { - // Remove the base Float reg dependency. - reg_idx = reg_idx - numPhysicalIntRegs; - - assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs); - - DPRINTF(IEW, "RegFile: Access to float register %i as single, has " - "data %8.8f\n", int(reg_idx), (float)floatRegFile[reg_idx].d); - - return (float)floatRegFile[reg_idx].d; - } - - /** Reads a floating point register (double precision). */ - double readFloatRegDouble(PhysRegIndex reg_idx) - { - // Remove the base Float reg dependency. - reg_idx = reg_idx - numPhysicalIntRegs; - - assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs); - - DPRINTF(IEW, "RegFile: Access to float register %i as double, has " - " data %8.8f\n", int(reg_idx), floatRegFile[reg_idx].d); - - return floatRegFile[reg_idx].d; - } - - /** Reads a floating point register as an integer. */ - uint64_t readFloatRegInt(PhysRegIndex reg_idx) - { - // Remove the base Float reg dependency. - reg_idx = reg_idx - numPhysicalIntRegs; - - assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs); - - DPRINTF(IEW, "RegFile: Access to float register %i as int, has data " - "%lli\n", int(reg_idx), floatRegFile[reg_idx].q); - - return floatRegFile[reg_idx].q; - } - - /** Sets an integer register to the given value. */ - void setIntReg(PhysRegIndex reg_idx, uint64_t val) - { - assert(reg_idx < numPhysicalIntRegs); - - DPRINTF(IEW, "RegFile: Setting int register %i to %lli\n", - int(reg_idx), val); - - if (reg_idx != TheISA::ZeroReg) - intRegFile[reg_idx] = val; - } - - /** Sets a single precision floating point register to the given value. */ - void setFloatRegSingle(PhysRegIndex reg_idx, float val) - { - // Remove the base Float reg dependency. - reg_idx = reg_idx - numPhysicalIntRegs; - - assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs); - - DPRINTF(IEW, "RegFile: Setting float register %i to %8.8f\n", - int(reg_idx), val); - - if (reg_idx != TheISA::ZeroReg) - floatRegFile[reg_idx].d = (double)val; - } - - /** Sets a double precision floating point register to the given value. */ - void setFloatRegDouble(PhysRegIndex reg_idx, double val) - { - // Remove the base Float reg dependency. - reg_idx = reg_idx - numPhysicalIntRegs; - - assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs); - - DPRINTF(IEW, "RegFile: Setting float register %i to %8.8f\n", - int(reg_idx), val); - - if (reg_idx != TheISA::ZeroReg) - floatRegFile[reg_idx].d = val; - } - - /** Sets a floating point register to the given integer value. */ - void setFloatRegInt(PhysRegIndex reg_idx, uint64_t val) - { - // Remove the base Float reg dependency. - reg_idx = reg_idx - numPhysicalIntRegs; - - assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs); - - DPRINTF(IEW, "RegFile: Setting float register %i to %lli\n", - int(reg_idx), val); - - if (reg_idx != TheISA::ZeroReg) - floatRegFile[reg_idx].q = val; - } - - //Consider leaving this stuff and below in some implementation specific - //file as opposed to the general register file. Or have a derived class. - MiscReg readMiscReg(int misc_reg, unsigned thread_id) - { - return miscRegs[thread_id].readReg(misc_reg); - } - - MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault, - unsigned thread_id) - { - return miscRegs[thread_id].readRegWithEffect(misc_reg, fault, - cpu->xcBase(thread_id)); - } - - Fault setMiscReg(int misc_reg, const MiscReg &val, unsigned thread_id) - { - return miscRegs[thread_id].setReg(misc_reg, val); - } - - Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val, - unsigned thread_id) - { - return miscRegs[thread_id].setRegWithEffect(misc_reg, val, - cpu->xcBase(thread_id)); - } - -#if FULL_SYSTEM - int readIntrFlag() { return intrflag; } - /** Sets an interrupt flag. */ - void setIntrFlag(int val) { intrflag = val; } -#endif - - public: - /** (signed) integer register file. */ - std::vector<IntReg> intRegFile; - - /** Floating point register file. */ - std::vector<FloatReg> floatRegFile; - - /** Miscellaneous register file. */ - MiscRegFile miscRegs[Impl::MaxThreads]; - -#if FULL_SYSTEM - private: - int intrflag; // interrupt flag -#endif - - private: - /** CPU pointer. */ - FullCPU *cpu; - - public: - /** Sets the CPU pointer. */ - void setCPU(FullCPU *cpu_ptr) { cpu = cpu_ptr; } - - /** Number of physical integer registers. */ - unsigned numPhysicalIntRegs; - /** Number of physical floating point registers. */ - unsigned numPhysicalFloatRegs; -}; - -template <class Impl> -PhysRegFile<Impl>::PhysRegFile(unsigned _numPhysicalIntRegs, - unsigned _numPhysicalFloatRegs) - : numPhysicalIntRegs(_numPhysicalIntRegs), - numPhysicalFloatRegs(_numPhysicalFloatRegs) -{ - intRegFile.resize(numPhysicalIntRegs); - floatRegFile.resize(numPhysicalFloatRegs); - - //memset(intRegFile, 0, sizeof(*intRegFile)); - //memset(floatRegFile, 0, sizeof(*floatRegFile)); -} - -#endif diff --git a/cpu/pc_event.hh b/cpu/pc_event.hh deleted file mode 100644 index 7fa3902cc..000000000 --- a/cpu/pc_event.hh +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (c) 2002-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __PC_EVENT_HH__ -#define __PC_EVENT_HH__ - -#include <vector> - -#include "mem/mem_req.hh" - -class ExecContext; -class PCEventQueue; - -class PCEvent -{ - protected: - static const Addr badpc = MemReq::inval_addr; - - protected: - std::string description; - PCEventQueue *queue; - Addr evpc; - - public: - PCEvent(PCEventQueue *q, const std::string &desc, Addr pc); - - virtual ~PCEvent() { if (queue) remove(); } - - // for DPRINTF - virtual const std::string name() const { return description; } - - std::string descr() const { return description; } - Addr pc() const { return evpc; } - - bool remove(); - virtual void process(ExecContext *xc) = 0; -}; - -class PCEventQueue -{ - protected: - typedef PCEvent * record_t; - class MapCompare { - public: - bool operator()(const record_t &l, const record_t &r) const { - return l->pc() < r->pc(); - } - bool operator()(const record_t &l, Addr pc) const { - return l->pc() < pc; - } - bool operator()(Addr pc, const record_t &r) const { - return pc < r->pc(); - } - }; - typedef std::vector<record_t> map_t; - - public: - typedef map_t::iterator iterator; - typedef map_t::const_iterator const_iterator; - - protected: - typedef std::pair<iterator, iterator> range_t; - typedef std::pair<const_iterator, const_iterator> const_range_t; - - protected: - map_t pc_map; - - bool doService(ExecContext *xc); - - public: - PCEventQueue(); - ~PCEventQueue(); - - bool remove(PCEvent *event); - bool schedule(PCEvent *event); - bool service(ExecContext *xc) - { - if (pc_map.empty()) - return false; - - return doService(xc); - } - - range_t equal_range(Addr pc); - range_t equal_range(PCEvent *event) { return equal_range(event->pc()); } - - void dump() const; -}; - - -inline -PCEvent::PCEvent(PCEventQueue *q, const std::string &desc, Addr pc) - : description(desc), queue(q), evpc(pc) -{ - queue->schedule(this); -} - -inline bool -PCEvent::remove() -{ - if (!queue) - panic("cannot remove an uninitialized event;"); - - return queue->remove(this); -} - -class BreakPCEvent : public PCEvent -{ - protected: - bool remove; - - public: - BreakPCEvent(PCEventQueue *q, const std::string &desc, Addr addr, - bool del = false); - virtual void process(ExecContext *xc); -}; - -#endif // __PC_EVENT_HH__ diff --git a/cpu/simple/cpu.cc b/cpu/simple/cpu.cc deleted file mode 100644 index c03945ffa..000000000 --- a/cpu/simple/cpu.cc +++ /dev/null @@ -1,955 +0,0 @@ -/* - * Copyright (c) 2002-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <cmath> -#include <cstdio> -#include <cstdlib> -#include <iostream> -#include <iomanip> -#include <list> -#include <sstream> -#include <string> - -#include "base/cprintf.hh" -#include "base/inifile.hh" -#include "base/loader/symtab.hh" -#include "base/misc.hh" -#include "base/pollevent.hh" -#include "base/range.hh" -#include "base/stats/events.hh" -#include "base/trace.hh" -#include "cpu/base.hh" -#include "cpu/cpu_exec_context.hh" -#include "cpu/exec_context.hh" -#include "cpu/exetrace.hh" -#include "cpu/profile.hh" -#include "cpu/sampler/sampler.hh" -#include "cpu/simple/cpu.hh" -#include "cpu/smt.hh" -#include "cpu/static_inst.hh" -#include "kern/kernel_stats.hh" -#include "mem/base_mem.hh" -#include "mem/mem_interface.hh" -#include "sim/byteswap.hh" -#include "sim/builder.hh" -#include "sim/debug.hh" -#include "sim/host.hh" -#include "sim/sim_events.hh" -#include "sim/sim_object.hh" -#include "sim/stats.hh" - -#if FULL_SYSTEM -#include "base/remote_gdb.hh" -#include "mem/functional/memory_control.hh" -#include "mem/functional/physical.hh" -#include "sim/system.hh" -#include "arch/tlb.hh" -#include "arch/stacktrace.hh" -#include "arch/vtophys.hh" -#else // !FULL_SYSTEM -#include "mem/functional/functional.hh" -#endif // FULL_SYSTEM - -using namespace std; -//The SimpleCPU does alpha only -using namespace AlphaISA; - - -SimpleCPU::TickEvent::TickEvent(SimpleCPU *c, int w) - : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c), width(w) -{ -} - - -void -SimpleCPU::init() -{ - BaseCPU::init(); -#if FULL_SYSTEM - for (int i = 0; i < execContexts.size(); ++i) { - ExecContext *xc = execContexts[i]; - - // initialize CPU, including PC - TheISA::initCPU(xc, xc->readCpuId()); - } -#endif -} - -void -SimpleCPU::TickEvent::process() -{ - int count = width; - do { - cpu->tick(); - } while (--count > 0 && cpu->status() == Running); -} - -const char * -SimpleCPU::TickEvent::description() -{ - return "SimpleCPU tick event"; -} - - -SimpleCPU::CacheCompletionEvent::CacheCompletionEvent(SimpleCPU *_cpu) - : Event(&mainEventQueue), cpu(_cpu) -{ -} - -void SimpleCPU::CacheCompletionEvent::process() -{ - cpu->processCacheCompletion(); -} - -const char * -SimpleCPU::CacheCompletionEvent::description() -{ - return "SimpleCPU cache completion event"; -} - -SimpleCPU::SimpleCPU(Params *p) - : BaseCPU(p), tickEvent(this, p->width), cpuXC(NULL), - cacheCompletionEvent(this) -{ - _status = Idle; -#if FULL_SYSTEM - cpuXC = new CPUExecContext(this, 0, p->system, p->itb, p->dtb, p->mem); - -#else - cpuXC = new CPUExecContext(this, /* thread_num */ 0, p->process, - /* asid */ 0); -#endif // !FULL_SYSTEM - cpuXC->setStatus(ExecContext::Suspended); - xcProxy = cpuXC->getProxy(); - - icacheInterface = p->icache_interface; - dcacheInterface = p->dcache_interface; - - memReq = new MemReq(); - memReq->xc = xcProxy; - memReq->asid = 0; - memReq->data = new uint8_t[64]; - - numInst = 0; - startNumInst = 0; - numLoad = 0; - startNumLoad = 0; - lastIcacheStall = 0; - lastDcacheStall = 0; - - execContexts.push_back(xcProxy); -} - -SimpleCPU::~SimpleCPU() -{ -} - -void -SimpleCPU::switchOut(Sampler *s) -{ - sampler = s; - if (status() == DcacheMissStall) { - DPRINTF(Sampler,"Outstanding dcache access, waiting for completion\n"); - _status = DcacheMissSwitch; - } - else { - _status = SwitchedOut; - - if (tickEvent.scheduled()) - tickEvent.squash(); - - sampler->signalSwitched(); - } -} - - -void -SimpleCPU::takeOverFrom(BaseCPU *oldCPU) -{ - BaseCPU::takeOverFrom(oldCPU); - - assert(!tickEvent.scheduled()); - - // if any of this CPU's ExecContexts are active, mark the CPU as - // running and schedule its tick event. - for (int i = 0; i < execContexts.size(); ++i) { - ExecContext *xc = execContexts[i]; - if (xc->status() == ExecContext::Active && _status != Running) { - _status = Running; - tickEvent.schedule(curTick); - } - } -} - - -void -SimpleCPU::activateContext(int thread_num, int delay) -{ - assert(thread_num == 0); - assert(cpuXC); - - assert(_status == Idle || _status == SwitchedOut); - notIdleFraction++; - scheduleTickEvent(delay); - _status = Running; -} - - -void -SimpleCPU::suspendContext(int thread_num) -{ - assert(thread_num == 0); - assert(cpuXC); - - assert(_status == Running || _status == SwitchedOut); - notIdleFraction--; - unscheduleTickEvent(); - _status = Idle; -} - - -void -SimpleCPU::deallocateContext(int thread_num) -{ - // for now, these are equivalent - suspendContext(thread_num); -} - - -void -SimpleCPU::haltContext(int thread_num) -{ - // for now, these are equivalent - suspendContext(thread_num); -} - - -void -SimpleCPU::regStats() -{ - using namespace Stats; - - BaseCPU::regStats(); - - numInsts - .name(name() + ".num_insts") - .desc("Number of instructions executed") - ; - - numMemRefs - .name(name() + ".num_refs") - .desc("Number of memory references") - ; - - notIdleFraction - .name(name() + ".not_idle_fraction") - .desc("Percentage of non-idle cycles") - ; - - idleFraction - .name(name() + ".idle_fraction") - .desc("Percentage of idle cycles") - ; - - icacheStallCycles - .name(name() + ".icache_stall_cycles") - .desc("ICache total stall cycles") - .prereq(icacheStallCycles) - ; - - dcacheStallCycles - .name(name() + ".dcache_stall_cycles") - .desc("DCache total stall cycles") - .prereq(dcacheStallCycles) - ; - - idleFraction = constant(1.0) - notIdleFraction; -} - -void -SimpleCPU::resetStats() -{ - startNumInst = numInst; - notIdleFraction = (_status != Idle); -} - -void -SimpleCPU::serialize(ostream &os) -{ - BaseCPU::serialize(os); - SERIALIZE_ENUM(_status); - SERIALIZE_SCALAR(inst); - nameOut(os, csprintf("%s.xc", name())); - cpuXC->serialize(os); - nameOut(os, csprintf("%s.tickEvent", name())); - tickEvent.serialize(os); - nameOut(os, csprintf("%s.cacheCompletionEvent", name())); - cacheCompletionEvent.serialize(os); -} - -void -SimpleCPU::unserialize(Checkpoint *cp, const string §ion) -{ - BaseCPU::unserialize(cp, section); - UNSERIALIZE_ENUM(_status); - UNSERIALIZE_SCALAR(inst); - cpuXC->unserialize(cp, csprintf("%s.xc", section)); - tickEvent.unserialize(cp, csprintf("%s.tickEvent", section)); - cacheCompletionEvent - .unserialize(cp, csprintf("%s.cacheCompletionEvent", section)); -} - -void -change_thread_state(int thread_number, int activate, int priority) -{ -} - -Fault -SimpleCPU::copySrcTranslate(Addr src) -{ - static bool no_warn = true; - int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; - // Only support block sizes of 64 atm. - assert(blk_size == 64); - int offset = src & (blk_size - 1); - - // Make sure block doesn't span page - if (no_warn && - (src & PageMask) != ((src + blk_size) & PageMask) && - (src >> 40) != 0xfffffc) { - warn("Copied block source spans pages %x.", src); - no_warn = false; - } - - memReq->reset(src & ~(blk_size - 1), blk_size); - - // translate to physical address - Fault fault = cpuXC->translateDataReadReq(memReq); - - if (fault == NoFault) { - cpuXC->copySrcAddr = src; - cpuXC->copySrcPhysAddr = memReq->paddr + offset; - } else { - assert(!fault->isAlignmentFault()); - - cpuXC->copySrcAddr = 0; - cpuXC->copySrcPhysAddr = 0; - } - return fault; -} - -Fault -SimpleCPU::copy(Addr dest) -{ - static bool no_warn = true; - int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; - // Only support block sizes of 64 atm. - assert(blk_size == 64); - uint8_t data[blk_size]; - //assert(cpuXC->copySrcAddr); - int offset = dest & (blk_size - 1); - - // Make sure block doesn't span page - if (no_warn && - (dest & PageMask) != ((dest + blk_size) & PageMask) && - (dest >> 40) != 0xfffffc) { - no_warn = false; - warn("Copied block destination spans pages %x. ", dest); - } - - memReq->reset(dest & ~(blk_size -1), blk_size); - // translate to physical address - Fault fault = cpuXC->translateDataWriteReq(memReq); - - if (fault == NoFault) { - Addr dest_addr = memReq->paddr + offset; - // Need to read straight from memory since we have more than 8 bytes. - memReq->paddr = cpuXC->copySrcPhysAddr; - cpuXC->mem->read(memReq, data); - memReq->paddr = dest_addr; - cpuXC->mem->write(memReq, data); - if (dcacheInterface) { - memReq->cmd = Copy; - memReq->completionEvent = NULL; - memReq->paddr = cpuXC->copySrcPhysAddr; - memReq->dest = dest_addr; - memReq->size = 64; - memReq->time = curTick; - memReq->flags &= ~INST_READ; - dcacheInterface->access(memReq); - } - } - else - assert(!fault->isAlignmentFault()); - - return fault; -} - -// precise architected memory state accessor macros -template <class T> -Fault -SimpleCPU::read(Addr addr, T &data, unsigned flags) -{ - if (status() == DcacheMissStall || status() == DcacheMissSwitch) { - Fault fault = cpuXC->read(memReq,data); - - if (traceData) { - traceData->setAddr(memReq->vaddr); - } - return fault; - } - - memReq->reset(addr, sizeof(T), flags); - - // translate to physical address - Fault fault = cpuXC->translateDataReadReq(memReq); - - // if we have a cache, do cache access too - if (fault == NoFault && dcacheInterface) { - memReq->cmd = Read; - memReq->completionEvent = NULL; - memReq->time = curTick; - memReq->flags &= ~INST_READ; - MemAccessResult result = dcacheInterface->access(memReq); - - // Ugly hack to get an event scheduled *only* if the access is - // a miss. We really should add first-class support for this - // at some point. - if (result != MA_HIT && dcacheInterface->doEvents()) { - memReq->completionEvent = &cacheCompletionEvent; - lastDcacheStall = curTick; - unscheduleTickEvent(); - _status = DcacheMissStall; - } else { - // do functional access - fault = cpuXC->read(memReq, data); - - } - } else if(fault == NoFault) { - // do functional access - fault = cpuXC->read(memReq, data); - - } - - if (!dcacheInterface && (memReq->flags & UNCACHEABLE)) - recordEvent("Uncached Read"); - - return fault; -} - -#ifndef DOXYGEN_SHOULD_SKIP_THIS - -template -Fault -SimpleCPU::read(Addr addr, uint64_t &data, unsigned flags); - -template -Fault -SimpleCPU::read(Addr addr, uint32_t &data, unsigned flags); - -template -Fault -SimpleCPU::read(Addr addr, uint16_t &data, unsigned flags); - -template -Fault -SimpleCPU::read(Addr addr, uint8_t &data, unsigned flags); - -#endif //DOXYGEN_SHOULD_SKIP_THIS - -template<> -Fault -SimpleCPU::read(Addr addr, double &data, unsigned flags) -{ - return read(addr, *(uint64_t*)&data, flags); -} - -template<> -Fault -SimpleCPU::read(Addr addr, float &data, unsigned flags) -{ - return read(addr, *(uint32_t*)&data, flags); -} - - -template<> -Fault -SimpleCPU::read(Addr addr, int32_t &data, unsigned flags) -{ - return read(addr, (uint32_t&)data, flags); -} - - -template <class T> -Fault -SimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) -{ - memReq->reset(addr, sizeof(T), flags); - - // translate to physical address - Fault fault = cpuXC->translateDataWriteReq(memReq); - - // do functional access - if (fault == NoFault) - fault = cpuXC->write(memReq, data); - - if (fault == NoFault && dcacheInterface) { - memReq->cmd = Write; - memcpy(memReq->data,(uint8_t *)&data,memReq->size); - memReq->completionEvent = NULL; - memReq->time = curTick; - memReq->flags &= ~INST_READ; - MemAccessResult result = dcacheInterface->access(memReq); - - // Ugly hack to get an event scheduled *only* if the access is - // a miss. We really should add first-class support for this - // at some point. - if (result != MA_HIT && dcacheInterface->doEvents()) { - memReq->completionEvent = &cacheCompletionEvent; - lastDcacheStall = curTick; - unscheduleTickEvent(); - _status = DcacheMissStall; - } - } - - if (res && (fault == NoFault)) - *res = memReq->result; - - if (!dcacheInterface && (memReq->flags & UNCACHEABLE)) - recordEvent("Uncached Write"); - - return fault; -} - - -#ifndef DOXYGEN_SHOULD_SKIP_THIS -template -Fault -SimpleCPU::write(uint64_t data, Addr addr, unsigned flags, uint64_t *res); - -template -Fault -SimpleCPU::write(uint32_t data, Addr addr, unsigned flags, uint64_t *res); - -template -Fault -SimpleCPU::write(uint16_t data, Addr addr, unsigned flags, uint64_t *res); - -template -Fault -SimpleCPU::write(uint8_t data, Addr addr, unsigned flags, uint64_t *res); - -#endif //DOXYGEN_SHOULD_SKIP_THIS - -template<> -Fault -SimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) -{ - return write(*(uint64_t*)&data, addr, flags, res); -} - -template<> -Fault -SimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) -{ - return write(*(uint32_t*)&data, addr, flags, res); -} - - -template<> -Fault -SimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) -{ - return write((uint32_t)data, addr, flags, res); -} - - -#if FULL_SYSTEM -Addr -SimpleCPU::dbg_vtophys(Addr addr) -{ - return vtophys(xcProxy, addr); -} -#endif // FULL_SYSTEM - -void -SimpleCPU::processCacheCompletion() -{ - switch (status()) { - case IcacheMissStall: - icacheStallCycles += curTick - lastIcacheStall; - _status = IcacheMissComplete; - scheduleTickEvent(1); - break; - case DcacheMissStall: - if (memReq->cmd.isRead()) { - curStaticInst->execute(this,traceData); - if (traceData) - traceData->finalize(); - } - dcacheStallCycles += curTick - lastDcacheStall; - _status = Running; - scheduleTickEvent(1); - break; - case DcacheMissSwitch: - if (memReq->cmd.isRead()) { - curStaticInst->execute(this,traceData); - if (traceData) - traceData->finalize(); - } - _status = SwitchedOut; - sampler->signalSwitched(); - case SwitchedOut: - // If this CPU has been switched out due to sampling/warm-up, - // ignore any further status changes (e.g., due to cache - // misses outstanding at the time of the switch). - return; - default: - panic("SimpleCPU::processCacheCompletion: bad state"); - break; - } -} - -#if FULL_SYSTEM -void -SimpleCPU::post_interrupt(int int_num, int index) -{ - BaseCPU::post_interrupt(int_num, index); - - if (cpuXC->status() == ExecContext::Suspended) { - DPRINTF(IPI,"Suspended Processor awoke\n"); - cpuXC->activate(); - } -} -#endif // FULL_SYSTEM - -/* start simulation, program loaded, processor precise state initialized */ -void -SimpleCPU::tick() -{ - numCycles++; - - traceData = NULL; - - Fault fault = NoFault; - -#if FULL_SYSTEM - if (checkInterrupts && check_interrupts() && !cpuXC->inPalMode() && - status() != IcacheMissComplete) { - int ipl = 0; - int summary = 0; - checkInterrupts = false; - - if (cpuXC->readMiscReg(IPR_SIRR)) { - for (int i = INTLEVEL_SOFTWARE_MIN; - i < INTLEVEL_SOFTWARE_MAX; i++) { - if (cpuXC->readMiscReg(IPR_SIRR) & (ULL(1) << i)) { - // See table 4-19 of 21164 hardware reference - ipl = (i - INTLEVEL_SOFTWARE_MIN) + 1; - summary |= (ULL(1) << i); - } - } - } - - uint64_t interrupts = cpuXC->cpu->intr_status(); - for (int i = INTLEVEL_EXTERNAL_MIN; - i < INTLEVEL_EXTERNAL_MAX; i++) { - if (interrupts & (ULL(1) << i)) { - // See table 4-19 of 21164 hardware reference - ipl = i; - summary |= (ULL(1) << i); - } - } - - if (cpuXC->readMiscReg(IPR_ASTRR)) - panic("asynchronous traps not implemented\n"); - - if (ipl && ipl > cpuXC->readMiscReg(IPR_IPLR)) { - cpuXC->setMiscReg(IPR_ISR, summary); - cpuXC->setMiscReg(IPR_INTID, ipl); - - Fault(new InterruptFault)->invoke(xcProxy); - - DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n", - cpuXC->readMiscReg(IPR_IPLR), ipl, summary); - } - } -#endif - - // maintain $r0 semantics - cpuXC->setIntReg(ZeroReg, 0); -#ifdef TARGET_ALPHA - cpuXC->setFloatRegDouble(ZeroReg, 0.0); -#endif // TARGET_ALPHA - - if (status() == IcacheMissComplete) { - // We've already fetched an instruction and were stalled on an - // I-cache miss. No need to fetch it again. - - // Set status to running; tick event will get rescheduled if - // necessary at end of tick() function. - _status = Running; - } - else { - // Try to fetch an instruction - - // set up memory request for instruction fetch -#if FULL_SYSTEM -#define IFETCH_FLAGS(pc) ((pc) & 1) ? PHYSICAL : 0 -#else -#define IFETCH_FLAGS(pc) 0 -#endif - - memReq->cmd = Read; - memReq->reset(cpuXC->readPC() & ~3, sizeof(uint32_t), - IFETCH_FLAGS(cpuXC->readPC())); - - fault = cpuXC->translateInstReq(memReq); - - if (fault == NoFault) - fault = cpuXC->mem->read(memReq, inst); - - if (icacheInterface && fault == NoFault) { - memReq->completionEvent = NULL; - - memReq->time = curTick; - memReq->flags |= INST_READ; - MemAccessResult result = icacheInterface->access(memReq); - - // Ugly hack to get an event scheduled *only* if the access is - // a miss. We really should add first-class support for this - // at some point. - if (result != MA_HIT && icacheInterface->doEvents()) { - memReq->completionEvent = &cacheCompletionEvent; - lastIcacheStall = curTick; - unscheduleTickEvent(); - _status = IcacheMissStall; - return; - } - } - } - - // If we've got a valid instruction (i.e., no fault on instruction - // fetch), then execute it. - if (fault == NoFault) { - - // keep an instruction count - numInst++; - numInsts++; - - // check for instruction-count-based events - comInstEventQueue[0]->serviceEvents(numInst); - - // decode the instruction - inst = gtoh(inst); - curStaticInst = StaticInst::decode(makeExtMI(inst, cpuXC->readPC())); - - traceData = Trace::getInstRecord(curTick, xcProxy, this, curStaticInst, - cpuXC->readPC()); - -#if FULL_SYSTEM - cpuXC->setInst(inst); -#endif // FULL_SYSTEM - - cpuXC->func_exe_inst++; - - fault = curStaticInst->execute(this, traceData); - -#if FULL_SYSTEM - if (system->kernelBinning->fnbin) { - assert(cpuXC->getKernelStats()); - system->kernelBinning->execute(xcProxy, inst); - } - - if (cpuXC->profile) { - bool usermode = - (cpuXC->readMiscReg(AlphaISA::IPR_DTB_CM) & 0x18) != 0; - cpuXC->profilePC = usermode ? 1 : cpuXC->readPC(); - ProfileNode *node = cpuXC->profile->consume(xcProxy, inst); - if (node) - cpuXC->profileNode = node; - } -#endif - - if (curStaticInst->isMemRef()) { - numMemRefs++; - } - - if (curStaticInst->isLoad()) { - ++numLoad; - comLoadEventQueue[0]->serviceEvents(numLoad); - } - - // If we have a dcache miss, then we can't finialize the instruction - // trace yet because we want to populate it with the data later - if (traceData && - !(status() == DcacheMissStall && memReq->cmd.isRead())) { - traceData->finalize(); - } - - traceFunctions(cpuXC->readPC()); - - } // if (fault == NoFault) - - if (fault != NoFault) { -#if FULL_SYSTEM - fault->invoke(xcProxy); -#else // !FULL_SYSTEM - fatal("fault (%d) detected @ PC 0x%08p", fault, cpuXC->readPC()); -#endif // FULL_SYSTEM - } - else { -#if THE_ISA != MIPS_ISA - // go to the next instruction - cpuXC->setPC(cpuXC->readNextPC()); - cpuXC->setNextPC(cpuXC->readNextPC() + sizeof(MachInst)); -#else - // go to the next instruction - cpuXC->setPC(cpuXC->readNextPC()); - cpuXC->setNextPC(cpuXC->readNextNPC()); - cpuXC->setNextNPC(cpuXC->readNextNPC() + sizeof(MachInst)); -#endif - - } - -#if FULL_SYSTEM - Addr oldpc; - do { - oldpc = cpuXC->readPC(); - system->pcEventQueue.service(xcProxy); - } while (oldpc != cpuXC->readPC()); -#endif - - assert(status() == Running || - status() == Idle || - status() == DcacheMissStall); - - if (status() == Running && !tickEvent.scheduled()) - tickEvent.schedule(curTick + cycles(1)); -} - -//////////////////////////////////////////////////////////////////////// -// -// SimpleCPU Simulation Object -// -BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU) - - Param<Counter> max_insts_any_thread; - Param<Counter> max_insts_all_threads; - Param<Counter> max_loads_any_thread; - Param<Counter> max_loads_all_threads; - -#if FULL_SYSTEM - SimObjectParam<AlphaITB *> itb; - SimObjectParam<AlphaDTB *> dtb; - SimObjectParam<FunctionalMemory *> mem; - SimObjectParam<System *> system; - Param<int> cpu_id; - Param<Tick> profile; -#else - SimObjectParam<Process *> workload; -#endif // FULL_SYSTEM - - Param<int> clock; - SimObjectParam<BaseMem *> icache; - SimObjectParam<BaseMem *> dcache; - - Param<bool> defer_registration; - Param<int> width; - Param<bool> function_trace; - Param<Tick> function_trace_start; - -END_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU) - -BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleCPU) - - INIT_PARAM(max_insts_any_thread, - "terminate when any thread reaches this inst count"), - INIT_PARAM(max_insts_all_threads, - "terminate when all threads have reached this inst count"), - INIT_PARAM(max_loads_any_thread, - "terminate when any thread reaches this load count"), - INIT_PARAM(max_loads_all_threads, - "terminate when all threads have reached this load count"), - -#if FULL_SYSTEM - INIT_PARAM(itb, "Instruction TLB"), - INIT_PARAM(dtb, "Data TLB"), - INIT_PARAM(mem, "memory"), - INIT_PARAM(system, "system object"), - INIT_PARAM(cpu_id, "processor ID"), - INIT_PARAM(profile, ""), -#else - INIT_PARAM(workload, "processes to run"), -#endif // FULL_SYSTEM - - INIT_PARAM(clock, "clock speed"), - INIT_PARAM(icache, "L1 instruction cache object"), - INIT_PARAM(dcache, "L1 data cache object"), - INIT_PARAM(defer_registration, "defer system registration (for sampling)"), - INIT_PARAM(width, "cpu width"), - INIT_PARAM(function_trace, "Enable function trace"), - INIT_PARAM(function_trace_start, "Cycle to start function trace") - -END_INIT_SIM_OBJECT_PARAMS(SimpleCPU) - - -CREATE_SIM_OBJECT(SimpleCPU) -{ - SimpleCPU::Params *params = new SimpleCPU::Params(); - params->name = getInstanceName(); - params->numberOfThreads = 1; - params->max_insts_any_thread = max_insts_any_thread; - params->max_insts_all_threads = max_insts_all_threads; - params->max_loads_any_thread = max_loads_any_thread; - params->max_loads_all_threads = max_loads_all_threads; - params->deferRegistration = defer_registration; - params->clock = clock; - params->functionTrace = function_trace; - params->functionTraceStart = function_trace_start; - params->icache_interface = (icache) ? icache->getInterface() : NULL; - params->dcache_interface = (dcache) ? dcache->getInterface() : NULL; - params->width = width; - -#if FULL_SYSTEM - params->itb = itb; - params->dtb = dtb; - params->mem = mem; - params->system = system; - params->cpu_id = cpu_id; - params->profile = profile; -#else - params->process = workload; -#endif - - SimpleCPU *cpu = new SimpleCPU(params); - return cpu; -} - -REGISTER_SIM_OBJECT("SimpleCPU", SimpleCPU) - diff --git a/cpu/simple/cpu.hh b/cpu/simple/cpu.hh deleted file mode 100644 index 4ab9a1c3e..000000000 --- a/cpu/simple/cpu.hh +++ /dev/null @@ -1,363 +0,0 @@ -/* - * Copyright (c) 2002-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_SIMPLE_CPU_SIMPLE_CPU_HH__ -#define __CPU_SIMPLE_CPU_SIMPLE_CPU_HH__ - -#include "base/statistics.hh" -#include "config/full_system.hh" -#include "cpu/base.hh" -#include "cpu/cpu_exec_context.hh" -#include "cpu/pc_event.hh" -#include "cpu/sampler/sampler.hh" -#include "cpu/static_inst.hh" -#include "sim/eventq.hh" - -// forward declarations -#if FULL_SYSTEM -class Processor; -class AlphaITB; -class AlphaDTB; -class PhysicalMemory; - -class RemoteGDB; -class GDBListener; - -#else - -class Process; - -#endif // FULL_SYSTEM - -class ExecContext; -class MemInterface; -class Checkpoint; - -namespace Trace { - class InstRecord; -} - -class SimpleCPU : public BaseCPU -{ - protected: - typedef TheISA::MachInst MachInst; - typedef TheISA::MiscReg MiscReg; - public: - // main simulation loop (one cycle) - void tick(); - virtual void init(); - - private: - struct TickEvent : public Event - { - SimpleCPU *cpu; - int width; - - TickEvent(SimpleCPU *c, int w); - void process(); - const char *description(); - }; - - TickEvent tickEvent; - - /// Schedule tick event, regardless of its current state. - void scheduleTickEvent(int numCycles) - { - if (tickEvent.squashed()) - tickEvent.reschedule(curTick + cycles(numCycles)); - else if (!tickEvent.scheduled()) - tickEvent.schedule(curTick + cycles(numCycles)); - } - - /// Unschedule tick event, regardless of its current state. - void unscheduleTickEvent() - { - if (tickEvent.scheduled()) - tickEvent.squash(); - } - - private: - Trace::InstRecord *traceData; - - public: - // - enum Status { - Running, - Idle, - IcacheMissStall, - IcacheMissComplete, - DcacheMissStall, - DcacheMissSwitch, - SwitchedOut - }; - - private: - Status _status; - - public: - void post_interrupt(int int_num, int index); - - void zero_fill_64(Addr addr) { - static int warned = 0; - if (!warned) { - warn ("WH64 is not implemented"); - warned = 1; - } - }; - - public: - struct Params : public BaseCPU::Params - { - MemInterface *icache_interface; - MemInterface *dcache_interface; - int width; -#if FULL_SYSTEM - AlphaITB *itb; - AlphaDTB *dtb; - FunctionalMemory *mem; -#else - Process *process; -#endif - }; - SimpleCPU(Params *params); - virtual ~SimpleCPU(); - - public: - // execution context - CPUExecContext *cpuXC; - - ExecContext *xcProxy; - - void switchOut(Sampler *s); - void takeOverFrom(BaseCPU *oldCPU); - -#if FULL_SYSTEM - Addr dbg_vtophys(Addr addr); - - bool interval_stats; -#endif - - // L1 instruction cache - MemInterface *icacheInterface; - - // L1 data cache - MemInterface *dcacheInterface; - - // current instruction - MachInst inst; - - // Refcounted pointer to the one memory request. - MemReqPtr memReq; - - // Pointer to the sampler that is telling us to switchover. - // Used to signal the completion of the pipe drain and schedule - // the next switchover - Sampler *sampler; - - StaticInstPtr curStaticInst; - - class CacheCompletionEvent : public Event - { - private: - SimpleCPU *cpu; - - public: - CacheCompletionEvent(SimpleCPU *_cpu); - - virtual void process(); - virtual const char *description(); - }; - - CacheCompletionEvent cacheCompletionEvent; - - Status status() const { return _status; } - - virtual void activateContext(int thread_num, int delay); - virtual void suspendContext(int thread_num); - virtual void deallocateContext(int thread_num); - virtual void haltContext(int thread_num); - - // statistics - virtual void regStats(); - virtual void resetStats(); - - // number of simulated instructions - Counter numInst; - Counter startNumInst; - Stats::Scalar<> numInsts; - - virtual Counter totalInstructions() const - { - return numInst - startNumInst; - } - - // number of simulated memory references - Stats::Scalar<> numMemRefs; - - // number of simulated loads - Counter numLoad; - Counter startNumLoad; - - // number of idle cycles - Stats::Average<> notIdleFraction; - Stats::Formula idleFraction; - - // number of cycles stalled for I-cache misses - Stats::Scalar<> icacheStallCycles; - Counter lastIcacheStall; - - // number of cycles stalled for D-cache misses - Stats::Scalar<> dcacheStallCycles; - Counter lastDcacheStall; - - void processCacheCompletion(); - - virtual void serialize(std::ostream &os); - virtual void unserialize(Checkpoint *cp, const std::string §ion); - - template <class T> - Fault read(Addr addr, T &data, unsigned flags); - - template <class T> - Fault write(T data, Addr addr, unsigned flags, uint64_t *res); - - // These functions are only used in CPU models that split - // effective address computation from the actual memory access. - void setEA(Addr EA) { panic("SimpleCPU::setEA() not implemented\n"); } - Addr getEA() { panic("SimpleCPU::getEA() not implemented\n"); } - - void prefetch(Addr addr, unsigned flags) - { - // need to do this... - } - - void writeHint(Addr addr, int size, unsigned flags) - { - // need to do this... - } - - Fault copySrcTranslate(Addr src); - - Fault copy(Addr dest); - - // The register accessor methods provide the index of the - // instruction's operand (e.g., 0 or 1), not the architectural - // register index, to simplify the implementation of register - // renaming. We find the architectural register index by indexing - // into the instruction's own operand index table. Note that a - // raw pointer to the StaticInst is provided instead of a - // ref-counted StaticInstPtr to redice overhead. This is fine as - // long as these methods don't copy the pointer into any long-term - // storage (which is pretty hard to imagine they would have reason - // to do). - - uint64_t readIntReg(const StaticInst *si, int idx) - { - return cpuXC->readIntReg(si->srcRegIdx(idx)); - } - - float readFloatRegSingle(const StaticInst *si, int idx) - { - int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag; - return cpuXC->readFloatRegSingle(reg_idx); - } - - double readFloatRegDouble(const StaticInst *si, int idx) - { - int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag; - return cpuXC->readFloatRegDouble(reg_idx); - } - - uint64_t readFloatRegInt(const StaticInst *si, int idx) - { - int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag; - return cpuXC->readFloatRegInt(reg_idx); - } - - void setIntReg(const StaticInst *si, int idx, uint64_t val) - { - cpuXC->setIntReg(si->destRegIdx(idx), val); - } - - void setFloatRegSingle(const StaticInst *si, int idx, float val) - { - int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag; - cpuXC->setFloatRegSingle(reg_idx, val); - } - - void setFloatRegDouble(const StaticInst *si, int idx, double val) - { - int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag; - cpuXC->setFloatRegDouble(reg_idx, val); - } - - void setFloatRegInt(const StaticInst *si, int idx, uint64_t val) - { - int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag; - cpuXC->setFloatRegInt(reg_idx, val); - } - - uint64_t readPC() { return cpuXC->readPC(); } - void setNextPC(uint64_t val) { cpuXC->setNextPC(val); } - - MiscReg readMiscReg(int misc_reg) - { - return cpuXC->readMiscReg(misc_reg); - } - - MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault) - { - return cpuXC->readMiscRegWithEffect(misc_reg, fault); - } - - Fault setMiscReg(int misc_reg, const MiscReg &val) - { - return cpuXC->setMiscReg(misc_reg, val); - } - - Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val) - { - return cpuXC->setMiscRegWithEffect(misc_reg, val); - } - -#if FULL_SYSTEM - Fault hwrei() { return cpuXC->hwrei(); } - int readIntrFlag() { return cpuXC->readIntrFlag(); } - void setIntrFlag(int val) { cpuXC->setIntrFlag(val); } - bool inPalMode() { return cpuXC->inPalMode(); } - void ev5_trap(Fault fault) { fault->invoke(xcProxy); } - bool simPalCheck(int palFunc) { return cpuXC->simPalCheck(palFunc); } -#else - void syscall() { cpuXC->syscall(); } -#endif - - bool misspeculating() { return cpuXC->misspeculating(); } - ExecContext *xcBase() { return xcProxy; } -}; - -#endif // __CPU_SIMPLE_CPU_SIMPLE_CPU_HH__ diff --git a/cpu/static_inst.hh b/cpu/static_inst.hh deleted file mode 100644 index b9d782b7b..000000000 --- a/cpu/static_inst.hh +++ /dev/null @@ -1,475 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_STATIC_INST_HH__ -#define __CPU_STATIC_INST_HH__ - -#include <bitset> -#include <string> - -#include "base/hashmap.hh" -#include "base/refcnt.hh" -#include "encumbered/cpu/full/op_class.hh" -#include "sim/host.hh" -#include "arch/isa_traits.hh" - -// forward declarations -struct AlphaSimpleImpl; -struct OzoneImpl; -struct SimpleImpl; -class ExecContext; -class DynInst; - -template <class Impl> -class AlphaDynInst; - -template <class Impl> -class OzoneDynInst; - -class CheckerCPU; -class FastCPU; -class SimpleCPU; -class InorderCPU; -class SymbolTable; - -namespace Trace { - class InstRecord; -} - -/** - * Base, ISA-independent static instruction class. - * - * The main component of this class is the vector of flags and the - * associated methods for reading them. Any object that can rely - * solely on these flags can process instructions without being - * recompiled for multiple ISAs. - */ -class StaticInstBase : public RefCounted -{ - protected: - - /// Set of boolean static instruction properties. - /// - /// Notes: - /// - The IsInteger and IsFloating flags are based on the class of - /// registers accessed by the instruction. Although most - /// instructions will have exactly one of these two flags set, it - /// is possible for an instruction to have neither (e.g., direct - /// unconditional branches, memory barriers) or both (e.g., an - /// FP/int conversion). - /// - If IsMemRef is set, then exactly one of IsLoad or IsStore - /// will be set. - /// - If IsControl is set, then exactly one of IsDirectControl or - /// IsIndirect Control will be set, and exactly one of - /// IsCondControl or IsUncondControl will be set. - /// - IsSerializing, IsMemBarrier, and IsWriteBarrier are - /// implemented as flags since in the current model there's no - /// other way for instructions to inject behavior into the - /// pipeline outside of fetch. Once we go to an exec-in-exec CPU - /// model we should be able to get rid of these flags and - /// implement this behavior via the execute() methods. - /// - enum Flags { - IsNop, ///< Is a no-op (no effect at all). - - IsInteger, ///< References integer regs. - IsFloating, ///< References FP regs. - - IsMemRef, ///< References memory (load, store, or prefetch). - IsLoad, ///< Reads from memory (load or prefetch). - IsStore, ///< Writes to memory. - IsStoreConditional, ///< Store conditional instruction. - IsInstPrefetch, ///< Instruction-cache prefetch. - IsDataPrefetch, ///< Data-cache prefetch. - IsCopy, ///< Fast Cache block copy - - IsControl, ///< Control transfer instruction. - IsDirectControl, ///< PC relative control transfer. - IsIndirectControl, ///< Register indirect control transfer. - IsCondControl, ///< Conditional control transfer. - IsUncondControl, ///< Unconditional control transfer. - IsCall, ///< Subroutine call. - IsReturn, ///< Subroutine return. - - IsCondDelaySlot,///< Conditional Delay-Slot Instruction - - IsThreadSync, ///< Thread synchronization operation. - - IsSerializing, ///< Serializes pipeline: won't execute until all - /// older instructions have committed. - IsSerializeBefore, - IsSerializeAfter, - IsMemBarrier, ///< Is a memory barrier - IsWriteBarrier, ///< Is a write barrier - - IsNonSpeculative, ///< Should not be executed speculatively - IsQuiesce, ///< Is a quiesce instruction - - IsIprAccess, ///< Accesses IPRs - IsUnverifiable, ///< Can't be verified by a checker - - NumFlags - }; - - /// Flag values for this instruction. - std::bitset<NumFlags> flags; - - /// See opClass(). - OpClass _opClass; - - /// See numSrcRegs(). - int8_t _numSrcRegs; - - /// See numDestRegs(). - int8_t _numDestRegs; - - /// The following are used to track physical register usage - /// for machines with separate int & FP reg files. - //@{ - int8_t _numFPDestRegs; - int8_t _numIntDestRegs; - //@} - - /// Constructor. - /// It's important to initialize everything here to a sane - /// default, since the decoder generally only overrides - /// the fields that are meaningful for the particular - /// instruction. - StaticInstBase(OpClass __opClass) - : _opClass(__opClass), _numSrcRegs(0), _numDestRegs(0), - _numFPDestRegs(0), _numIntDestRegs(0) - { - } - - public: - - /// @name Register information. - /// The sum of numFPDestRegs() and numIntDestRegs() equals - /// numDestRegs(). The former two functions are used to track - /// physical register usage for machines with separate int & FP - /// reg files. - //@{ - /// Number of source registers. - int8_t numSrcRegs() const { return _numSrcRegs; } - /// Number of destination registers. - int8_t numDestRegs() const { return _numDestRegs; } - /// Number of floating-point destination regs. - int8_t numFPDestRegs() const { return _numFPDestRegs; } - /// Number of integer destination regs. - int8_t numIntDestRegs() const { return _numIntDestRegs; } - //@} - - /// @name Flag accessors. - /// These functions are used to access the values of the various - /// instruction property flags. See StaticInstBase::Flags for descriptions - /// of the individual flags. - //@{ - - bool isNop() const { return flags[IsNop]; } - - bool isMemRef() const { return flags[IsMemRef]; } - bool isLoad() const { return flags[IsLoad]; } - bool isStore() const { return flags[IsStore]; } - bool isStoreConditional() const { return flags[IsStoreConditional]; } - bool isInstPrefetch() const { return flags[IsInstPrefetch]; } - bool isDataPrefetch() const { return flags[IsDataPrefetch]; } - bool isCopy() const { return flags[IsCopy];} - - bool isInteger() const { return flags[IsInteger]; } - bool isFloating() const { return flags[IsFloating]; } - - bool isControl() const { return flags[IsControl]; } - bool isCall() const { return flags[IsCall]; } - bool isReturn() const { return flags[IsReturn]; } - bool isDirectCtrl() const { return flags[IsDirectControl]; } - bool isIndirectCtrl() const { return flags[IsIndirectControl]; } - bool isCondCtrl() const { return flags[IsCondControl]; } - bool isUncondCtrl() const { return flags[IsUncondControl]; } - - bool isThreadSync() const { return flags[IsThreadSync]; } - bool isSerializing() const { return flags[IsSerializing] || - flags[IsSerializeBefore] || - flags[IsSerializeAfter]; } - bool isSerializeBefore() const { return flags[IsSerializeBefore]; } - bool isSerializeAfter() const { return flags[IsSerializeAfter]; } - bool isMemBarrier() const { return flags[IsMemBarrier]; } - bool isWriteBarrier() const { return flags[IsWriteBarrier]; } - bool isNonSpeculative() const { return flags[IsNonSpeculative]; } - bool isQuiesce() const { return flags[IsQuiesce]; } - bool isIprAccess() const { return flags[IsIprAccess]; } - bool isUnverifiable() const { return flags[IsUnverifiable]; } - //@} - - /// Operation class. Used to select appropriate function unit in issue. - OpClass opClass() const { return _opClass; } -}; - - -// forward declaration -class StaticInstPtr; - -/** - * Generic yet ISA-dependent static instruction class. - * - * This class builds on StaticInstBase, defining fields and interfaces - * that are generic across all ISAs but that differ in details - * according to the specific ISA being used. - */ -class StaticInst : public StaticInstBase -{ - public: - - /// Binary machine instruction type. - typedef TheISA::MachInst MachInst; - /// Binary extended machine instruction type. - typedef TheISA::ExtMachInst ExtMachInst; - /// Logical register index type. - typedef TheISA::RegIndex RegIndex; - - enum { - MaxInstSrcRegs = TheISA::MaxInstSrcRegs, //< Max source regs - MaxInstDestRegs = TheISA::MaxInstDestRegs, //< Max dest regs - }; - - - /// Return logical index (architectural reg num) of i'th destination reg. - /// Only the entries from 0 through numDestRegs()-1 are valid. - RegIndex destRegIdx(int i) const { return _destRegIdx[i]; } - - /// Return logical index (architectural reg num) of i'th source reg. - /// Only the entries from 0 through numSrcRegs()-1 are valid. - RegIndex srcRegIdx(int i) const { return _srcRegIdx[i]; } - - /// Pointer to a statically allocated "null" instruction object. - /// Used to give eaCompInst() and memAccInst() something to return - /// when called on non-memory instructions. - static StaticInstPtr nullStaticInstPtr; - - /** - * Memory references only: returns "fake" instruction representing - * the effective address part of the memory operation. Used to - * obtain the dependence info (numSrcRegs and srcRegIdx[]) for - * just the EA computation. - */ - virtual const - StaticInstPtr &eaCompInst() const { return nullStaticInstPtr; } - - /** - * Memory references only: returns "fake" instruction representing - * the memory access part of the memory operation. Used to - * obtain the dependence info (numSrcRegs and srcRegIdx[]) for - * just the memory access (not the EA computation). - */ - virtual const - StaticInstPtr &memAccInst() const { return nullStaticInstPtr; } - - /// The binary machine instruction. - const ExtMachInst machInst; - - protected: - - /// See destRegIdx(). - RegIndex _destRegIdx[MaxInstDestRegs]; - /// See srcRegIdx(). - RegIndex _srcRegIdx[MaxInstSrcRegs]; - - /** - * Base mnemonic (e.g., "add"). Used by generateDisassembly() - * methods. Also useful to readily identify instructions from - * within the debugger when #cachedDisassembly has not been - * initialized. - */ - const char *mnemonic; - - /** - * String representation of disassembly (lazily evaluated via - * disassemble()). - */ - mutable std::string *cachedDisassembly; - - /** - * Internal function to generate disassembly string. - */ - virtual std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const = 0; - - /// Constructor. - StaticInst(const char *_mnemonic, ExtMachInst _machInst, OpClass __opClass) - : StaticInstBase(__opClass), - machInst(_machInst), mnemonic(_mnemonic), cachedDisassembly(0) - { - } - - public: - - virtual ~StaticInst() - { - if (cachedDisassembly) - delete cachedDisassembly; - } - -/** - * The execute() signatures are auto-generated by scons based on the - * set of CPU models we are compiling in today. - */ -#include "cpu/static_inst_exec_sigs.hh" - - /** - * Return the target address for a PC-relative branch. - * Invalid if not a PC-relative branch (i.e. isDirectCtrl() - * should be true). - */ - virtual Addr branchTarget(Addr branchPC) const - { - panic("StaticInst::branchTarget() called on instruction " - "that is not a PC-relative branch."); - } - - /** - * Return the target address for an indirect branch (jump). The - * register value is read from the supplied execution context, so - * the result is valid only if the execution context is about to - * execute the branch in question. Invalid if not an indirect - * branch (i.e. isIndirectCtrl() should be true). - */ - virtual Addr branchTarget(ExecContext *xc) const - { - panic("StaticInst::branchTarget() called on instruction " - "that is not an indirect branch."); - } - - /** - * Return true if the instruction is a control transfer, and if so, - * return the target address as well. - */ - bool hasBranchTarget(Addr pc, ExecContext *xc, Addr &tgt) const; - - /** - * Return string representation of disassembled instruction. - * The default version of this function will call the internal - * virtual generateDisassembly() function to get the string, - * then cache it in #cachedDisassembly. If the disassembly - * should not be cached, this function should be overridden directly. - */ - virtual const std::string &disassemble(Addr pc, - const SymbolTable *symtab = 0) const - { - if (!cachedDisassembly) - cachedDisassembly = - new std::string(generateDisassembly(pc, symtab)); - - return *cachedDisassembly; - } - - /// Decoded instruction cache type. - /// For now we're using a generic hash_map; this seems to work - /// pretty well. - typedef m5::hash_map<ExtMachInst, StaticInstPtr> DecodeCache; - - /// A cache of decoded instruction objects. - static DecodeCache decodeCache; - - /** - * Dump some basic stats on the decode cache hash map. - * Only gets called if DECODE_CACHE_HASH_STATS is defined. - */ - static void dumpDecodeCacheStats(); - - /// Decode a machine instruction. - /// @param mach_inst The binary instruction to decode. - /// @retval A pointer to the corresponding StaticInst object. - //This is defined as inline below. - static StaticInstPtr decode(ExtMachInst mach_inst); -}; - -typedef RefCountingPtr<StaticInstBase> StaticInstBasePtr; - -/// Reference-counted pointer to a StaticInst object. -/// This type should be used instead of "StaticInst *" so that -/// StaticInst objects can be properly reference-counted. -class StaticInstPtr : public RefCountingPtr<StaticInst> -{ - public: - /// Constructor. - StaticInstPtr() - : RefCountingPtr<StaticInst>() - { - } - - /// Conversion from "StaticInst *". - StaticInstPtr(StaticInst *p) - : RefCountingPtr<StaticInst>(p) - { - } - - /// Copy constructor. - StaticInstPtr(const StaticInstPtr &r) - : RefCountingPtr<StaticInst>(r) - { - } - - /// Construct directly from machine instruction. - /// Calls StaticInst::decode(). - StaticInstPtr(TheISA::ExtMachInst mach_inst) - : RefCountingPtr<StaticInst>(StaticInst::decode(mach_inst)) - { - } - - /// Convert to pointer to StaticInstBase class. - operator const StaticInstBasePtr() - { - return this->get(); - } -}; - -inline StaticInstPtr -StaticInst::decode(StaticInst::ExtMachInst mach_inst) -{ -#ifdef DECODE_CACHE_HASH_STATS - // Simple stats on decode hash_map. Turns out the default - // hash function is as good as anything I could come up with. - const int dump_every_n = 10000000; - static int decodes_til_dump = dump_every_n; - - if (--decodes_til_dump == 0) { - dumpDecodeCacheStats(); - decodes_til_dump = dump_every_n; - } -#endif - - DecodeCache::iterator iter = decodeCache.find(mach_inst); - if (iter != decodeCache.end()) { - return iter->second; - } - - StaticInstPtr si = TheISA::decodeInst(mach_inst); - decodeCache[mach_inst] = si; - return si; -} - -#endif // __CPU_STATIC_INST_HH__ diff --git a/dev/alpha_console.cc b/dev/alpha_console.cc deleted file mode 100644 index 6ca5e3a06..000000000 --- a/dev/alpha_console.cc +++ /dev/null @@ -1,356 +0,0 @@ -/* - * Copyright (c) 2001-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** @file - * Alpha Console Definition - */ - -#include <cstddef> -#include <cstdio> -#include <string> - -#include "arch/alpha/system.hh" -#include "base/inifile.hh" -#include "base/str.hh" -#include "base/trace.hh" -#include "cpu/base.hh" -#include "cpu/exec_context.hh" -#include "dev/alpha_console.hh" -#include "dev/simconsole.hh" -#include "dev/simple_disk.hh" -#include "dev/tsunami_io.hh" -#include "mem/bus/bus.hh" -#include "mem/bus/pio_interface.hh" -#include "mem/bus/pio_interface_impl.hh" -#include "mem/functional/memory_control.hh" -#include "mem/functional/physical.hh" -#include "sim/builder.hh" -#include "sim/sim_object.hh" - -using namespace std; -using namespace AlphaISA; - -AlphaConsole::AlphaConsole(const string &name, SimConsole *cons, SimpleDisk *d, - AlphaSystem *s, BaseCPU *c, Platform *p, - MemoryController *mmu, Addr a, - HierParams *hier, Bus *pio_bus) - : PioDevice(name, p), disk(d), console(cons), system(s), cpu(c), addr(a) -{ - mmu->add_child(this, RangeSize(addr, size)); - - if (pio_bus) { - pioInterface = newPioInterface(name + ".pio", hier, pio_bus, this, - &AlphaConsole::cacheAccess); - pioInterface->addAddrRange(RangeSize(addr, size)); - } - - alphaAccess = new Access; - alphaAccess->last_offset = size - 1; - - alphaAccess->version = ALPHA_ACCESS_VERSION; - alphaAccess->diskUnit = 1; - - alphaAccess->diskCount = 0; - alphaAccess->diskPAddr = 0; - alphaAccess->diskBlock = 0; - alphaAccess->diskOperation = 0; - alphaAccess->outputChar = 0; - alphaAccess->inputChar = 0; - bzero(alphaAccess->cpuStack, sizeof(alphaAccess->cpuStack)); - - system->setAlphaAccess(addr); -} - -void -AlphaConsole::startup() -{ - alphaAccess->numCPUs = system->getNumCPUs(); - alphaAccess->kernStart = system->getKernelStart(); - alphaAccess->kernEnd = system->getKernelEnd(); - alphaAccess->entryPoint = system->getKernelEntry(); - alphaAccess->mem_size = system->physmem->size(); - alphaAccess->cpuClock = cpu->frequency() / 1000000; // In MHz - alphaAccess->intrClockFrequency = platform->intrFrequency(); -} - -Fault -AlphaConsole::read(MemReqPtr &req, uint8_t *data) -{ - memset(data, 0, req->size); - - Addr daddr = req->paddr - (addr & EV5::PAddrImplMask); - - switch (req->size) - { - case sizeof(uint32_t): - DPRINTF(AlphaConsole, "read: offset=%#x val=%#x\n", daddr, - *(uint32_t*)data); - switch (daddr) - { - case offsetof(AlphaAccess, last_offset): - *(uint32_t*)data = alphaAccess->last_offset; - break; - case offsetof(AlphaAccess, version): - *(uint32_t*)data = alphaAccess->version; - break; - case offsetof(AlphaAccess, numCPUs): - *(uint32_t*)data = alphaAccess->numCPUs; - break; - case offsetof(AlphaAccess, intrClockFrequency): - *(uint32_t*)data = alphaAccess->intrClockFrequency; - break; - default: - // Old console code read in everyting as a 32bit int - *(uint32_t*)data = *(uint32_t*)(consoleData + daddr); - - } - break; - case sizeof(uint64_t): - DPRINTF(AlphaConsole, "read: offset=%#x val=%#x\n", daddr, - *(uint64_t*)data); - switch (daddr) - { - case offsetof(AlphaAccess, inputChar): - *(uint64_t*)data = console->console_in(); - break; - case offsetof(AlphaAccess, cpuClock): - *(uint64_t*)data = alphaAccess->cpuClock; - break; - case offsetof(AlphaAccess, mem_size): - *(uint64_t*)data = alphaAccess->mem_size; - break; - case offsetof(AlphaAccess, kernStart): - *(uint64_t*)data = alphaAccess->kernStart; - break; - case offsetof(AlphaAccess, kernEnd): - *(uint64_t*)data = alphaAccess->kernEnd; - break; - case offsetof(AlphaAccess, entryPoint): - *(uint64_t*)data = alphaAccess->entryPoint; - break; - case offsetof(AlphaAccess, diskUnit): - *(uint64_t*)data = alphaAccess->diskUnit; - break; - case offsetof(AlphaAccess, diskCount): - *(uint64_t*)data = alphaAccess->diskCount; - break; - case offsetof(AlphaAccess, diskPAddr): - *(uint64_t*)data = alphaAccess->diskPAddr; - break; - case offsetof(AlphaAccess, diskBlock): - *(uint64_t*)data = alphaAccess->diskBlock; - break; - case offsetof(AlphaAccess, diskOperation): - *(uint64_t*)data = alphaAccess->diskOperation; - break; - case offsetof(AlphaAccess, outputChar): - *(uint64_t*)data = alphaAccess->outputChar; - break; - default: - int cpunum = (daddr - offsetof(AlphaAccess, cpuStack)) / - sizeof(alphaAccess->cpuStack[0]); - - if (cpunum >= 0 && cpunum < 64) - *(uint64_t*)data = alphaAccess->cpuStack[cpunum]; - else - panic("Unknown 64bit access, %#x\n", daddr); - } - break; - default: - return genMachineCheckFault(); - } - - return NoFault; -} - -Fault -AlphaConsole::write(MemReqPtr &req, const uint8_t *data) -{ - uint64_t val; - - switch (req->size) { - case sizeof(uint32_t): - val = *(uint32_t *)data; - break; - - case sizeof(uint64_t): - val = *(uint64_t *)data; - break; - default: - return genMachineCheckFault(); - } - - Addr daddr = req->paddr - (addr & EV5::PAddrImplMask); - ExecContext *other_xc; - - switch (daddr) { - case offsetof(AlphaAccess, diskUnit): - alphaAccess->diskUnit = val; - break; - - case offsetof(AlphaAccess, diskCount): - alphaAccess->diskCount = val; - break; - - case offsetof(AlphaAccess, diskPAddr): - alphaAccess->diskPAddr = val; - break; - - case offsetof(AlphaAccess, diskBlock): - alphaAccess->diskBlock = val; - break; - - case offsetof(AlphaAccess, diskOperation): - if (val == 0x13) - disk->read(alphaAccess->diskPAddr, alphaAccess->diskBlock, - alphaAccess->diskCount); - else - panic("Invalid disk operation!"); - - break; - - case offsetof(AlphaAccess, outputChar): - console->out((char)(val & 0xff)); - break; - - other_xc->activate(); //Start the cpu - break; - - default: - int cpunum = (daddr - offsetof(AlphaAccess, cpuStack)) / - sizeof(alphaAccess->cpuStack[0]); - warn("%d: Trying to launch CPU number %d!", curTick, cpunum); - assert(val > 0 && "Must not access primary cpu"); - if (cpunum >= 0 && cpunum < 64) - alphaAccess->cpuStack[cpunum] = val; - else - panic("Unknown 64bit access, %#x\n", daddr); - } - - return NoFault; -} - -Tick -AlphaConsole::cacheAccess(MemReqPtr &req) -{ - return curTick + 1000; -} - -void -AlphaConsole::Access::serialize(ostream &os) -{ - SERIALIZE_SCALAR(last_offset); - SERIALIZE_SCALAR(version); - SERIALIZE_SCALAR(numCPUs); - SERIALIZE_SCALAR(mem_size); - SERIALIZE_SCALAR(cpuClock); - SERIALIZE_SCALAR(intrClockFrequency); - SERIALIZE_SCALAR(kernStart); - SERIALIZE_SCALAR(kernEnd); - SERIALIZE_SCALAR(entryPoint); - SERIALIZE_SCALAR(diskUnit); - SERIALIZE_SCALAR(diskCount); - SERIALIZE_SCALAR(diskPAddr); - SERIALIZE_SCALAR(diskBlock); - SERIALIZE_SCALAR(diskOperation); - SERIALIZE_SCALAR(outputChar); - SERIALIZE_SCALAR(inputChar); - SERIALIZE_ARRAY(cpuStack,64); -} - -void -AlphaConsole::Access::unserialize(Checkpoint *cp, const std::string §ion) -{ - UNSERIALIZE_SCALAR(last_offset); - UNSERIALIZE_SCALAR(version); - UNSERIALIZE_SCALAR(numCPUs); - UNSERIALIZE_SCALAR(mem_size); - UNSERIALIZE_SCALAR(cpuClock); - UNSERIALIZE_SCALAR(intrClockFrequency); - UNSERIALIZE_SCALAR(kernStart); - UNSERIALIZE_SCALAR(kernEnd); - UNSERIALIZE_SCALAR(entryPoint); - UNSERIALIZE_SCALAR(diskUnit); - UNSERIALIZE_SCALAR(diskCount); - UNSERIALIZE_SCALAR(diskPAddr); - UNSERIALIZE_SCALAR(diskBlock); - UNSERIALIZE_SCALAR(diskOperation); - UNSERIALIZE_SCALAR(outputChar); - UNSERIALIZE_SCALAR(inputChar); - UNSERIALIZE_ARRAY(cpuStack, 64); -} - -void -AlphaConsole::serialize(ostream &os) -{ - alphaAccess->serialize(os); -} - -void -AlphaConsole::unserialize(Checkpoint *cp, const std::string §ion) -{ - alphaAccess->unserialize(cp, section); -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaConsole) - - SimObjectParam<SimConsole *> sim_console; - SimObjectParam<SimpleDisk *> disk; - SimObjectParam<MemoryController *> mmu; - Param<Addr> addr; - SimObjectParam<AlphaSystem *> system; - SimObjectParam<BaseCPU *> cpu; - SimObjectParam<Platform *> platform; - SimObjectParam<Bus*> pio_bus; - Param<Tick> pio_latency; - SimObjectParam<HierParams *> hier; - -END_DECLARE_SIM_OBJECT_PARAMS(AlphaConsole) - -BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaConsole) - - INIT_PARAM(sim_console, "The Simulator Console"), - INIT_PARAM(disk, "Simple Disk"), - INIT_PARAM(mmu, "Memory Controller"), - INIT_PARAM(addr, "Device Address"), - INIT_PARAM(system, "system object"), - INIT_PARAM(cpu, "Processor"), - INIT_PARAM(platform, "platform"), - INIT_PARAM(pio_bus, "The IO Bus to attach to"), - INIT_PARAM_DFLT(pio_latency, "Programmed IO latency", 1000), - INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams) - -END_INIT_SIM_OBJECT_PARAMS(AlphaConsole) - -CREATE_SIM_OBJECT(AlphaConsole) -{ - return new AlphaConsole(getInstanceName(), sim_console, disk, - system, cpu, platform, mmu, addr, hier, pio_bus); -} - -REGISTER_SIM_OBJECT("AlphaConsole", AlphaConsole) diff --git a/dev/alpha_console.hh b/dev/alpha_console.hh deleted file mode 100644 index f63c6ad7e..000000000 --- a/dev/alpha_console.hh +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2001-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** @file - * System Console Interface - */ - -#ifndef __ALPHA_CONSOLE_HH__ -#define __ALPHA_CONSOLE_HH__ - -#include "base/range.hh" -#include "dev/alpha_access.h" -#include "dev/io_device.hh" -#include "sim/host.hh" -#include "sim/sim_object.hh" - -class BaseCPU; -class SimConsole; -class AlphaSystem; -class SimpleDisk; -class MemoryController; - -/** - * Memory mapped interface to the system console. This device - * represents a shared data region between the OS Kernel and the - * System Console. - * - * The system console is a small standalone program that is initially - * run when the system boots. It contains the necessary code to - * access the boot disk, to read/write from the console, and to pass - * boot parameters to the kernel. - * - * This version of the system console is very different from the one - * that would be found in a real system. Many of the functions use - * some sort of backdoor to get their job done. For example, reading - * from the boot device on a real system would require a minimal - * device driver to access the disk controller, but since we have a - * simulator here, we are able to bypass the disk controller and - * access the disk image directly. There are also some things like - * reading the kernel off the disk image into memory that are normally - * taken care of by the console that are now taken care of by the - * simulator. - * - * These shortcuts are acceptable since the system console is - * primarily used doing boot before the kernel has loaded its device - * drivers. - */ -class AlphaConsole : public PioDevice -{ - protected: - struct Access : public AlphaAccess - { - void serialize(std::ostream &os); - void unserialize(Checkpoint *cp, const std::string §ion); - }; - - union { - Access *alphaAccess; - uint8_t *consoleData; - }; - - /** the disk must be accessed from the console */ - SimpleDisk *disk; - - /** the system console (the terminal) is accessable from the console */ - SimConsole *console; - - /** a pointer to the system we are running in */ - AlphaSystem *system; - - /** a pointer to the CPU boot cpu */ - BaseCPU *cpu; - - Addr addr; - static const Addr size = sizeof(struct AlphaAccess); - - public: - /** Standard Constructor */ - AlphaConsole(const std::string &name, SimConsole *cons, SimpleDisk *d, - AlphaSystem *s, BaseCPU *c, Platform *platform, - MemoryController *mmu, Addr addr, - HierParams *hier, Bus *pio_bus); - - virtual void startup(); - - /** - * memory mapped reads and writes - */ - virtual Fault read(MemReqPtr &req, uint8_t *data); - virtual Fault write(MemReqPtr &req, const uint8_t *data); - - /** - * standard serialization routines for checkpointing - */ - virtual void serialize(std::ostream &os); - virtual void unserialize(Checkpoint *cp, const std::string §ion); - - public: - Tick cacheAccess(MemReqPtr &req); -}; - -#endif // __ALPHA_CONSOLE_HH__ diff --git a/dev/baddev.cc b/dev/baddev.cc deleted file mode 100644 index 87d683a5d..000000000 --- a/dev/baddev.cc +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** @file - * BadDevice implemenation - */ - -#include <deque> -#include <string> -#include <vector> - -#include "base/trace.hh" -#include "cpu/exec_context.hh" -#include "dev/baddev.hh" -#include "dev/platform.hh" -#include "mem/bus/bus.hh" -#include "mem/bus/pio_interface.hh" -#include "mem/bus/pio_interface_impl.hh" -#include "mem/functional/memory_control.hh" -#include "sim/builder.hh" -#include "sim/system.hh" - -using namespace std; -using namespace TheISA; - -BadDevice::BadDevice(const string &name, Addr a, MemoryController *mmu, - HierParams *hier, Bus *pio_bus, const string &devicename) - : PioDevice(name, NULL), addr(a), devname(devicename) -{ - mmu->add_child(this, RangeSize(addr, size)); - - if (pio_bus) { - pioInterface = newPioInterface(name, hier, pio_bus, this, - &BadDevice::cacheAccess); - pioInterface->addAddrRange(RangeSize(addr, size)); - } - -} - -Fault -BadDevice::read(MemReqPtr &req, uint8_t *data) -{ - - panic("Device %s not imlpmented\n", devname); - return NoFault; -} - -Fault -BadDevice::write(MemReqPtr &req, const uint8_t *data) -{ - panic("Device %s not imlpmented\n", devname); - return NoFault; -} - -Tick -BadDevice::cacheAccess(MemReqPtr &req) -{ - return curTick; -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(BadDevice) - - SimObjectParam<Platform *> platform; - SimObjectParam<MemoryController *> mmu; - Param<Addr> addr; - SimObjectParam<HierParams *> hier; - SimObjectParam<Bus*> pio_bus; - Param<Tick> pio_latency; - Param<string> devicename; - -END_DECLARE_SIM_OBJECT_PARAMS(BadDevice) - -BEGIN_INIT_SIM_OBJECT_PARAMS(BadDevice) - - INIT_PARAM(platform, "Platform"), - INIT_PARAM(mmu, "Memory Controller"), - INIT_PARAM(addr, "Device Address"), - INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams), - INIT_PARAM_DFLT(pio_bus, "The IO Bus to attach to", NULL), - INIT_PARAM_DFLT(pio_latency, "Programmed IO latency", 1000), - INIT_PARAM(devicename, "Name of device to error on") - -END_INIT_SIM_OBJECT_PARAMS(BadDevice) - -CREATE_SIM_OBJECT(BadDevice) -{ - return new BadDevice(getInstanceName(), addr, mmu, hier, pio_bus, - devicename); -} - -REGISTER_SIM_OBJECT("BadDevice", BadDevice) diff --git a/dev/baddev.hh b/dev/baddev.hh deleted file mode 100644 index 189f28331..000000000 --- a/dev/baddev.hh +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** @file - * This devices just panics when touched. For example if you have a - * kernel that touches the frame buffer which isn't allowed. - */ - -#ifndef __DEV_BADDEV_HH__ -#define __DEV_BADDEV_HH__ - -#include "base/range.hh" -#include "dev/io_device.hh" - -class MemoryController; - -/** - * BadDevice - * This device just panics when accessed. It is supposed to warn - * the user that the kernel they are running has unsupported - * options (i.e. frame buffer) - */ -class BadDevice : public PioDevice -{ - private: - Addr addr; - static const Addr size = 0xf; - - std::string devname; - - public: - /** - * Constructor for the Baddev Class. - * @param name name of the object - * @param a base address of the write - * @param mmu the memory controller - * @param hier object to store parameters universal the device hierarchy - * @param bus The bus that this device is attached to - * @param devicename device that is not implemented - */ - BadDevice(const std::string &name, Addr a, MemoryController *mmu, - HierParams *hier, Bus *bus, const std::string &devicename); - - /** - * On a read event we just panic aand hopefully print a - * meaningful error message. - * @param req Contains the address to read from. - * @param data A pointer to write the read data to. - * @return The fault condition of the access. - */ - virtual Fault read(MemReqPtr &req, uint8_t *data); - - /** - * On a write event we just panic aand hopefully print a - * meaningful error message. - * @param req Contains the address to write to. - * @param data The data to write. - * @return The fault condition of the access. - */ - virtual Fault write(MemReqPtr &req, const uint8_t *data); - - /** - * Return how long this access will take. - * @param req the memory request to calcuate - * @return Tick when the request is done - */ - Tick cacheAccess(MemReqPtr &req); -}; - -#endif // __DEV_BADDEV_HH__ diff --git a/dev/disk_image.cc b/dev/disk_image.cc deleted file mode 100644 index 447c54697..000000000 --- a/dev/disk_image.cc +++ /dev/null @@ -1,471 +0,0 @@ -/* - * Copyright (c) 2001-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** @file - * Disk Image Definitions - */ - -#include <sys/types.h> -#include <sys/uio.h> -#include <errno.h> -#include <unistd.h> - -#include <cstdio> -#include <cstring> -#include <fstream> -#include <string> - -#include "base/callback.hh" -#include "base/misc.hh" -#include "base/trace.hh" -#include "dev/disk_image.hh" -#include "sim/builder.hh" -#include "sim/sim_exit.hh" -#include "sim/byteswap.hh" - -using namespace std; - -//////////////////////////////////////////////////////////////////////// -// -// Raw Disk image -// -RawDiskImage::RawDiskImage(const string &name, const string &filename, - bool rd_only) - : DiskImage(name), disk_size(0) -{ open(filename, rd_only); } - -RawDiskImage::~RawDiskImage() -{ close(); } - -void -RawDiskImage::open(const string &filename, bool rd_only) -{ - if (!filename.empty()) { - initialized = true; - readonly = rd_only; - file = filename; - - ios::openmode mode = ios::in | ios::binary; - if (!readonly) - mode |= ios::out; - stream.open(file.c_str(), mode); - if (!stream.is_open()) - panic("Error opening %s", filename); - } -} - -void -RawDiskImage::close() -{ - stream.close(); -} - -off_t -RawDiskImage::size() const -{ - if (disk_size == 0) { - if (!stream.is_open()) - panic("file not open!\n"); - stream.seekg(0, ios::end); - disk_size = stream.tellg(); - } - - return disk_size / SectorSize; -} - -off_t -RawDiskImage::read(uint8_t *data, off_t offset) const -{ - if (!initialized) - panic("RawDiskImage not initialized"); - - if (!stream.is_open()) - panic("file not open!\n"); - - if (stream.seekg(offset * SectorSize, ios::beg) < 0) - panic("Could not seek to location in file"); - - streampos pos = stream.tellg(); - stream.read((char *)data, SectorSize); - - DPRINTF(DiskImageRead, "read: offset=%d\n", (uint64_t)offset); - DDUMP(DiskImageRead, data, SectorSize); - - return stream.tellg() - pos; -} - -off_t -RawDiskImage::write(const uint8_t *data, off_t offset) -{ - if (!initialized) - panic("RawDiskImage not initialized"); - - if (readonly) - panic("Cannot write to a read only disk image"); - - if (!stream.is_open()) - panic("file not open!\n"); - - if (stream.seekp(offset * SectorSize, ios::beg) < 0) - panic("Could not seek to location in file"); - - DPRINTF(DiskImageWrite, "write: offset=%d\n", (uint64_t)offset); - DDUMP(DiskImageWrite, data, SectorSize); - - streampos pos = stream.tellp(); - stream.write((const char *)data, SectorSize); - return stream.tellp() - pos; -} - -DEFINE_SIM_OBJECT_CLASS_NAME("DiskImage", DiskImage) - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(RawDiskImage) - - Param<string> image_file; - Param<bool> read_only; - -END_DECLARE_SIM_OBJECT_PARAMS(RawDiskImage) - -BEGIN_INIT_SIM_OBJECT_PARAMS(RawDiskImage) - - INIT_PARAM(image_file, "disk image file"), - INIT_PARAM_DFLT(read_only, "read only image", false) - -END_INIT_SIM_OBJECT_PARAMS(RawDiskImage) - - -CREATE_SIM_OBJECT(RawDiskImage) -{ - return new RawDiskImage(getInstanceName(), image_file, read_only); -} - -REGISTER_SIM_OBJECT("RawDiskImage", RawDiskImage) - -//////////////////////////////////////////////////////////////////////// -// -// Copy on Write Disk image -// -const int CowDiskImage::VersionMajor = 1; -const int CowDiskImage::VersionMinor = 0; - -CowDiskImage::CowDiskImage(const string &name, DiskImage *kid, int hash_size) - : DiskImage(name), child(kid), table(NULL) -{ init(hash_size); } - -class CowDiskCallback : public Callback -{ - private: - CowDiskImage *image; - - public: - CowDiskCallback(CowDiskImage *i) : image(i) {} - void process() { image->save(); delete this; } -}; - -CowDiskImage::CowDiskImage(const string &name, DiskImage *kid, int hash_size, - const string &file, bool read_only) - : DiskImage(name), filename(file), child(kid), table(NULL) -{ - if (!open(filename)) { - assert(!read_only && "why have a non-existent read only file?"); - init(hash_size); - } - - if (!read_only) - registerExitCallback(new CowDiskCallback(this)); -} - -CowDiskImage::~CowDiskImage() -{ - SectorTable::iterator i = table->begin(); - SectorTable::iterator end = table->end(); - - while (i != end) { - delete (*i).second; - ++i; - } -} - -void -SafeRead(ifstream &stream, void *data, int count) -{ - stream.read((char *)data, count); - if (!stream.is_open()) - panic("file not open"); - - if (stream.eof()) - panic("premature end-of-file"); - - if (stream.bad() || stream.fail()) - panic("error reading cowdisk image"); -} - -template<class T> -void -SafeRead(ifstream &stream, T &data) -{ - SafeRead(stream, &data, sizeof(data)); -} - -template<class T> -void -SafeReadSwap(ifstream &stream, T &data) -{ - SafeRead(stream, &data, sizeof(data)); - data = letoh(data); //is this the proper byte order conversion? -} - -bool -CowDiskImage::open(const string &file) -{ - ifstream stream(file.c_str()); - if (!stream.is_open()) - return false; - - if (stream.fail() || stream.bad()) - panic("Error opening %s", file); - - uint64_t magic; - SafeRead(stream, magic); - - if (memcmp(&magic, "COWDISK!", sizeof(magic)) != 0) - panic("Could not open %s: Invalid magic", file); - - uint32_t major, minor; - SafeReadSwap(stream, major); - SafeReadSwap(stream, minor); - - if (major != VersionMajor && minor != VersionMinor) - panic("Could not open %s: invalid version %d.%d != %d.%d", - file, major, minor, VersionMajor, VersionMinor); - - uint64_t sector_count; - SafeReadSwap(stream, sector_count); - table = new SectorTable(sector_count); - - - for (uint64_t i = 0; i < sector_count; i++) { - uint64_t offset; - SafeReadSwap(stream, offset); - - Sector *sector = new Sector; - SafeRead(stream, sector, sizeof(Sector)); - - assert(table->find(offset) == table->end()); - (*table)[offset] = sector; - } - - stream.close(); - - initialized = true; - return true; -} - -void -CowDiskImage::init(int hash_size) -{ - table = new SectorTable(hash_size); - - initialized = true; -} - -void -SafeWrite(ofstream &stream, const void *data, int count) -{ - stream.write((const char *)data, count); - if (!stream.is_open()) - panic("file not open"); - - if (stream.eof()) - panic("premature end-of-file"); - - if (stream.bad() || stream.fail()) - panic("error reading cowdisk image"); -} - -template<class T> -void -SafeWrite(ofstream &stream, const T &data) -{ - SafeWrite(stream, &data, sizeof(data)); -} - -template<class T> -void -SafeWriteSwap(ofstream &stream, const T &data) -{ - T swappeddata = letoh(data); //is this the proper byte order conversion? - SafeWrite(stream, &swappeddata, sizeof(data)); -} -void -CowDiskImage::save() -{ - save(filename); -} - -void -CowDiskImage::save(const string &file) -{ - if (!initialized) - panic("RawDiskImage not initialized"); - - ofstream stream(file.c_str()); - if (!stream.is_open() || stream.fail() || stream.bad()) - panic("Error opening %s", file); - - uint64_t magic; - memcpy(&magic, "COWDISK!", sizeof(magic)); - SafeWrite(stream, magic); - - SafeWriteSwap(stream, (uint32_t)VersionMajor); - SafeWriteSwap(stream, (uint32_t)VersionMinor); - SafeWriteSwap(stream, (uint64_t)table->size()); - - uint64_t size = table->size(); - SectorTable::iterator iter = table->begin(); - SectorTable::iterator end = table->end(); - - for (uint64_t i = 0; i < size; i++) { - if (iter == end) - panic("Incorrect Table Size during save of COW disk image"); - - SafeWriteSwap(stream, (uint64_t)(*iter).first); - SafeWrite(stream, (*iter).second->data, sizeof(Sector)); - ++iter; - } - - stream.close(); -} - -void -CowDiskImage::writeback() -{ - SectorTable::iterator i = table->begin(); - SectorTable::iterator end = table->end(); - - while (i != end) { - child->write((*i).second->data, (*i).first); - ++i; - } -} - -off_t -CowDiskImage::size() const -{ return child->size(); } - -off_t -CowDiskImage::read(uint8_t *data, off_t offset) const -{ - if (!initialized) - panic("CowDiskImage not initialized"); - - if (offset > size()) - panic("access out of bounds"); - - SectorTable::const_iterator i = table->find(offset); - if (i == table->end()) - return child->read(data, offset); - else { - memcpy(data, (*i).second->data, SectorSize); - DPRINTF(DiskImageRead, "read: offset=%d\n", (uint64_t)offset); - DDUMP(DiskImageRead, data, SectorSize); - return SectorSize; - } -} - -off_t -CowDiskImage::write(const uint8_t *data, off_t offset) -{ - if (!initialized) - panic("RawDiskImage not initialized"); - - if (offset > size()) - panic("access out of bounds"); - - SectorTable::iterator i = table->find(offset); - if (i == table->end()) { - Sector *sector = new Sector; - memcpy(sector, data, SectorSize); - table->insert(make_pair(offset, sector)); - } else { - memcpy((*i).second->data, data, SectorSize); - } - - DPRINTF(DiskImageWrite, "write: offset=%d\n", (uint64_t)offset); - DDUMP(DiskImageWrite, data, SectorSize); - - return SectorSize; -} - -void -CowDiskImage::serialize(ostream &os) -{ - string cowFilename = name() + ".cow"; - SERIALIZE_SCALAR(cowFilename); - save(Checkpoint::dir() + "/" + cowFilename); -} - -void -CowDiskImage::unserialize(Checkpoint *cp, const string §ion) -{ - string cowFilename; - UNSERIALIZE_SCALAR(cowFilename); - cowFilename = cp->cptDir + "/" + cowFilename; - open(cowFilename); -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(CowDiskImage) - - SimObjectParam<DiskImage *> child; - Param<string> image_file; - Param<int> table_size; - Param<bool> read_only; - -END_DECLARE_SIM_OBJECT_PARAMS(CowDiskImage) - -BEGIN_INIT_SIM_OBJECT_PARAMS(CowDiskImage) - - INIT_PARAM(child, "child image"), - INIT_PARAM_DFLT(image_file, "disk image file", ""), - INIT_PARAM_DFLT(table_size, "initial table size", 65536), - INIT_PARAM_DFLT(read_only, "don't write back to the copy-on-write file", - true) - -END_INIT_SIM_OBJECT_PARAMS(CowDiskImage) - - -CREATE_SIM_OBJECT(CowDiskImage) -{ - if (((string)image_file).empty()) - return new CowDiskImage(getInstanceName(), child, table_size); - else - return new CowDiskImage(getInstanceName(), child, table_size, - image_file, read_only); -} - -REGISTER_SIM_OBJECT("CowDiskImage", CowDiskImage) diff --git a/dev/etherbus.cc b/dev/etherbus.cc deleted file mode 100644 index c6b131e8e..000000000 --- a/dev/etherbus.cc +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (c) 2002-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* @file - * Device module for modelling an ethernet hub - */ - -#include <cmath> -#include <deque> -#include <string> -#include <vector> - -#include "base/trace.hh" -#include "dev/etherbus.hh" -#include "dev/etherdump.hh" -#include "dev/etherint.hh" -#include "dev/etherpkt.hh" -#include "sim/builder.hh" -#include "sim/root.hh" - -using namespace std; - -EtherBus::EtherBus(const string &name, double speed, bool loop, - EtherDump *packet_dump) - : SimObject(name), ticksPerByte(speed), loopback(loop), - event(&mainEventQueue, this), sender(0), dump(packet_dump) -{ -} - -void -EtherBus::txDone() -{ - devlist_t::iterator i = devlist.begin(); - devlist_t::iterator end = devlist.end(); - - DPRINTF(Ethernet, "ethernet packet received: length=%d\n", packet->length); - DDUMP(EthernetData, packet->data, packet->length); - - while (i != end) { - if (loopback || *i != sender) - (*i)->sendPacket(packet); - ++i; - } - - sender->sendDone(); - - if (dump) - dump->dump(packet); - - sender = 0; - packet = 0; -} - -void -EtherBus::reg(EtherInt *dev) -{ devlist.push_back(dev); } - -bool -EtherBus::send(EtherInt *sndr, PacketPtr &pkt) -{ - if (busy()) { - DPRINTF(Ethernet, "ethernet packet not sent, bus busy\n", curTick); - return false; - } - - DPRINTF(Ethernet, "ethernet packet sent: length=%d\n", pkt->length); - DDUMP(EthernetData, pkt->data, pkt->length); - - packet = pkt; - sender = sndr; - int delay = (int)ceil(((double)pkt->length * ticksPerByte) + 1.0); - DPRINTF(Ethernet, "scheduling packet: delay=%d, (rate=%f)\n", - delay, ticksPerByte); - event.schedule(curTick + delay); - - return true; -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherBus) - - Param<bool> loopback; - Param<double> speed; - SimObjectParam<EtherDump *> packet_dump; - -END_DECLARE_SIM_OBJECT_PARAMS(EtherBus) - -BEGIN_INIT_SIM_OBJECT_PARAMS(EtherBus) - - INIT_PARAM(loopback, "send the packet back to the sending interface"), - INIT_PARAM(speed, "bus speed in ticks per byte"), - INIT_PARAM(packet_dump, "object to dump network packets to") - -END_INIT_SIM_OBJECT_PARAMS(EtherBus) - -CREATE_SIM_OBJECT(EtherBus) -{ - return new EtherBus(getInstanceName(), speed, loopback, packet_dump); -} - -REGISTER_SIM_OBJECT("EtherBus", EtherBus) diff --git a/dev/etherbus.hh b/dev/etherbus.hh deleted file mode 100644 index ca859d85f..000000000 --- a/dev/etherbus.hh +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2002-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* @file - * Device module for modelling an ethernet hub - */ - -#ifndef __ETHERBUS_H__ -#define __ETHERBUS_H__ - -#include "sim/eventq.hh" -#include "dev/etherpkt.hh" -#include "sim/sim_object.hh" - -class EtherDump; -class EtherInt; -class EtherBus : public SimObject -{ - protected: - typedef std::list<EtherInt *> devlist_t; - devlist_t devlist; - double ticksPerByte; - bool loopback; - - protected: - class DoneEvent : public Event - { - protected: - EtherBus *bus; - - public: - DoneEvent(EventQueue *q, EtherBus *b) - : Event(q), bus(b) {} - virtual void process() { bus->txDone(); } - virtual const char *description() { return "ethernet bus completion"; } - }; - - DoneEvent event; - PacketPtr packet; - EtherInt *sender; - EtherDump *dump; - - public: - EtherBus(const std::string &name, double speed, bool loopback, - EtherDump *dump); - virtual ~EtherBus() {} - - void txDone(); - void reg(EtherInt *dev); - bool busy() const { return (bool)packet; } - bool send(EtherInt *sender, PacketPtr &packet); -}; - -#endif // __ETHERBUS_H__ diff --git a/dev/etherdump.cc b/dev/etherdump.cc deleted file mode 100644 index d8a51fc5b..000000000 --- a/dev/etherdump.cc +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (c) 2002-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* @file - * Simple object for creating a simple pcap style packet trace - */ - -#include <sys/time.h> - -#include <algorithm> -#include <string> - -#include "base/misc.hh" -#include "base/output.hh" -#include "dev/etherdump.hh" -#include "sim/builder.hh" -#include "sim/root.hh" - -using std::string; - -EtherDump::EtherDump(const string &name, const string &file, int max) - : SimObject(name), stream(file.c_str()), maxlen(max) -{ -} - -#define DLT_EN10MB 1 // Ethernet (10Mb) -#define TCPDUMP_MAGIC 0xa1b2c3d4 -#define PCAP_VERSION_MAJOR 2 -#define PCAP_VERSION_MINOR 4 - -struct pcap_file_header { - uint32_t magic; - uint16_t version_major; - uint16_t version_minor; - int32_t thiszone; // gmt to local correction - uint32_t sigfigs; // accuracy of timestamps - uint32_t snaplen; // max length saved portion of each pkt - uint32_t linktype; // data link type (DLT_*) -}; - -struct pcap_pkthdr { - uint32_t seconds; - uint32_t microseconds; - uint32_t caplen; // length of portion present - uint32_t len; // length this packet (off wire) -}; - -void -EtherDump::init() -{ - curtime = time(NULL); - struct pcap_file_header hdr; - hdr.magic = TCPDUMP_MAGIC; - hdr.version_major = PCAP_VERSION_MAJOR; - hdr.version_minor = PCAP_VERSION_MINOR; - - hdr.thiszone = -5 * 3600; - hdr.snaplen = 1500; - hdr.sigfigs = 0; - hdr.linktype = DLT_EN10MB; - - stream.write(reinterpret_cast<char *>(&hdr), sizeof(hdr)); - - /* - * output an empty packet with the current time so that we know - * when the simulation began. This allows us to correlate packets - * to sim_cycles. - */ - pcap_pkthdr pkthdr; - pkthdr.seconds = curtime; - pkthdr.microseconds = 0; - pkthdr.caplen = 0; - pkthdr.len = 0; - stream.write(reinterpret_cast<char *>(&pkthdr), sizeof(pkthdr)); - - stream.flush(); -} - -void -EtherDump::dumpPacket(PacketPtr &packet) -{ - pcap_pkthdr pkthdr; - pkthdr.seconds = curtime + (curTick / Clock::Int::s); - pkthdr.microseconds = (curTick / Clock::Int::us) % ULL(1000000); - pkthdr.caplen = std::min(packet->length, maxlen); - pkthdr.len = packet->length; - stream.write(reinterpret_cast<char *>(&pkthdr), sizeof(pkthdr)); - stream.write(reinterpret_cast<char *>(packet->data), pkthdr.caplen); - stream.flush(); -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherDump) - - Param<string> file; - Param<int> maxlen; - -END_DECLARE_SIM_OBJECT_PARAMS(EtherDump) - -BEGIN_INIT_SIM_OBJECT_PARAMS(EtherDump) - - INIT_PARAM(file, "file to dump packets to"), - INIT_PARAM(maxlen, "max portion of packet data to dump") - -END_INIT_SIM_OBJECT_PARAMS(EtherDump) - -CREATE_SIM_OBJECT(EtherDump) -{ - return new EtherDump(getInstanceName(), simout.resolve(file), maxlen); -} - -REGISTER_SIM_OBJECT("EtherDump", EtherDump) diff --git a/dev/etherdump.hh b/dev/etherdump.hh deleted file mode 100644 index 149192cd7..000000000 --- a/dev/etherdump.hh +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2002-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* @file - * Simple object for creating a simple pcap style packet trace - */ - -#ifndef __ETHERDUMP_H__ -#define __ETHERDUMP_H__ - -#include <fstream> -#include "dev/etherpkt.hh" -#include "sim/sim_object.hh" - -/* - * Simple object for creating a simple pcap style packet trace - */ -class EtherDump : public SimObject -{ - private: - std::ofstream stream; - const int maxlen; - void dumpPacket(PacketPtr &packet); - void init(); - - Tick curtime; - - public: - EtherDump(const std::string &name, const std::string &file, int max); - - inline void dump(PacketPtr &pkt) { dumpPacket(pkt); } -}; - -#endif // __ETHERDUMP_H__ diff --git a/dev/etherint.hh b/dev/etherint.hh deleted file mode 100644 index e397846ae..000000000 --- a/dev/etherint.hh +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2002-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* @file - * Class representing the actual interface between two ethernet - * components. - */ - -#ifndef __DEV_ETHERINT_HH__ -#define __DEV_ETHERINT_HH__ - -#include <string> - -#include "dev/etherpkt.hh" -#include "sim/sim_object.hh" - -/* - * Class representing the actual interface between two ethernet - * components. These components are intended to attach to another - * ethernet interface on one side and whatever device on the other. - */ -class EtherInt : public SimObject -{ - protected: - EtherInt *peer; - - public: - EtherInt(const std::string &name) : SimObject(name), peer(NULL) {} - virtual ~EtherInt() {} - - void setPeer(EtherInt *p); - - void recvDone() { peer->sendDone(); } - virtual void sendDone() = 0; - - bool sendPacket(PacketPtr packet) - { return peer ? peer->recvPacket(packet) : true; } - virtual bool recvPacket(PacketPtr packet) = 0; -}; - -#endif // __DEV_ETHERINT_HH__ diff --git a/dev/etherlink.cc b/dev/etherlink.cc deleted file mode 100644 index f68332926..000000000 --- a/dev/etherlink.cc +++ /dev/null @@ -1,300 +0,0 @@ -/* - * Copyright (c) 2002-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* @file - * Device module for modelling a fixed bandwidth full duplex ethernet link - */ - -#include <cmath> -#include <deque> -#include <string> -#include <vector> - -#include "base/random.hh" -#include "base/trace.hh" -#include "dev/etherdump.hh" -#include "dev/etherint.hh" -#include "dev/etherlink.hh" -#include "dev/etherpkt.hh" -#include "sim/builder.hh" -#include "sim/serialize.hh" -#include "sim/system.hh" -#include "sim/root.hh" - -using namespace std; - -EtherLink::EtherLink(const string &name, EtherInt *peer0, EtherInt *peer1, - double rate, Tick delay, Tick delayVar, EtherDump *dump) - : SimObject(name) -{ - link[0] = new Link(name + ".link0", this, 0, rate, delay, delayVar, dump); - link[1] = new Link(name + ".link1", this, 1, rate, delay, delayVar, dump); - - interface[0] = new Interface(name + ".int0", link[0], link[1]); - interface[1] = new Interface(name + ".int1", link[1], link[0]); - - interface[0]->setPeer(peer0); - peer0->setPeer(interface[0]); - interface[1]->setPeer(peer1); - peer1->setPeer(interface[1]); -} - -EtherLink::~EtherLink() -{ - delete link[0]; - delete link[1]; - - delete interface[0]; - delete interface[1]; -} - -EtherLink::Interface::Interface(const string &name, Link *tx, Link *rx) - : EtherInt(name), txlink(tx) -{ - tx->setTxInt(this); - rx->setRxInt(this); -} - -EtherLink::Link::Link(const string &name, EtherLink *p, int num, - double rate, Tick delay, Tick delay_var, EtherDump *d) - : objName(name), parent(p), number(num), txint(NULL), rxint(NULL), - ticksPerByte(rate), linkDelay(delay), delayVar(delay_var), dump(d), - doneEvent(this) -{ } - -void -EtherLink::serialize(ostream &os) -{ - link[0]->serialize("link0", os); - link[1]->serialize("link1", os); -} - -void -EtherLink::unserialize(Checkpoint *cp, const string §ion) -{ - link[0]->unserialize("link0", cp, section); - link[1]->unserialize("link1", cp, section); -} - -void -EtherLink::Link::txComplete(PacketPtr packet) -{ - DPRINTF(Ethernet, "packet received: len=%d\n", packet->length); - DDUMP(EthernetData, packet->data, packet->length); - rxint->sendPacket(packet); -} - -class LinkDelayEvent : public Event -{ - protected: - EtherLink::Link *link; - PacketPtr packet; - - public: - // non-scheduling version for createForUnserialize() - LinkDelayEvent(); - LinkDelayEvent(EtherLink::Link *link, PacketPtr pkt, Tick when); - - void process(); - - virtual void serialize(ostream &os); - virtual void unserialize(Checkpoint *cp, const string §ion); - static Serializable *createForUnserialize(Checkpoint *cp, - const string §ion); -}; - -void -EtherLink::Link::txDone() -{ - if (dump) - dump->dump(packet); - - if (linkDelay > 0) { - DPRINTF(Ethernet, "packet delayed: delay=%d\n", linkDelay); - new LinkDelayEvent(this, packet, curTick + linkDelay); - } else { - txComplete(packet); - } - - packet = 0; - assert(!busy()); - - txint->sendDone(); -} - -bool -EtherLink::Link::transmit(PacketPtr pkt) -{ - if (busy()) { - DPRINTF(Ethernet, "packet not sent, link busy\n"); - return false; - } - - DPRINTF(Ethernet, "packet sent: len=%d\n", pkt->length); - DDUMP(EthernetData, pkt->data, pkt->length); - - packet = pkt; - Tick delay = (Tick)ceil(((double)pkt->length * ticksPerByte) + 1.0); - if (delayVar != 0) { - Random<Tick> var; - delay += var.uniform(0, delayVar); - } - DPRINTF(Ethernet, "scheduling packet: delay=%d, (rate=%f)\n", - delay, ticksPerByte); - doneEvent.schedule(curTick + delay); - - return true; -} - -void -EtherLink::Link::serialize(const string &base, ostream &os) -{ - bool packet_exists = packet; - paramOut(os, base + ".packet_exists", packet_exists); - if (packet_exists) - packet->serialize(base + ".packet", os); - - bool event_scheduled = doneEvent.scheduled(); - paramOut(os, base + ".event_scheduled", event_scheduled); - if (event_scheduled) { - Tick event_time = doneEvent.when(); - paramOut(os, base + ".event_time", event_time); - } - -} - -void -EtherLink::Link::unserialize(const string &base, Checkpoint *cp, - const string §ion) -{ - bool packet_exists; - paramIn(cp, section, base + ".packet_exists", packet_exists); - if (packet_exists) { - packet = new PacketData(16384); - packet->unserialize(base + ".packet", cp, section); - } - - bool event_scheduled; - paramIn(cp, section, base + ".event_scheduled", event_scheduled); - if (event_scheduled) { - Tick event_time; - paramIn(cp, section, base + ".event_time", event_time); - doneEvent.schedule(event_time); - } -} - -LinkDelayEvent::LinkDelayEvent() - : Event(&mainEventQueue), link(NULL) -{ - setFlags(AutoSerialize); - setFlags(AutoDelete); -} - -LinkDelayEvent::LinkDelayEvent(EtherLink::Link *l, PacketPtr p, Tick when) - : Event(&mainEventQueue), link(l), packet(p) -{ - setFlags(AutoSerialize); - setFlags(AutoDelete); - schedule(when); -} - -void -LinkDelayEvent::process() -{ - link->txComplete(packet); -} - -void -LinkDelayEvent::serialize(ostream &os) -{ - paramOut(os, "type", string("LinkDelayEvent")); - Event::serialize(os); - - EtherLink *parent = link->parent; - bool number = link->number; - SERIALIZE_OBJPTR(parent); - SERIALIZE_SCALAR(number); - - packet->serialize("packet", os); -} - - -void -LinkDelayEvent::unserialize(Checkpoint *cp, const string §ion) -{ - Event::unserialize(cp, section); - - EtherLink *parent; - bool number; - UNSERIALIZE_OBJPTR(parent); - UNSERIALIZE_SCALAR(number); - - link = parent->link[number]; - - packet = new PacketData(16384); - packet->unserialize("packet", cp, section); -} - - -Serializable * -LinkDelayEvent::createForUnserialize(Checkpoint *cp, const string §ion) -{ - return new LinkDelayEvent(); -} - -REGISTER_SERIALIZEABLE("LinkDelayEvent", LinkDelayEvent) - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherLink) - - SimObjectParam<EtherInt *> int1; - SimObjectParam<EtherInt *> int2; - Param<double> speed; - Param<Tick> delay; - Param<Tick> delay_var; - SimObjectParam<EtherDump *> dump; - -END_DECLARE_SIM_OBJECT_PARAMS(EtherLink) - -BEGIN_INIT_SIM_OBJECT_PARAMS(EtherLink) - - INIT_PARAM(int1, "interface 1"), - INIT_PARAM(int2, "interface 2"), - INIT_PARAM(speed, "link speed in bits per second"), - INIT_PARAM(delay, "transmit delay of packets in us"), - INIT_PARAM(delay_var, "Difference in amount of time to traverse wire"), - INIT_PARAM(dump, "object to dump network packets to") - -END_INIT_SIM_OBJECT_PARAMS(EtherLink) - -CREATE_SIM_OBJECT(EtherLink) -{ - return new EtherLink(getInstanceName(), int1, int2, speed, delay, delay_var, - dump); -} - -REGISTER_SIM_OBJECT("EtherLink", EtherLink) diff --git a/dev/etherlink.hh b/dev/etherlink.hh deleted file mode 100644 index 305007d9e..000000000 --- a/dev/etherlink.hh +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c) 2002-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* @file - * Device module for modelling a fixed bandwidth full duplex ethernet link - */ - -#ifndef __DEV_ETHERLINK_HH__ -#define __DEV_ETHERLINK_HH__ - -#include "dev/etherint.hh" -#include "dev/etherpkt.hh" -#include "sim/eventq.hh" -#include "sim/host.hh" -#include "sim/sim_object.hh" - -class EtherDump; -class Checkpoint; -/* - * Model for a fixed bandwidth full duplex ethernet link - */ -class EtherLink : public SimObject -{ - protected: - class Interface; - - friend class LinkDelayEvent; - /* - * Model for a single uni-directional link - */ - class Link - { - protected: - std::string objName; - - EtherLink *parent; - int number; - - Interface *txint; - Interface *rxint; - - double ticksPerByte; - Tick linkDelay; - Tick delayVar; - EtherDump *dump; - - protected: - /* - * Transfer is complete - */ - PacketPtr packet; - void txDone(); - typedef EventWrapper<Link, &Link::txDone> DoneEvent; - friend void DoneEvent::process(); - DoneEvent doneEvent; - - friend class LinkDelayEvent; - void txComplete(PacketPtr packet); - - public: - Link(const std::string &name, EtherLink *p, int num, - double rate, Tick delay, Tick delay_var, EtherDump *dump); - ~Link() {} - - const std::string name() const { return objName; } - - bool busy() const { return (bool)packet; } - bool transmit(PacketPtr packet); - - void setTxInt(Interface *i) { assert(!txint); txint = i; } - void setRxInt(Interface *i) { assert(!rxint); rxint = i; } - - void serialize(const std::string &base, std::ostream &os); - void unserialize(const std::string &base, Checkpoint *cp, - const std::string §ion); - }; - - /* - * Interface at each end of the link - */ - class Interface : public EtherInt - { - private: - Link *txlink; - - public: - Interface(const std::string &name, Link *txlink, Link *rxlink); - bool recvPacket(PacketPtr packet) { return txlink->transmit(packet); } - void sendDone() { peer->sendDone(); } - }; - - Link *link[2]; - EtherInt *interface[2]; - - public: - EtherLink(const std::string &name, EtherInt *peer0, EtherInt *peer1, - double rate, Tick delay, Tick delayVar, EtherDump *dump); - virtual ~EtherLink(); - - virtual void serialize(std::ostream &os); - virtual void unserialize(Checkpoint *cp, const std::string §ion); - -}; - -#endif // __ETHERLINK_HH__ diff --git a/dev/etherpkt.cc b/dev/etherpkt.cc deleted file mode 100644 index 44dbd7c18..000000000 --- a/dev/etherpkt.cc +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <iostream> - -#include "base/misc.hh" -#include "dev/etherpkt.hh" -#include "sim/serialize.hh" - -using namespace std; - -void -PacketData::serialize(const string &base, ostream &os) -{ - paramOut(os, base + ".length", length); - paramOut(os, base + ".slack", slack); - arrayParamOut(os, base + ".data", data, length); -} - -void -PacketData::unserialize(const string &base, Checkpoint *cp, - const string §ion) -{ - paramIn(cp, section, base + ".length", length); - paramIn(cp, section, base + ".slack", slack); - if (length) - arrayParamIn(cp, section, base + ".data", data, length); -} diff --git a/dev/etherpkt.hh b/dev/etherpkt.hh deleted file mode 100644 index cb9022d72..000000000 --- a/dev/etherpkt.hh +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2002-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* @file - * Reference counted class containing ethernet packet data - */ - -#ifndef __ETHERPKT_HH__ -#define __ETHERPKT_HH__ - -#include <iosfwd> -#include <memory> -#include <assert.h> - -#include "base/refcnt.hh" -#include "sim/host.hh" - -/* - * Reference counted class containing ethernet packet data - */ -class Checkpoint; -class PacketData : public RefCounted -{ - public: - /* - * Pointer to packet data will be deleted - */ - uint8_t *data; - - /* - * Length of the current packet - */ - int length; - - /* - * Extra space taken up by the packet in whatever data structure - * it is in. - * - * NOTE: This can only be use by *one* data structure at a time! - */ - int slack; - - public: - PacketData() : data(NULL), length(0), slack(0) { } - explicit PacketData(size_t size) - : data(new uint8_t[size]), length(0), slack(0) { } - PacketData(std::auto_ptr<uint8_t> d, int l, int s = 0) - : data(d.release()), length(l), slack(s) { } - ~PacketData() { if (data) delete [] data; } - - public: - void serialize(const std::string &base, std::ostream &os); - void unserialize(const std::string &base, Checkpoint *cp, - const std::string §ion); -}; - -typedef RefCountingPtr<PacketData> PacketPtr; - -#endif // __ETHERPKT_HH__ diff --git a/dev/ethertap.cc b/dev/ethertap.cc deleted file mode 100644 index 7589991ef..000000000 --- a/dev/ethertap.cc +++ /dev/null @@ -1,345 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* @file - * Interface to connect a simulated ethernet device to the real world - */ - -#if defined(__OpenBSD__) || defined(__APPLE__) -#include <sys/param.h> -#endif -#include <netinet/in.h> - -#include <unistd.h> - -#include <deque> -#include <string> - -#include "base/misc.hh" -#include "base/pollevent.hh" -#include "base/socket.hh" -#include "base/trace.hh" -#include "dev/etherdump.hh" -#include "dev/etherint.hh" -#include "dev/etherpkt.hh" -#include "dev/ethertap.hh" -#include "sim/builder.hh" - -using namespace std; - -/** - */ -class TapListener -{ - protected: - /** - */ - class Event : public PollEvent - { - protected: - TapListener *listener; - - public: - Event(TapListener *l, int fd, int e) - : PollEvent(fd, e), listener(l) {} - - virtual void process(int revent) { listener->accept(); } - }; - - friend class Event; - Event *event; - - protected: - ListenSocket listener; - EtherTap *tap; - int port; - - public: - TapListener(EtherTap *t, int p) - : event(NULL), tap(t), port(p) {} - ~TapListener() { if (event) delete event; } - - void accept(); - void listen(); -}; - -void -TapListener::listen() -{ - while (!listener.listen(port, true)) { - DPRINTF(Ethernet, "TapListener(listen): Can't bind port %d\n", port); - port++; - } - - ccprintf(cerr, "Listening for tap connection on port %d\n", port); - event = new Event(this, listener.getfd(), POLLIN|POLLERR); - pollQueue.schedule(event); -} - -void -TapListener::accept() -{ - if (!listener.islistening()) - panic("TapListener(accept): cannot accept if we're not listening!"); - - int sfd = listener.accept(true); - if (sfd != -1) - tap->attach(sfd); -} - -/** - */ -class TapEvent : public PollEvent -{ - protected: - EtherTap *tap; - - public: - TapEvent(EtherTap *_tap, int fd, int e) - : PollEvent(fd, e), tap(_tap) {} - virtual void process(int revent) { tap->process(revent); } -}; - -EtherTap::EtherTap(const string &name, EtherDump *d, int port, int bufsz) - : EtherInt(name), event(NULL), socket(-1), buflen(bufsz), dump(d), - txEvent(this) -{ - buffer = new char[buflen]; - listener = new TapListener(this, port); - listener->listen(); -} - -EtherTap::~EtherTap() -{ - if (event) - delete event; - if (buffer) - delete [] buffer; - - delete listener; -} - -void -EtherTap::attach(int fd) -{ - if (socket != -1) - close(fd); - - buffer_offset = 0; - data_len = 0; - socket = fd; - DPRINTF(Ethernet, "EtherTap attached\n"); - event = new TapEvent(this, socket, POLLIN|POLLERR); - pollQueue.schedule(event); -} - -void -EtherTap::detach() -{ - DPRINTF(Ethernet, "EtherTap detached\n"); - delete event; - event = 0; - close(socket); - socket = -1; -} - -bool -EtherTap::recvPacket(PacketPtr packet) -{ - if (dump) - dump->dump(packet); - - DPRINTF(Ethernet, "EtherTap output len=%d\n", packet->length); - DDUMP(EthernetData, packet->data, packet->length); - u_int32_t len = htonl(packet->length); - write(socket, &len, sizeof(len)); - write(socket, packet->data, packet->length); - - recvDone(); - - return true; -} - -void -EtherTap::sendDone() -{} - -void -EtherTap::process(int revent) -{ - if (revent & POLLERR) { - detach(); - return; - } - - char *data = buffer + sizeof(u_int32_t); - if (!(revent & POLLIN)) - return; - - if (buffer_offset < data_len + sizeof(u_int32_t)) { - int len = read(socket, buffer + buffer_offset, buflen - buffer_offset); - if (len == 0) { - detach(); - return; - } - - buffer_offset += len; - - if (data_len == 0) - data_len = ntohl(*(u_int32_t *)buffer); - - DPRINTF(Ethernet, "Received data from peer: len=%d buffer_offset=%d " - "data_len=%d\n", len, buffer_offset, data_len); - } - - while (data_len != 0 && buffer_offset >= data_len + sizeof(u_int32_t)) { - PacketPtr packet; - packet = new PacketData(data_len); - packet->length = data_len; - memcpy(packet->data, data, data_len); - - buffer_offset -= data_len + sizeof(u_int32_t); - assert(buffer_offset >= 0); - if (buffer_offset > 0) { - memmove(buffer, data + data_len, buffer_offset); - data_len = ntohl(*(u_int32_t *)buffer); - } else - data_len = 0; - - DPRINTF(Ethernet, "EtherTap input len=%d\n", packet->length); - DDUMP(EthernetData, packet->data, packet->length); - if (!sendPacket(packet)) { - DPRINTF(Ethernet, "bus busy...buffer for retransmission\n"); - packetBuffer.push(packet); - if (!txEvent.scheduled()) - txEvent.schedule(curTick + retryTime); - } else if (dump) { - dump->dump(packet); - } - } -} - -void -EtherTap::retransmit() -{ - if (packetBuffer.empty()) - return; - - PacketPtr packet = packetBuffer.front(); - if (sendPacket(packet)) { - if (dump) - dump->dump(packet); - DPRINTF(Ethernet, "EtherTap retransmit\n"); - packetBuffer.front() = NULL; - packetBuffer.pop(); - } - - if (!packetBuffer.empty() && !txEvent.scheduled()) - txEvent.schedule(curTick + retryTime); -} - -//===================================================================== - -void -EtherTap::serialize(ostream &os) -{ - SERIALIZE_SCALAR(socket); - SERIALIZE_SCALAR(buflen); - uint8_t *buffer = (uint8_t *)this->buffer; - SERIALIZE_ARRAY(buffer, buflen); - SERIALIZE_SCALAR(buffer_offset); - SERIALIZE_SCALAR(data_len); - - bool tapevent_present = false; - if (event) { - tapevent_present = true; - SERIALIZE_SCALAR(tapevent_present); - event->serialize(os); - } - else { - SERIALIZE_SCALAR(tapevent_present); - } -} - -void -EtherTap::unserialize(Checkpoint *cp, const std::string §ion) -{ - UNSERIALIZE_SCALAR(socket); - UNSERIALIZE_SCALAR(buflen); - uint8_t *buffer = (uint8_t *)this->buffer; - UNSERIALIZE_ARRAY(buffer, buflen); - UNSERIALIZE_SCALAR(buffer_offset); - UNSERIALIZE_SCALAR(data_len); - - bool tapevent_present; - UNSERIALIZE_SCALAR(tapevent_present); - if (tapevent_present) { - event = new TapEvent(this, socket, POLLIN|POLLERR); - - event->unserialize(cp,section); - - if (event->queued()) { - pollQueue.schedule(event); - } - } -} - -//===================================================================== - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherTap) - - SimObjectParam<EtherInt *> peer; - SimObjectParam<EtherDump *> dump; - Param<unsigned> port; - Param<unsigned> bufsz; - -END_DECLARE_SIM_OBJECT_PARAMS(EtherTap) - -BEGIN_INIT_SIM_OBJECT_PARAMS(EtherTap) - - INIT_PARAM_DFLT(peer, "peer interface", NULL), - INIT_PARAM_DFLT(dump, "object to dump network packets to", NULL), - INIT_PARAM_DFLT(port, "tap port", 3500), - INIT_PARAM_DFLT(bufsz, "tap buffer size", 10000) - -END_INIT_SIM_OBJECT_PARAMS(EtherTap) - - -CREATE_SIM_OBJECT(EtherTap) -{ - EtherTap *tap = new EtherTap(getInstanceName(), dump, port, bufsz); - - if (peer) { - tap->setPeer(peer); - peer->setPeer(tap); - } - - return tap; -} - -REGISTER_SIM_OBJECT("EtherTap", EtherTap) diff --git a/dev/ethertap.hh b/dev/ethertap.hh deleted file mode 100644 index 069ba734f..000000000 --- a/dev/ethertap.hh +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* @file - * Interface to connect a simulated ethernet device to the real world - */ - -#ifndef __ETHERTAP_HH__ -#define __ETHERTAP_HH__ - -#include <queue> -#include <string> - -#include "dev/etherint.hh" -#include "dev/etherpkt.hh" -#include "sim/eventq.hh" -#include "base/pollevent.hh" -#include "sim/sim_object.hh" - -class TapEvent; -class TapListener; - -/* - * Interface to connect a simulated ethernet device to the real world - */ -class EtherTap : public EtherInt -{ - protected: - friend class TapEvent; - TapEvent *event; - - protected: - friend class TapListener; - TapListener *listener; - int socket; - char *buffer; - int buflen; - int32_t buffer_offset; - int32_t data_len; - - EtherDump *dump; - - void attach(int fd); - void detach(); - - protected: - std::string device; - std::queue<PacketPtr> packetBuffer; - - void process(int revent); - void enqueue(PacketData *packet); - void retransmit(); - - /* - */ - class TxEvent : public Event - { - protected: - EtherTap *tap; - - public: - TxEvent(EtherTap *_tap) - : Event(&mainEventQueue), tap(_tap) {} - void process() { tap->retransmit(); } - virtual const char *description() { return "retransmit event"; } - }; - - friend class TxEvent; - TxEvent txEvent; - - public: - EtherTap(const std::string &name, EtherDump *dump, int port, int bufsz); - virtual ~EtherTap(); - - virtual bool recvPacket(PacketPtr packet); - virtual void sendDone(); - - virtual void serialize(std::ostream &os); - virtual void unserialize(Checkpoint *cp, const std::string §ion); -}; - -#endif // __ETHERTAP_HH__ diff --git a/dev/ide_ctrl.cc b/dev/ide_ctrl.cc deleted file mode 100644 index 05c756f04..000000000 --- a/dev/ide_ctrl.cc +++ /dev/null @@ -1,813 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <cstddef> -#include <cstdlib> -#include <string> -#include <vector> - -#include "base/trace.hh" -#include "cpu/intr_control.hh" -#include "dev/ide_ctrl.hh" -#include "dev/ide_disk.hh" -#include "dev/pciconfigall.hh" -#include "dev/pcireg.h" -#include "dev/platform.hh" -#include "mem/bus/bus.hh" -#include "mem/bus/dma_interface.hh" -#include "mem/bus/pio_interface.hh" -#include "mem/bus/pio_interface_impl.hh" -#include "mem/functional/memory_control.hh" -#include "mem/functional/physical.hh" -#include "sim/builder.hh" -#include "sim/sim_object.hh" - -using namespace std; -using namespace TheISA; - -//// -// Initialization and destruction -//// - -IdeController::IdeController(Params *p) - : PciDev(p) -{ - // initialize the PIO interface addresses - pri_cmd_addr = 0; - pri_cmd_size = BARSize[0]; - - pri_ctrl_addr = 0; - pri_ctrl_size = BARSize[1]; - - sec_cmd_addr = 0; - sec_cmd_size = BARSize[2]; - - sec_ctrl_addr = 0; - sec_ctrl_size = BARSize[3]; - - // initialize the bus master interface (BMI) address to be configured - // via PCI - bmi_addr = 0; - bmi_size = BARSize[4]; - - // zero out all of the registers - memset(bmi_regs.data, 0, sizeof(bmi_regs)); - memset(config_regs.data, 0, sizeof(config_regs.data)); - - // setup initial values - // enable both channels - config_regs.idetim0 = htole((uint16_t)IDETIM_DECODE_EN); - config_regs.idetim1 = htole((uint16_t)IDETIM_DECODE_EN); - bmi_regs.bmis0 = DMA1CAP | DMA0CAP; - bmi_regs.bmis1 = DMA1CAP | DMA0CAP; - - // reset all internal variables - io_enabled = false; - bm_enabled = false; - memset(cmd_in_progress, 0, sizeof(cmd_in_progress)); - - pioInterface = NULL; - dmaInterface = NULL; - // create the PIO and DMA interfaces - if (params()->pio_bus) { - pioInterface = newPioInterface(name() + ".pio", params()->hier, - params()->pio_bus, this, - &IdeController::cacheAccess); - pioLatency = params()->pio_latency * params()->pio_bus->clockRate; - } - - if (params()->dma_bus) { - dmaInterface = new DMAInterface<Bus>(name() + ".dma", - params()->dma_bus, - params()->dma_bus, 1, true); - } - - // setup the disks attached to controller - memset(disks, 0, sizeof(disks)); - dev[0] = 0; - dev[1] = 0; - - if (params()->disks.size() > 3) - panic("IDE controllers support a maximum of 4 devices attached!\n"); - - for (int i = 0; i < params()->disks.size(); i++) { - disks[i] = params()->disks[i]; - disks[i]->setController(this, dmaInterface); - } -} - -IdeController::~IdeController() -{ - for (int i = 0; i < 4; i++) - if (disks[i]) - delete disks[i]; -} - -//// -// Utility functions -/// - -void -IdeController::parseAddr(const Addr &addr, Addr &offset, IdeChannel &channel, - IdeRegType ®_type) -{ - offset = addr; - - if (addr >= pri_cmd_addr && addr < (pri_cmd_addr + pri_cmd_size)) { - offset -= pri_cmd_addr; - reg_type = COMMAND_BLOCK; - channel = PRIMARY; - } else if (addr >= pri_ctrl_addr && - addr < (pri_ctrl_addr + pri_ctrl_size)) { - offset -= pri_ctrl_addr; - reg_type = CONTROL_BLOCK; - channel = PRIMARY; - } else if (addr >= sec_cmd_addr && - addr < (sec_cmd_addr + sec_cmd_size)) { - offset -= sec_cmd_addr; - reg_type = COMMAND_BLOCK; - channel = SECONDARY; - } else if (addr >= sec_ctrl_addr && - addr < (sec_ctrl_addr + sec_ctrl_size)) { - offset -= sec_ctrl_addr; - reg_type = CONTROL_BLOCK; - channel = SECONDARY; - } else if (addr >= bmi_addr && addr < (bmi_addr + bmi_size)) { - offset -= bmi_addr; - reg_type = BMI_BLOCK; - channel = (offset < BMIC1) ? PRIMARY : SECONDARY; - } else { - panic("IDE controller access to invalid address: %#x\n", addr); - } -} - -int -IdeController::getDisk(IdeChannel channel) -{ - int disk = 0; - uint8_t *devBit = &dev[0]; - - if (channel == SECONDARY) { - disk += 2; - devBit = &dev[1]; - } - - disk += *devBit; - - assert(*devBit == 0 || *devBit == 1); - - return disk; -} - -int -IdeController::getDisk(IdeDisk *diskPtr) -{ - for (int i = 0; i < 4; i++) { - if ((long)diskPtr == (long)disks[i]) - return i; - } - return -1; -} - -bool -IdeController::isDiskSelected(IdeDisk *diskPtr) -{ - for (int i = 0; i < 4; i++) { - if ((long)diskPtr == (long)disks[i]) { - // is disk is on primary or secondary channel - int channel = i/2; - // is disk the master or slave - int devID = i%2; - - return (dev[channel] == devID); - } - } - panic("Unable to find disk by pointer!!\n"); -} - -//// -// Command completion -//// - -void -IdeController::setDmaComplete(IdeDisk *disk) -{ - int diskNum = getDisk(disk); - - if (diskNum < 0) - panic("Unable to find disk based on pointer %#x\n", disk); - - if (diskNum < 2) { - // clear the start/stop bit in the command register - bmi_regs.bmic0 &= ~SSBM; - // clear the bus master active bit in the status register - bmi_regs.bmis0 &= ~BMIDEA; - // set the interrupt bit - bmi_regs.bmis0 |= IDEINTS; - } else { - // clear the start/stop bit in the command register - bmi_regs.bmic1 &= ~SSBM; - // clear the bus master active bit in the status register - bmi_regs.bmis1 &= ~BMIDEA; - // set the interrupt bit - bmi_regs.bmis1 |= IDEINTS; - } -} - -//// -// Bus timing and bus access functions -//// - -Tick -IdeController::cacheAccess(MemReqPtr &req) -{ - // @todo Add more accurate timing to cache access - return curTick + pioLatency; -} - -//// -// Read and write handling -//// - -void -IdeController::readConfig(int offset, int size, uint8_t *data) -{ - int config_offset; - - if (offset < PCI_DEVICE_SPECIFIC) { - PciDev::readConfig(offset, size, data); - } else if (offset >= IDE_CTRL_CONF_START && - (offset + size) <= IDE_CTRL_CONF_END) { - - config_offset = offset - IDE_CTRL_CONF_START; - - switch (size) { - case sizeof(uint8_t): - *data = config_regs.data[config_offset]; - break; - case sizeof(uint16_t): - *(uint16_t*)data = *(uint16_t*)&config_regs.data[config_offset]; - break; - case sizeof(uint32_t): - *(uint32_t*)data = *(uint32_t*)&config_regs.data[config_offset]; - break; - default: - panic("Invalid PCI configuration read size!\n"); - } - - - - } else { - panic("Read of unimplemented PCI config. register: %x\n", offset); - } - switch (size) { - case sizeof(uint8_t): - DPRINTF(IdeCtrl, "PCI read offset: %#x size: %d data: %#x\n", - offset, size, (uint32_t)*data); - break; - case sizeof(uint16_t): - DPRINTF(IdeCtrl, "PCI read offset: %#x size: %d data: %#x\n", - offset, size, *(uint16_t*)data); - break; - case sizeof(uint32_t): - DPRINTF(IdeCtrl, "PCI read offset: %#x size: %d data: %#x\n", - offset, size, *(uint32_t*)data); - break; - default: - panic("Invalid PCI configuration read size!\n"); - } - -} - -void -IdeController::writeConfig(int offset, int size, const uint8_t *data) -{ - int config_offset; - - if (offset < PCI_DEVICE_SPECIFIC) { - PciDev::writeConfig(offset, size, data); - } else if (offset >= IDE_CTRL_CONF_START && - (offset + size) <= IDE_CTRL_CONF_END) { - - config_offset = offset - IDE_CTRL_CONF_START; - - switch(size) { - case sizeof(uint8_t): - config_regs.data[config_offset] = *data; - break; - case sizeof(uint16_t): - *(uint16_t*)&config_regs.data[config_offset] = *(uint16_t*)data; - break; - case sizeof(uint32_t): - *(uint32_t*)&config_regs.data[config_offset] = *(uint32_t*)data; - break; - default: - panic("Invalid PCI configuration write size!\n"); - } - } else { - panic("Write of unimplemented PCI config. register: %x\n", offset); - } - - switch(size) { - case sizeof(uint8_t): - DPRINTF(IdeCtrl, "PCI write offset: %#x size: %d data: %#x\n", - offset, size, (uint32_t)*data); - break; - case sizeof(uint16_t): - DPRINTF(IdeCtrl, "PCI write offset: %#x size: %d data: %#x\n", - offset, size, *(uint16_t*)data); - break; - case sizeof(uint32_t): - DPRINTF(IdeCtrl, "PCI write offset: %#x size: %d data: %#x\n", - offset, size, *(uint32_t*)data); - break; - default: - panic("Invalid PCI configuration write size!\n"); - } - - // Catch the writes to specific PCI registers that have side affects - // (like updating the PIO ranges) - switch (offset) { - case PCI_COMMAND: - if (letoh(config.command) & PCI_CMD_IOSE) - io_enabled = true; - else - io_enabled = false; - - if (letoh(config.command) & PCI_CMD_BME) - bm_enabled = true; - else - bm_enabled = false; - break; - - case PCI0_BASE_ADDR0: - if (BARAddrs[0] != 0) { - pri_cmd_addr = BARAddrs[0]; - if (pioInterface) - pioInterface->addAddrRange(RangeSize(pri_cmd_addr, - pri_cmd_size)); - - pri_cmd_addr &= EV5::PAddrUncachedMask; - } - break; - - case PCI0_BASE_ADDR1: - if (BARAddrs[1] != 0) { - pri_ctrl_addr = BARAddrs[1]; - if (pioInterface) - pioInterface->addAddrRange(RangeSize(pri_ctrl_addr, - pri_ctrl_size)); - - pri_ctrl_addr &= EV5::PAddrUncachedMask; - } - break; - - case PCI0_BASE_ADDR2: - if (BARAddrs[2] != 0) { - sec_cmd_addr = BARAddrs[2]; - if (pioInterface) - pioInterface->addAddrRange(RangeSize(sec_cmd_addr, - sec_cmd_size)); - - sec_cmd_addr &= EV5::PAddrUncachedMask; - } - break; - - case PCI0_BASE_ADDR3: - if (BARAddrs[3] != 0) { - sec_ctrl_addr = BARAddrs[3]; - if (pioInterface) - pioInterface->addAddrRange(RangeSize(sec_ctrl_addr, - sec_ctrl_size)); - - sec_ctrl_addr &= EV5::PAddrUncachedMask; - } - break; - - case PCI0_BASE_ADDR4: - if (BARAddrs[4] != 0) { - bmi_addr = BARAddrs[4]; - if (pioInterface) - pioInterface->addAddrRange(RangeSize(bmi_addr, bmi_size)); - - bmi_addr &= EV5::PAddrUncachedMask; - } - break; - } -} - -Fault -IdeController::read(MemReqPtr &req, uint8_t *data) -{ - Addr offset; - IdeChannel channel; - IdeRegType reg_type; - int disk; - - parseAddr(req->paddr, offset, channel, reg_type); - - if (!io_enabled) - return NoFault; - - switch (reg_type) { - case BMI_BLOCK: - switch (req->size) { - case sizeof(uint8_t): - *data = bmi_regs.data[offset]; - break; - case sizeof(uint16_t): - *(uint16_t*)data = *(uint16_t*)&bmi_regs.data[offset]; - break; - case sizeof(uint32_t): - *(uint32_t*)data = *(uint32_t*)&bmi_regs.data[offset]; - break; - default: - panic("IDE read of BMI reg invalid size: %#x\n", req->size); - } - break; - - case COMMAND_BLOCK: - case CONTROL_BLOCK: - disk = getDisk(channel); - - if (disks[disk] == NULL) - break; - - switch (offset) { - case DATA_OFFSET: - switch (req->size) { - case sizeof(uint16_t): - disks[disk]->read(offset, reg_type, data); - break; - - case sizeof(uint32_t): - disks[disk]->read(offset, reg_type, data); - disks[disk]->read(offset, reg_type, &data[2]); - break; - - default: - panic("IDE read of data reg invalid size: %#x\n", req->size); - } - break; - default: - if (req->size == sizeof(uint8_t)) { - disks[disk]->read(offset, reg_type, data); - } else - panic("IDE read of command reg of invalid size: %#x\n", req->size); - } - break; - default: - panic("IDE controller read of unknown register block type!\n"); - } - - if (req->size == 1) - DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n", - offset, req->size, (uint32_t)*data); - else if (req->size == 2) - DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n", - offset, req->size, *(uint16_t*)data); - else - DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n", - offset, req->size, *(uint32_t*)data); - - return NoFault; -} - -Fault -IdeController::write(MemReqPtr &req, const uint8_t *data) -{ - Addr offset; - IdeChannel channel; - IdeRegType reg_type; - int disk; - uint8_t oldVal, newVal; - - parseAddr(req->paddr, offset, channel, reg_type); - - if (!io_enabled) - return NoFault; - - switch (reg_type) { - case BMI_BLOCK: - if (!bm_enabled) - return NoFault; - - switch (offset) { - // Bus master IDE command register - case BMIC1: - case BMIC0: - if (req->size != sizeof(uint8_t)) - panic("Invalid BMIC write size: %x\n", req->size); - - // select the current disk based on DEV bit - disk = getDisk(channel); - - oldVal = bmi_regs.chan[channel].bmic; - newVal = *data; - - // if a DMA transfer is in progress, R/W control cannot change - if (oldVal & SSBM) { - if ((oldVal & RWCON) ^ (newVal & RWCON)) { - (oldVal & RWCON) ? newVal |= RWCON : newVal &= ~RWCON; - } - } - - // see if the start/stop bit is being changed - if ((oldVal & SSBM) ^ (newVal & SSBM)) { - if (oldVal & SSBM) { - // stopping DMA transfer - DPRINTF(IdeCtrl, "Stopping DMA transfer\n"); - - // clear the BMIDEA bit - bmi_regs.chan[channel].bmis = - bmi_regs.chan[channel].bmis & ~BMIDEA; - - if (disks[disk] == NULL) - panic("DMA stop for disk %d which does not exist\n", - disk); - - // inform the disk of the DMA transfer abort - disks[disk]->abortDma(); - } else { - // starting DMA transfer - DPRINTF(IdeCtrl, "Starting DMA transfer\n"); - - // set the BMIDEA bit - bmi_regs.chan[channel].bmis = - bmi_regs.chan[channel].bmis | BMIDEA; - - if (disks[disk] == NULL) - panic("DMA start for disk %d which does not exist\n", - disk); - - // inform the disk of the DMA transfer start - disks[disk]->startDma(letoh(bmi_regs.chan[channel].bmidtp)); - } - } - - // update the register value - bmi_regs.chan[channel].bmic = newVal; - break; - - // Bus master IDE status register - case BMIS0: - case BMIS1: - if (req->size != sizeof(uint8_t)) - panic("Invalid BMIS write size: %x\n", req->size); - - oldVal = bmi_regs.chan[channel].bmis; - newVal = *data; - - // the BMIDEA bit is RO - newVal |= (oldVal & BMIDEA); - - // to reset (set 0) IDEINTS and IDEDMAE, write 1 to each - if ((oldVal & IDEINTS) && (newVal & IDEINTS)) - newVal &= ~IDEINTS; // clear the interrupt? - else - (oldVal & IDEINTS) ? newVal |= IDEINTS : newVal &= ~IDEINTS; - - if ((oldVal & IDEDMAE) && (newVal & IDEDMAE)) - newVal &= ~IDEDMAE; - else - (oldVal & IDEDMAE) ? newVal |= IDEDMAE : newVal &= ~IDEDMAE; - - bmi_regs.chan[channel].bmis = newVal; - break; - - // Bus master IDE descriptor table pointer register - case BMIDTP0: - case BMIDTP1: - { - if (req->size != sizeof(uint32_t)) - panic("Invalid BMIDTP write size: %x\n", req->size); - - uint32_t host_data = letoh(*(uint32_t*)data); - host_data &= ~0x3; - bmi_regs.chan[channel].bmidtp = htole(host_data); - } - break; - - default: - if (req->size != sizeof(uint8_t) && - req->size != sizeof(uint16_t) && - req->size != sizeof(uint32_t)) - panic("IDE controller write of invalid write size: %x\n", - req->size); - - // do a default copy of data into the registers - memcpy(&bmi_regs.data[offset], data, req->size); - } - break; - case COMMAND_BLOCK: - if (offset == IDE_SELECT_OFFSET) { - uint8_t *devBit = &dev[channel]; - *devBit = (letoh(*data) & IDE_SELECT_DEV_BIT) ? 1 : 0; - } - // fall-through ok! - case CONTROL_BLOCK: - disk = getDisk(channel); - - if (disks[disk] == NULL) - break; - - switch (offset) { - case DATA_OFFSET: - switch (req->size) { - case sizeof(uint16_t): - disks[disk]->write(offset, reg_type, data); - break; - - case sizeof(uint32_t): - disks[disk]->write(offset, reg_type, data); - disks[disk]->write(offset, reg_type, &data[2]); - break; - default: - panic("IDE write of data reg invalid size: %#x\n", req->size); - } - break; - default: - if (req->size == sizeof(uint8_t)) { - disks[disk]->write(offset, reg_type, data); - } else - panic("IDE write of command reg of invalid size: %#x\n", req->size); - } - break; - default: - panic("IDE controller write of unknown register block type!\n"); - } - if (req->size == 1) - DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n", - offset, req->size, (uint32_t)*data); - else if (req->size == 2) - DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n", - offset, req->size, *(uint16_t*)data); - else - DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n", - offset, req->size, *(uint32_t*)data); - - return NoFault; -} - -//// -// Serialization -//// - -void -IdeController::serialize(std::ostream &os) -{ - // Serialize the PciDev base class - PciDev::serialize(os); - - // Serialize register addresses and sizes - SERIALIZE_SCALAR(pri_cmd_addr); - SERIALIZE_SCALAR(pri_cmd_size); - SERIALIZE_SCALAR(pri_ctrl_addr); - SERIALIZE_SCALAR(pri_ctrl_size); - SERIALIZE_SCALAR(sec_cmd_addr); - SERIALIZE_SCALAR(sec_cmd_size); - SERIALIZE_SCALAR(sec_ctrl_addr); - SERIALIZE_SCALAR(sec_ctrl_size); - SERIALIZE_SCALAR(bmi_addr); - SERIALIZE_SCALAR(bmi_size); - - // Serialize registers - SERIALIZE_ARRAY(bmi_regs.data, - sizeof(bmi_regs.data) / sizeof(bmi_regs.data[0])); - SERIALIZE_ARRAY(dev, sizeof(dev) / sizeof(dev[0])); - SERIALIZE_ARRAY(config_regs.data, - sizeof(config_regs.data) / sizeof(config_regs.data[0])); - - // Serialize internal state - SERIALIZE_SCALAR(io_enabled); - SERIALIZE_SCALAR(bm_enabled); - SERIALIZE_ARRAY(cmd_in_progress, - sizeof(cmd_in_progress) / sizeof(cmd_in_progress[0])); -} - -void -IdeController::unserialize(Checkpoint *cp, const std::string §ion) -{ - // Unserialize the PciDev base class - PciDev::unserialize(cp, section); - - // Unserialize register addresses and sizes - UNSERIALIZE_SCALAR(pri_cmd_addr); - UNSERIALIZE_SCALAR(pri_cmd_size); - UNSERIALIZE_SCALAR(pri_ctrl_addr); - UNSERIALIZE_SCALAR(pri_ctrl_size); - UNSERIALIZE_SCALAR(sec_cmd_addr); - UNSERIALIZE_SCALAR(sec_cmd_size); - UNSERIALIZE_SCALAR(sec_ctrl_addr); - UNSERIALIZE_SCALAR(sec_ctrl_size); - UNSERIALIZE_SCALAR(bmi_addr); - UNSERIALIZE_SCALAR(bmi_size); - - // Unserialize registers - UNSERIALIZE_ARRAY(bmi_regs.data, - sizeof(bmi_regs.data) / sizeof(bmi_regs.data[0])); - UNSERIALIZE_ARRAY(dev, sizeof(dev) / sizeof(dev[0])); - UNSERIALIZE_ARRAY(config_regs.data, - sizeof(config_regs.data) / sizeof(config_regs.data[0])); - - // Unserialize internal state - UNSERIALIZE_SCALAR(io_enabled); - UNSERIALIZE_SCALAR(bm_enabled); - UNSERIALIZE_ARRAY(cmd_in_progress, - sizeof(cmd_in_progress) / sizeof(cmd_in_progress[0])); - - if (pioInterface) { - pioInterface->addAddrRange(RangeSize(pri_cmd_addr, pri_cmd_size)); - pioInterface->addAddrRange(RangeSize(pri_ctrl_addr, pri_ctrl_size)); - pioInterface->addAddrRange(RangeSize(sec_cmd_addr, sec_cmd_size)); - pioInterface->addAddrRange(RangeSize(sec_ctrl_addr, sec_ctrl_size)); - pioInterface->addAddrRange(RangeSize(bmi_addr, bmi_size)); - } -} - -#ifndef DOXYGEN_SHOULD_SKIP_THIS - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(IdeController) - - Param<Addr> addr; - SimObjectVectorParam<IdeDisk *> disks; - SimObjectParam<MemoryController *> mmu; - SimObjectParam<PciConfigAll *> configspace; - SimObjectParam<PciConfigData *> configdata; - SimObjectParam<Platform *> platform; - Param<uint32_t> pci_bus; - Param<uint32_t> pci_dev; - Param<uint32_t> pci_func; - SimObjectParam<Bus *> pio_bus; - SimObjectParam<Bus *> dma_bus; - Param<Tick> pio_latency; - SimObjectParam<HierParams *> hier; - -END_DECLARE_SIM_OBJECT_PARAMS(IdeController) - -BEGIN_INIT_SIM_OBJECT_PARAMS(IdeController) - - INIT_PARAM(addr, "Device Address"), - INIT_PARAM(disks, "IDE disks attached to this controller"), - INIT_PARAM(mmu, "Memory controller"), - INIT_PARAM(configspace, "PCI Configspace"), - INIT_PARAM(configdata, "PCI Config data"), - INIT_PARAM(platform, "Platform pointer"), - INIT_PARAM(pci_bus, "PCI bus ID"), - INIT_PARAM(pci_dev, "PCI device number"), - INIT_PARAM(pci_func, "PCI function code"), - INIT_PARAM(pio_bus, ""), - INIT_PARAM(dma_bus, ""), - INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1), - INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams) - -END_INIT_SIM_OBJECT_PARAMS(IdeController) - -CREATE_SIM_OBJECT(IdeController) -{ - IdeController::Params *params = new IdeController::Params; - params->name = getInstanceName(); - params->mmu = mmu; - params->configSpace = configspace; - params->configData = configdata; - params->plat = platform; - params->busNum = pci_bus; - params->deviceNum = pci_dev; - params->functionNum = pci_func; - - params->disks = disks; - params->pio_bus = pio_bus; - params->dma_bus = dma_bus; - params->pio_latency = pio_latency; - params->hier = hier; - return new IdeController(params); -} - -REGISTER_SIM_OBJECT("IdeController", IdeController) - -#endif //DOXYGEN_SHOULD_SKIP_THIS diff --git a/dev/ide_ctrl.hh b/dev/ide_ctrl.hh deleted file mode 100644 index 0fbaf9207..000000000 --- a/dev/ide_ctrl.hh +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** @file - * Simple PCI IDE controller with bus mastering capability and UDMA - * modeled after controller in the Intel PIIX4 chip - */ - -#ifndef __IDE_CTRL_HH__ -#define __IDE_CTRL_HH__ - -#include "dev/pcidev.hh" -#include "dev/pcireg.h" -#include "dev/io_device.hh" - -#define BMIC0 0x0 // Bus master IDE command register -#define BMIS0 0x2 // Bus master IDE status register -#define BMIDTP0 0x4 // Bus master IDE descriptor table pointer register -#define BMIC1 0x8 // Bus master IDE command register -#define BMIS1 0xa // Bus master IDE status register -#define BMIDTP1 0xc // Bus master IDE descriptor table pointer register - -// Bus master IDE command register bit fields -#define RWCON 0x08 // Bus master read/write control -#define SSBM 0x01 // Start/stop bus master - -// Bus master IDE status register bit fields -#define DMA1CAP 0x40 // Drive 1 DMA capable -#define DMA0CAP 0x20 // Drive 0 DMA capable -#define IDEINTS 0x04 // IDE Interrupt Status -#define IDEDMAE 0x02 // IDE DMA error -#define BMIDEA 0x01 // Bus master IDE active - -// IDE Command byte fields -#define IDE_SELECT_OFFSET (6) -#define IDE_SELECT_DEV_BIT 0x10 - -#define IDE_FEATURE_OFFSET IDE_ERROR_OFFSET -#define IDE_COMMAND_OFFSET IDE_STATUS_OFFSET - -// IDE Timing Register bit fields -#define IDETIM_DECODE_EN 0x8000 - -// PCI device specific register byte offsets -#define IDE_CTRL_CONF_START 0x40 -#define IDE_CTRL_CONF_END ((IDE_CTRL_CONF_START) + sizeof(config_regs)) - - -enum IdeRegType { - COMMAND_BLOCK, - CONTROL_BLOCK, - BMI_BLOCK -}; - -class BaseInterface; -class Bus; -class HierParams; -class IdeDisk; -class IntrControl; -class PciConfigAll; -class PhysicalMemory; -class Platform; - -/** - * Device model for an Intel PIIX4 IDE controller - */ - -class IdeController : public PciDev -{ - friend class IdeDisk; - - enum IdeChannel { - PRIMARY = 0, - SECONDARY = 1 - }; - - private: - /** Primary command block registers */ - Addr pri_cmd_addr; - Addr pri_cmd_size; - /** Primary control block registers */ - Addr pri_ctrl_addr; - Addr pri_ctrl_size; - /** Secondary command block registers */ - Addr sec_cmd_addr; - Addr sec_cmd_size; - /** Secondary control block registers */ - Addr sec_ctrl_addr; - Addr sec_ctrl_size; - /** Bus master interface (BMI) registers */ - Addr bmi_addr; - Addr bmi_size; - - private: - /** Registers used for bus master interface */ - union { - uint8_t data[16]; - - struct { - uint8_t bmic0; - uint8_t reserved_0; - uint8_t bmis0; - uint8_t reserved_1; - uint32_t bmidtp0; - uint8_t bmic1; - uint8_t reserved_2; - uint8_t bmis1; - uint8_t reserved_3; - uint32_t bmidtp1; - }; - - struct { - uint8_t bmic; - uint8_t reserved_4; - uint8_t bmis; - uint8_t reserved_5; - uint32_t bmidtp; - } chan[2]; - - } bmi_regs; - /** Shadows of the device select bit */ - uint8_t dev[2]; - /** Registers used in device specific PCI configuration */ - union { - uint8_t data[22]; - - struct { - uint16_t idetim0; - uint16_t idetim1; - uint8_t sidetim; - uint8_t reserved_0[3]; - uint8_t udmactl; - uint8_t reserved_1; - uint16_t udmatim; - uint8_t reserved_2[8]; - uint16_t ideconfig; - }; - } config_regs; - - // Internal management variables - bool io_enabled; - bool bm_enabled; - bool cmd_in_progress[4]; - - private: - /** IDE disks connected to controller */ - IdeDisk *disks[4]; - - private: - /** Parse the access address to pass on to device */ - void parseAddr(const Addr &addr, Addr &offset, IdeChannel &channel, - IdeRegType ®_type); - - /** Select the disk based on the channel and device bit */ - int getDisk(IdeChannel channel); - - /** Select the disk based on a pointer */ - int getDisk(IdeDisk *diskPtr); - - public: - /** See if a disk is selected based on its pointer */ - bool isDiskSelected(IdeDisk *diskPtr); - - public: - struct Params : public PciDev::Params - { - /** Array of disk objects */ - std::vector<IdeDisk *> disks; - Bus *pio_bus; - Bus *dma_bus; - Tick pio_latency; - HierParams *hier; - }; - const Params *params() const { return (const Params *)_params; } - - public: - IdeController(Params *p); - ~IdeController(); - - virtual void writeConfig(int offset, int size, const uint8_t *data); - virtual void readConfig(int offset, int size, uint8_t *data); - - void setDmaComplete(IdeDisk *disk); - - /** - * Read a done field for a given target. - * @param req Contains the address of the field to read. - * @param data Return the field read. - * @return The fault condition of the access. - */ - virtual Fault read(MemReqPtr &req, uint8_t *data); - - /** - * Write to the mmapped I/O control registers. - * @param req Contains the address to write to. - * @param data The data to write. - * @return The fault condition of the access. - */ - virtual Fault write(MemReqPtr &req, const uint8_t *data); - - /** - * Serialize this object to the given output stream. - * @param os The stream to serialize to. - */ - virtual void serialize(std::ostream &os); - - /** - * Reconstruct the state of this object from a checkpoint. - * @param cp The checkpoint use. - * @param section The section name of this object - */ - virtual void unserialize(Checkpoint *cp, const std::string §ion); - - /** - * Return how long this access will take. - * @param req the memory request to calcuate - * @return Tick when the request is done - */ - Tick cacheAccess(MemReqPtr &req); -}; -#endif // __IDE_CTRL_HH_ diff --git a/dev/ide_disk.cc b/dev/ide_disk.cc deleted file mode 100644 index c13556ed6..000000000 --- a/dev/ide_disk.cc +++ /dev/null @@ -1,1286 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** @file - * Device model implementation for an IDE disk - */ - -#include <cerrno> -#include <cstring> -#include <deque> -#include <string> - -#include "base/cprintf.hh" // csprintf -#include "base/trace.hh" -#include "dev/disk_image.hh" -#include "dev/ide_disk.hh" -#include "dev/ide_ctrl.hh" -#include "dev/tsunami.hh" -#include "dev/tsunami_pchip.hh" -#include "mem/functional/physical.hh" -#include "mem/bus/bus.hh" -#include "mem/bus/dma_interface.hh" -#include "mem/bus/pio_interface.hh" -#include "mem/bus/pio_interface_impl.hh" -#include "sim/builder.hh" -#include "sim/sim_object.hh" -#include "sim/root.hh" -#include "arch/isa_traits.hh" - -using namespace std; -using namespace TheISA; - -IdeDisk::IdeDisk(const string &name, DiskImage *img, PhysicalMemory *phys, - int id, Tick delay) - : SimObject(name), ctrl(NULL), image(img), physmem(phys), diskDelay(delay), - dmaTransferEvent(this), dmaReadWaitEvent(this), - dmaWriteWaitEvent(this), dmaPrdReadEvent(this), - dmaReadEvent(this), dmaWriteEvent(this) -{ - // Reset the device state - reset(id); - - // fill out the drive ID structure - memset(&driveID, 0, sizeof(struct ataparams)); - - // Calculate LBA and C/H/S values - uint16_t cylinders; - uint8_t heads; - uint8_t sectors; - - uint32_t lba_size = image->size(); - if (lba_size >= 16383*16*63) { - cylinders = 16383; - heads = 16; - sectors = 63; - } else { - if (lba_size >= 63) - sectors = 63; - else - sectors = lba_size; - - if ((lba_size / sectors) >= 16) - heads = 16; - else - heads = (lba_size / sectors); - - cylinders = lba_size / (heads * sectors); - } - - // Setup the model name - strncpy((char *)driveID.atap_model, "5MI EDD si k", - sizeof(driveID.atap_model)); - // Set the maximum multisector transfer size - driveID.atap_multi = MAX_MULTSECT; - // IORDY supported, IORDY disabled, LBA enabled, DMA enabled - driveID.atap_capabilities1 = 0x7; - // UDMA support, EIDE support - driveID.atap_extensions = 0x6; - // Setup default C/H/S settings - driveID.atap_cylinders = cylinders; - driveID.atap_sectors = sectors; - driveID.atap_heads = heads; - // Setup the current multisector transfer size - driveID.atap_curmulti = MAX_MULTSECT; - driveID.atap_curmulti_valid = 0x1; - // Number of sectors on disk - driveID.atap_capacity = lba_size; - // Multiword DMA mode 2 and below supported - driveID.atap_dmamode_supp = 0x400; - // Set PIO mode 4 and 3 supported - driveID.atap_piomode_supp = 0x3; - // Set DMA mode 4 and below supported - driveID.atap_udmamode_supp = 0x1f; - // Statically set hardware config word - driveID.atap_hwreset_res = 0x4001; - - //arbitrary for now... - driveID.atap_ata_major = WDC_VER_ATA7; -} - -IdeDisk::~IdeDisk() -{ - // destroy the data buffer - delete [] dataBuffer; -} - -void -IdeDisk::reset(int id) -{ - // initialize the data buffer and shadow registers - dataBuffer = new uint8_t[MAX_DMA_SIZE]; - - memset(dataBuffer, 0, MAX_DMA_SIZE); - memset(&cmdReg, 0, sizeof(CommandReg_t)); - memset(&curPrd.entry, 0, sizeof(PrdEntry_t)); - - dmaInterfaceBytes = 0; - curPrdAddr = 0; - curSector = 0; - cmdBytes = 0; - cmdBytesLeft = 0; - drqBytesLeft = 0; - dmaRead = false; - intrPending = false; - - // set the device state to idle - dmaState = Dma_Idle; - - if (id == DEV0) { - devState = Device_Idle_S; - devID = DEV0; - } else if (id == DEV1) { - devState = Device_Idle_NS; - devID = DEV1; - } else { - panic("Invalid device ID: %#x\n", id); - } - - // set the device ready bit - status = STATUS_DRDY_BIT; - - /* The error register must be set to 0x1 on start-up to - indicate that no diagnostic error was detected */ - cmdReg.error = 0x1; -} - -//// -// Utility functions -//// - -bool -IdeDisk::isDEVSelect() -{ - return ctrl->isDiskSelected(this); -} - -Addr -IdeDisk::pciToDma(Addr pciAddr) -{ - if (ctrl) - return ctrl->plat->pciToDma(pciAddr); - else - panic("Access to unset controller!\n"); -} - -uint32_t -IdeDisk::bytesInDmaPage(Addr curAddr, uint32_t bytesLeft) -{ - uint32_t bytesInPage = 0; - - // First calculate how many bytes could be in the page - if (bytesLeft > TheISA::PageBytes) - bytesInPage = TheISA::PageBytes; - else - bytesInPage = bytesLeft; - - // Next, see if we have crossed a page boundary, and adjust - Addr upperBound = curAddr + bytesInPage; - Addr pageBound = TheISA::TruncPage(curAddr) + TheISA::PageBytes; - - assert(upperBound >= curAddr && "DMA read wraps around address space!\n"); - - if (upperBound >= pageBound) - bytesInPage = pageBound - curAddr; - - return bytesInPage; -} - -//// -// Device registers read/write -//// - -void -IdeDisk::read(const Addr &offset, IdeRegType reg_type, uint8_t *data) -{ - DevAction_t action = ACT_NONE; - - switch (reg_type) { - case COMMAND_BLOCK: - switch (offset) { - // Data transfers occur two bytes at a time - case DATA_OFFSET: - *(uint16_t*)data = cmdReg.data; - action = ACT_DATA_READ_SHORT; - break; - case ERROR_OFFSET: - *data = cmdReg.error; - break; - case NSECTOR_OFFSET: - *data = cmdReg.sec_count; - break; - case SECTOR_OFFSET: - *data = cmdReg.sec_num; - break; - case LCYL_OFFSET: - *data = cmdReg.cyl_low; - break; - case HCYL_OFFSET: - *data = cmdReg.cyl_high; - break; - case DRIVE_OFFSET: - *data = cmdReg.drive; - break; - case STATUS_OFFSET: - *data = status; - action = ACT_STAT_READ; - break; - default: - panic("Invalid IDE command register offset: %#x\n", offset); - } - break; - case CONTROL_BLOCK: - if (offset == ALTSTAT_OFFSET) - *data = status; - else - panic("Invalid IDE control register offset: %#x\n", offset); - break; - default: - panic("Unknown register block!\n"); - } - - if (action != ACT_NONE) - updateState(action); -} - -void -IdeDisk::write(const Addr &offset, IdeRegType reg_type, const uint8_t *data) -{ - DevAction_t action = ACT_NONE; - - switch (reg_type) { - case COMMAND_BLOCK: - switch (offset) { - case DATA_OFFSET: - cmdReg.data = *(uint16_t*)data; - action = ACT_DATA_WRITE_SHORT; - break; - case FEATURES_OFFSET: - break; - case NSECTOR_OFFSET: - cmdReg.sec_count = *data; - break; - case SECTOR_OFFSET: - cmdReg.sec_num = *data; - break; - case LCYL_OFFSET: - cmdReg.cyl_low = *data; - break; - case HCYL_OFFSET: - cmdReg.cyl_high = *data; - break; - case DRIVE_OFFSET: - cmdReg.drive = *data; - action = ACT_SELECT_WRITE; - break; - case COMMAND_OFFSET: - cmdReg.command = *data; - action = ACT_CMD_WRITE; - break; - default: - panic("Invalid IDE command register offset: %#x\n", offset); - } - break; - case CONTROL_BLOCK: - if (offset == CONTROL_OFFSET) { - if (*data & CONTROL_RST_BIT) { - // force the device into the reset state - devState = Device_Srst; - action = ACT_SRST_SET; - } else if (devState == Device_Srst && !(*data & CONTROL_RST_BIT)) - action = ACT_SRST_CLEAR; - - nIENBit = (*data & CONTROL_IEN_BIT) ? true : false; - } - else - panic("Invalid IDE control register offset: %#x\n", offset); - break; - default: - panic("Unknown register block!\n"); - } - - if (action != ACT_NONE) - updateState(action); -} - -//// -// Perform DMA transactions -//// - -void -IdeDisk::doDmaTransfer() -{ - if (dmaState != Dma_Transfer || devState != Transfer_Data_Dma) - panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n", - dmaState, devState); - - // first read the current PRD - if (dmaInterface) { - if (dmaInterface->busy()) { - // reschedule after waiting period - dmaTransferEvent.schedule(curTick + DMA_BACKOFF_PERIOD); - return; - } - - dmaInterface->doDMA(Read, curPrdAddr, sizeof(PrdEntry_t), curTick, - &dmaPrdReadEvent); - } else { - dmaPrdReadDone(); - } -} - -void -IdeDisk::dmaPrdReadDone() -{ - // actually copy the PRD from physical memory - memcpy((void *)&curPrd.entry, - physmem->dma_addr(curPrdAddr, sizeof(PrdEntry_t)), - sizeof(PrdEntry_t)); - - DPRINTF(IdeDisk, - "PRD: baseAddr:%#x (%#x) byteCount:%d (%d) eot:%#x sector:%d\n", - curPrd.getBaseAddr(), pciToDma(curPrd.getBaseAddr()), - curPrd.getByteCount(), (cmdBytesLeft/SectorSize), - curPrd.getEOT(), curSector); - - // the prd pointer has already been translated, so just do an increment - curPrdAddr = curPrdAddr + sizeof(PrdEntry_t); - - if (dmaRead) - doDmaRead(); - else - doDmaWrite(); -} - -void -IdeDisk::regStats() -{ - using namespace Stats; - dmaReadFullPages - .name(name() + ".dma_read_full_pages") - .desc("Number of full page size DMA reads (not PRD).") - ; - dmaReadBytes - .name(name() + ".dma_read_bytes") - .desc("Number of bytes transfered via DMA reads (not PRD).") - ; - dmaReadTxs - .name(name() + ".dma_read_txs") - .desc("Number of DMA read transactions (not PRD).") - ; - - dmaWriteFullPages - .name(name() + ".dma_write_full_pages") - .desc("Number of full page size DMA writes.") - ; - dmaWriteBytes - .name(name() + ".dma_write_bytes") - .desc("Number of bytes transfered via DMA writes.") - ; - dmaWriteTxs - .name(name() + ".dma_write_txs") - .desc("Number of DMA write transactions.") - ; -} - -void -IdeDisk::doDmaRead() -{ - /** @todo we need to figure out what the delay actually will be */ - Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize); - - DPRINTF(IdeDisk, "doDmaRead, diskDelay: %d totalDiskDelay: %d\n", - diskDelay, totalDiskDelay); - if (dmaInterface) { - if (dmaInterface->busy()) { - // reschedule after waiting period - dmaReadWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD); - return; - } - - Addr dmaAddr = pciToDma(curPrd.getBaseAddr()); - - uint32_t bytesInPage = bytesInDmaPage(curPrd.getBaseAddr(), - (uint32_t)curPrd.getByteCount()); - - dmaInterfaceBytes = bytesInPage; - - if (bytesInPage == TheISA::VMPageSize) - dmaReadFullPages++; - dmaReadBytes += bytesInPage; - dmaReadTxs++; - dmaInterface->doDMA(Read, dmaAddr, bytesInPage, - curTick + totalDiskDelay, &dmaReadEvent); - } else { - // schedule dmaReadEvent with sectorDelay (dmaReadDone) - dmaReadEvent.schedule(curTick + totalDiskDelay); - } -} - -void -IdeDisk::dmaReadDone() -{ - - Addr curAddr = 0, dmaAddr = 0; - uint32_t bytesWritten = 0, bytesInPage = 0, bytesLeft = 0; - - // continue to use the DMA interface until all pages are read - if (dmaInterface && (dmaInterfaceBytes < curPrd.getByteCount())) { - // see if the interface is busy - if (dmaInterface->busy()) { - // reschedule after waiting period - dmaReadEvent.schedule(curTick + DMA_BACKOFF_PERIOD); - return; - } - - uint32_t bytesLeft = curPrd.getByteCount() - dmaInterfaceBytes; - curAddr = curPrd.getBaseAddr() + dmaInterfaceBytes; - dmaAddr = pciToDma(curAddr); - - bytesInPage = bytesInDmaPage(curAddr, bytesLeft); - dmaInterfaceBytes += bytesInPage; - - if (bytesInPage == TheISA::VMPageSize) - dmaReadFullPages++; - dmaReadBytes += bytesInPage; - dmaReadTxs++; - - dmaInterface->doDMA(Read, dmaAddr, bytesInPage, - curTick, &dmaReadEvent); - - return; - } - - // set initial address - curAddr = curPrd.getBaseAddr(); - - // clear out the data buffer - memset(dataBuffer, 0, MAX_DMA_SIZE); - - // read the data from memory via DMA into a data buffer - while (bytesWritten < curPrd.getByteCount()) { - if (cmdBytesLeft <= 0) - panic("DMA data is larger than # of sectors specified\n"); - - dmaAddr = pciToDma(curAddr); - - // calculate how many bytes are in the current page - bytesLeft = curPrd.getByteCount() - bytesWritten; - bytesInPage = bytesInDmaPage(curAddr, bytesLeft); - - // copy the data from memory into the data buffer - memcpy((void *)(dataBuffer + bytesWritten), - physmem->dma_addr(dmaAddr, bytesInPage), - bytesInPage); - - curAddr += bytesInPage; - bytesWritten += bytesInPage; - cmdBytesLeft -= bytesInPage; - } - - // write the data to the disk image - for (bytesWritten = 0; - bytesWritten < curPrd.getByteCount(); - bytesWritten += SectorSize) { - - writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten)); - } - - // check for the EOT - if (curPrd.getEOT()) { - assert(cmdBytesLeft == 0); - dmaState = Dma_Idle; - updateState(ACT_DMA_DONE); - } else { - doDmaTransfer(); - } -} - -void -IdeDisk::doDmaWrite() -{ - /** @todo we need to figure out what the delay actually will be */ - Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize); - - DPRINTF(IdeDisk, "doDmaWrite, diskDelay: %d totalDiskDelay: %d\n", - diskDelay, totalDiskDelay); - - if (dmaInterface) { - if (dmaInterface->busy()) { - // reschedule after waiting period - dmaWriteWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD); - return; - } - - Addr dmaAddr = pciToDma(curPrd.getBaseAddr()); - - uint32_t bytesInPage = bytesInDmaPage(curPrd.getBaseAddr(), - (uint32_t)curPrd.getByteCount()); - - dmaInterfaceBytes = bytesInPage; - - if (bytesInPage == TheISA::VMPageSize) - dmaWriteFullPages++; - dmaWriteBytes += bytesInPage; - dmaWriteTxs++; - - dmaInterface->doDMA(WriteInvalidate, dmaAddr, - bytesInPage, curTick + totalDiskDelay, - &dmaWriteEvent); - } else { - // schedule event with disk delay (dmaWriteDone) - dmaWriteEvent.schedule(curTick + totalDiskDelay); - } -} - -void -IdeDisk::dmaWriteDone() -{ - Addr curAddr = 0, pageAddr = 0, dmaAddr = 0; - uint32_t bytesRead = 0, bytesInPage = 0; - - // continue to use the DMA interface until all pages are read - if (dmaInterface && (dmaInterfaceBytes < curPrd.getByteCount())) { - // see if the interface is busy - if (dmaInterface->busy()) { - // reschedule after waiting period - dmaWriteEvent.schedule(curTick + DMA_BACKOFF_PERIOD); - return; - } - - uint32_t bytesLeft = curPrd.getByteCount() - dmaInterfaceBytes; - curAddr = curPrd.getBaseAddr() + dmaInterfaceBytes; - dmaAddr = pciToDma(curAddr); - - bytesInPage = bytesInDmaPage(curAddr, bytesLeft); - dmaInterfaceBytes += bytesInPage; - - if (bytesInPage == TheISA::VMPageSize) - dmaWriteFullPages++; - dmaWriteBytes += bytesInPage; - dmaWriteTxs++; - - dmaInterface->doDMA(WriteInvalidate, dmaAddr, - bytesInPage, curTick, - &dmaWriteEvent); - - return; - } - - // setup the initial page and DMA address - curAddr = curPrd.getBaseAddr(); - pageAddr = TheISA::TruncPage(curAddr); - dmaAddr = pciToDma(curAddr); - - // clear out the data buffer - memset(dataBuffer, 0, MAX_DMA_SIZE); - - while (bytesRead < curPrd.getByteCount()) { - // see if we have crossed into a new page - if (pageAddr != TheISA::TruncPage(curAddr)) { - // write the data to memory - memcpy(physmem->dma_addr(dmaAddr, bytesInPage), - (void *)(dataBuffer + (bytesRead - bytesInPage)), - bytesInPage); - - // update the DMA address and page address - pageAddr = TheISA::TruncPage(curAddr); - dmaAddr = pciToDma(curAddr); - - bytesInPage = 0; - } - - if (cmdBytesLeft <= 0) - panic("DMA requested data is larger than # sectors specified\n"); - - readDisk(curSector++, (uint8_t *)(dataBuffer + bytesRead)); - - curAddr += SectorSize; - bytesRead += SectorSize; - bytesInPage += SectorSize; - cmdBytesLeft -= SectorSize; - } - - // write the last page worth read to memory - if (bytesInPage != 0) { - memcpy(physmem->dma_addr(dmaAddr, bytesInPage), - (void *)(dataBuffer + (bytesRead - bytesInPage)), - bytesInPage); - } - - // check for the EOT - if (curPrd.getEOT()) { - assert(cmdBytesLeft == 0); - dmaState = Dma_Idle; - updateState(ACT_DMA_DONE); - } else { - doDmaTransfer(); - } -} - -//// -// Disk utility routines -/// - -void -IdeDisk::readDisk(uint32_t sector, uint8_t *data) -{ - uint32_t bytesRead = image->read(data, sector); - - if (bytesRead != SectorSize) - panic("Can't read from %s. Only %d of %d read. errno=%d\n", - name(), bytesRead, SectorSize, errno); -} - -void -IdeDisk::writeDisk(uint32_t sector, uint8_t *data) -{ - uint32_t bytesWritten = image->write(data, sector); - - if (bytesWritten != SectorSize) - panic("Can't write to %s. Only %d of %d written. errno=%d\n", - name(), bytesWritten, SectorSize, errno); -} - -//// -// Setup and handle commands -//// - -void -IdeDisk::startDma(const uint32_t &prdTableBase) -{ - if (dmaState != Dma_Start) - panic("Inconsistent DMA state, should be in Dma_Start!\n"); - - if (devState != Transfer_Data_Dma) - panic("Inconsistent device state for DMA start!\n"); - - // PRD base address is given by bits 31:2 - curPrdAddr = pciToDma((Addr)(prdTableBase & ~ULL(0x3))); - - dmaState = Dma_Transfer; - - // schedule dma transfer (doDmaTransfer) - dmaTransferEvent.schedule(curTick + 1); -} - -void -IdeDisk::abortDma() -{ - if (dmaState == Dma_Idle) - panic("Inconsistent DMA state, should be Start or Transfer!"); - - if (devState != Transfer_Data_Dma && devState != Prepare_Data_Dma) - panic("Inconsistent device state, should be Transfer or Prepare!\n"); - - updateState(ACT_CMD_ERROR); -} - -void -IdeDisk::startCommand() -{ - DevAction_t action = ACT_NONE; - uint32_t size = 0; - dmaRead = false; - - // Decode commands - switch (cmdReg.command) { - // Supported non-data commands - case WDSF_READ_NATIVE_MAX: - size = image->size() - 1; - cmdReg.sec_num = (size & 0xff); - cmdReg.cyl_low = ((size & 0xff00) >> 8); - cmdReg.cyl_high = ((size & 0xff0000) >> 16); - cmdReg.head = ((size & 0xf000000) >> 24); - - devState = Command_Execution; - action = ACT_CMD_COMPLETE; - break; - - case WDCC_RECAL: - case WDCC_IDP: - case WDCC_STANDBY_IMMED: - case WDCC_FLUSHCACHE: - case WDSF_VERIFY: - case WDSF_SEEK: - case SET_FEATURES: - case WDCC_SETMULTI: - devState = Command_Execution; - action = ACT_CMD_COMPLETE; - break; - - // Supported PIO data-in commands - case WDCC_IDENTIFY: - cmdBytes = cmdBytesLeft = sizeof(struct ataparams); - devState = Prepare_Data_In; - action = ACT_DATA_READY; - break; - - case WDCC_READMULTI: - case WDCC_READ: - if (!(cmdReg.drive & DRIVE_LBA_BIT)) - panic("Attempt to perform CHS access, only supports LBA\n"); - - if (cmdReg.sec_count == 0) - cmdBytes = cmdBytesLeft = (256 * SectorSize); - else - cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize); - - curSector = getLBABase(); - - /** @todo make this a scheduled event to simulate disk delay */ - devState = Prepare_Data_In; - action = ACT_DATA_READY; - break; - - // Supported PIO data-out commands - case WDCC_WRITEMULTI: - case WDCC_WRITE: - if (!(cmdReg.drive & DRIVE_LBA_BIT)) - panic("Attempt to perform CHS access, only supports LBA\n"); - - if (cmdReg.sec_count == 0) - cmdBytes = cmdBytesLeft = (256 * SectorSize); - else - cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize); - - curSector = getLBABase(); - - devState = Prepare_Data_Out; - action = ACT_DATA_READY; - break; - - // Supported DMA commands - case WDCC_WRITEDMA: - dmaRead = true; // a write to the disk is a DMA read from memory - case WDCC_READDMA: - if (!(cmdReg.drive & DRIVE_LBA_BIT)) - panic("Attempt to perform CHS access, only supports LBA\n"); - - if (cmdReg.sec_count == 0) - cmdBytes = cmdBytesLeft = (256 * SectorSize); - else - cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize); - - curSector = getLBABase(); - - devState = Prepare_Data_Dma; - action = ACT_DMA_READY; - break; - - default: - panic("Unsupported ATA command: %#x\n", cmdReg.command); - } - - if (action != ACT_NONE) { - // set the BSY bit - status |= STATUS_BSY_BIT; - // clear the DRQ bit - status &= ~STATUS_DRQ_BIT; - // clear the DF bit - status &= ~STATUS_DF_BIT; - - updateState(action); - } -} - -//// -// Handle setting and clearing interrupts -//// - -void -IdeDisk::intrPost() -{ - DPRINTF(IdeDisk, "Posting Interrupt\n"); - if (intrPending) - panic("Attempt to post an interrupt with one pending\n"); - - intrPending = true; - - // talk to controller to set interrupt - if (ctrl) { - ctrl->bmi_regs.bmis0 |= IDEINTS; - ctrl->intrPost(); - } -} - -void -IdeDisk::intrClear() -{ - DPRINTF(IdeDisk, "Clearing Interrupt\n"); - if (!intrPending) - panic("Attempt to clear a non-pending interrupt\n"); - - intrPending = false; - - // talk to controller to clear interrupt - if (ctrl) - ctrl->intrClear(); -} - -//// -// Manage the device internal state machine -//// - -void -IdeDisk::updateState(DevAction_t action) -{ - switch (devState) { - case Device_Srst: - if (action == ACT_SRST_SET) { - // set the BSY bit - status |= STATUS_BSY_BIT; - } else if (action == ACT_SRST_CLEAR) { - // clear the BSY bit - status &= ~STATUS_BSY_BIT; - - // reset the device state - reset(devID); - } - break; - - case Device_Idle_S: - if (action == ACT_SELECT_WRITE && !isDEVSelect()) { - devState = Device_Idle_NS; - } else if (action == ACT_CMD_WRITE) { - startCommand(); - } - - break; - - case Device_Idle_SI: - if (action == ACT_SELECT_WRITE && !isDEVSelect()) { - devState = Device_Idle_NS; - intrClear(); - } else if (action == ACT_STAT_READ || isIENSet()) { - devState = Device_Idle_S; - intrClear(); - } else if (action == ACT_CMD_WRITE) { - intrClear(); - startCommand(); - } - - break; - - case Device_Idle_NS: - if (action == ACT_SELECT_WRITE && isDEVSelect()) { - if (!isIENSet() && intrPending) { - devState = Device_Idle_SI; - intrPost(); - } - if (isIENSet() || !intrPending) { - devState = Device_Idle_S; - } - } - break; - - case Command_Execution: - if (action == ACT_CMD_COMPLETE) { - // clear the BSY bit - setComplete(); - - if (!isIENSet()) { - devState = Device_Idle_SI; - intrPost(); - } else { - devState = Device_Idle_S; - } - } - break; - - case Prepare_Data_In: - if (action == ACT_CMD_ERROR) { - // clear the BSY bit - setComplete(); - - if (!isIENSet()) { - devState = Device_Idle_SI; - intrPost(); - } else { - devState = Device_Idle_S; - } - } else if (action == ACT_DATA_READY) { - // clear the BSY bit - status &= ~STATUS_BSY_BIT; - // set the DRQ bit - status |= STATUS_DRQ_BIT; - - // copy the data into the data buffer - if (cmdReg.command == WDCC_IDENTIFY) { - // Reset the drqBytes for this block - drqBytesLeft = sizeof(struct ataparams); - - memcpy((void *)dataBuffer, (void *)&driveID, - sizeof(struct ataparams)); - } else { - // Reset the drqBytes for this block - drqBytesLeft = SectorSize; - - readDisk(curSector++, dataBuffer); - } - - // put the first two bytes into the data register - memcpy((void *)&cmdReg.data, (void *)dataBuffer, - sizeof(uint16_t)); - - if (!isIENSet()) { - devState = Data_Ready_INTRQ_In; - intrPost(); - } else { - devState = Transfer_Data_In; - } - } - break; - - case Data_Ready_INTRQ_In: - if (action == ACT_STAT_READ) { - devState = Transfer_Data_In; - intrClear(); - } - break; - - case Transfer_Data_In: - if (action == ACT_DATA_READ_BYTE || action == ACT_DATA_READ_SHORT) { - if (action == ACT_DATA_READ_BYTE) { - panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n"); - } else { - drqBytesLeft -= 2; - cmdBytesLeft -= 2; - - // copy next short into data registers - if (drqBytesLeft) - memcpy((void *)&cmdReg.data, - (void *)&dataBuffer[SectorSize - drqBytesLeft], - sizeof(uint16_t)); - } - - if (drqBytesLeft == 0) { - if (cmdBytesLeft == 0) { - // Clear the BSY bit - setComplete(); - devState = Device_Idle_S; - } else { - devState = Prepare_Data_In; - // set the BSY_BIT - status |= STATUS_BSY_BIT; - // clear the DRQ_BIT - status &= ~STATUS_DRQ_BIT; - - /** @todo change this to a scheduled event to simulate - disk delay */ - updateState(ACT_DATA_READY); - } - } - } - break; - - case Prepare_Data_Out: - if (action == ACT_CMD_ERROR || cmdBytesLeft == 0) { - // clear the BSY bit - setComplete(); - - if (!isIENSet()) { - devState = Device_Idle_SI; - intrPost(); - } else { - devState = Device_Idle_S; - } - } else if (action == ACT_DATA_READY && cmdBytesLeft != 0) { - // clear the BSY bit - status &= ~STATUS_BSY_BIT; - // set the DRQ bit - status |= STATUS_DRQ_BIT; - - // clear the data buffer to get it ready for writes - memset(dataBuffer, 0, MAX_DMA_SIZE); - - // reset the drqBytes for this block - drqBytesLeft = SectorSize; - - if (cmdBytesLeft == cmdBytes || isIENSet()) { - devState = Transfer_Data_Out; - } else { - devState = Data_Ready_INTRQ_Out; - intrPost(); - } - } - break; - - case Data_Ready_INTRQ_Out: - if (action == ACT_STAT_READ) { - devState = Transfer_Data_Out; - intrClear(); - } - break; - - case Transfer_Data_Out: - if (action == ACT_DATA_WRITE_BYTE || - action == ACT_DATA_WRITE_SHORT) { - - if (action == ACT_DATA_READ_BYTE) { - panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n"); - } else { - // copy the latest short into the data buffer - memcpy((void *)&dataBuffer[SectorSize - drqBytesLeft], - (void *)&cmdReg.data, - sizeof(uint16_t)); - - drqBytesLeft -= 2; - cmdBytesLeft -= 2; - } - - if (drqBytesLeft == 0) { - // copy the block to the disk - writeDisk(curSector++, dataBuffer); - - // set the BSY bit - status |= STATUS_BSY_BIT; - // set the seek bit - status |= STATUS_SEEK_BIT; - // clear the DRQ bit - status &= ~STATUS_DRQ_BIT; - - devState = Prepare_Data_Out; - - /** @todo change this to a scheduled event to simulate - disk delay */ - updateState(ACT_DATA_READY); - } - } - break; - - case Prepare_Data_Dma: - if (action == ACT_CMD_ERROR) { - // clear the BSY bit - setComplete(); - - if (!isIENSet()) { - devState = Device_Idle_SI; - intrPost(); - } else { - devState = Device_Idle_S; - } - } else if (action == ACT_DMA_READY) { - // clear the BSY bit - status &= ~STATUS_BSY_BIT; - // set the DRQ bit - status |= STATUS_DRQ_BIT; - - devState = Transfer_Data_Dma; - - if (dmaState != Dma_Idle) - panic("Inconsistent DMA state, should be Dma_Idle\n"); - - dmaState = Dma_Start; - // wait for the write to the DMA start bit - } - break; - - case Transfer_Data_Dma: - if (action == ACT_CMD_ERROR || action == ACT_DMA_DONE) { - // clear the BSY bit - setComplete(); - // set the seek bit - status |= STATUS_SEEK_BIT; - // clear the controller state for DMA transfer - ctrl->setDmaComplete(this); - - if (!isIENSet()) { - devState = Device_Idle_SI; - intrPost(); - } else { - devState = Device_Idle_S; - } - } - break; - - default: - panic("Unknown IDE device state: %#x\n", devState); - } -} - -void -IdeDisk::serialize(ostream &os) -{ - // Check all outstanding events to see if they are scheduled - // these are all mutually exclusive - Tick reschedule = 0; - Events_t event = None; - - int eventCount = 0; - - if (dmaTransferEvent.scheduled()) { - reschedule = dmaTransferEvent.when(); - event = Transfer; - eventCount++; - } - if (dmaReadWaitEvent.scheduled()) { - reschedule = dmaReadWaitEvent.when(); - event = ReadWait; - eventCount++; - } - if (dmaWriteWaitEvent.scheduled()) { - reschedule = dmaWriteWaitEvent.when(); - event = WriteWait; - eventCount++; - } - if (dmaPrdReadEvent.scheduled()) { - reschedule = dmaPrdReadEvent.when(); - event = PrdRead; - eventCount++; - } - if (dmaReadEvent.scheduled()) { - reschedule = dmaReadEvent.when(); - event = DmaRead; - eventCount++; - } - if (dmaWriteEvent.scheduled()) { - reschedule = dmaWriteEvent.when(); - event = DmaWrite; - eventCount++; - } - - assert(eventCount <= 1); - - SERIALIZE_SCALAR(reschedule); - SERIALIZE_ENUM(event); - - // Serialize device registers - SERIALIZE_SCALAR(cmdReg.data); - SERIALIZE_SCALAR(cmdReg.sec_count); - SERIALIZE_SCALAR(cmdReg.sec_num); - SERIALIZE_SCALAR(cmdReg.cyl_low); - SERIALIZE_SCALAR(cmdReg.cyl_high); - SERIALIZE_SCALAR(cmdReg.drive); - SERIALIZE_SCALAR(cmdReg.command); - SERIALIZE_SCALAR(status); - SERIALIZE_SCALAR(nIENBit); - SERIALIZE_SCALAR(devID); - - // Serialize the PRD related information - SERIALIZE_SCALAR(curPrd.entry.baseAddr); - SERIALIZE_SCALAR(curPrd.entry.byteCount); - SERIALIZE_SCALAR(curPrd.entry.endOfTable); - SERIALIZE_SCALAR(curPrdAddr); - - // Serialize current transfer related information - SERIALIZE_SCALAR(cmdBytesLeft); - SERIALIZE_SCALAR(cmdBytes); - SERIALIZE_SCALAR(drqBytesLeft); - SERIALIZE_SCALAR(curSector); - SERIALIZE_SCALAR(dmaRead); - SERIALIZE_SCALAR(dmaInterfaceBytes); - SERIALIZE_SCALAR(intrPending); - SERIALIZE_ENUM(devState); - SERIALIZE_ENUM(dmaState); - SERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE); -} - -void -IdeDisk::unserialize(Checkpoint *cp, const string §ion) -{ - // Reschedule events that were outstanding - // these are all mutually exclusive - Tick reschedule = 0; - Events_t event = None; - - UNSERIALIZE_SCALAR(reschedule); - UNSERIALIZE_ENUM(event); - - switch (event) { - case None : break; - case Transfer : dmaTransferEvent.schedule(reschedule); break; - case ReadWait : dmaReadWaitEvent.schedule(reschedule); break; - case WriteWait : dmaWriteWaitEvent.schedule(reschedule); break; - case PrdRead : dmaPrdReadEvent.schedule(reschedule); break; - case DmaRead : dmaReadEvent.schedule(reschedule); break; - case DmaWrite : dmaWriteEvent.schedule(reschedule); break; - } - - // Unserialize device registers - UNSERIALIZE_SCALAR(cmdReg.data); - UNSERIALIZE_SCALAR(cmdReg.sec_count); - UNSERIALIZE_SCALAR(cmdReg.sec_num); - UNSERIALIZE_SCALAR(cmdReg.cyl_low); - UNSERIALIZE_SCALAR(cmdReg.cyl_high); - UNSERIALIZE_SCALAR(cmdReg.drive); - UNSERIALIZE_SCALAR(cmdReg.command); - UNSERIALIZE_SCALAR(status); - UNSERIALIZE_SCALAR(nIENBit); - UNSERIALIZE_SCALAR(devID); - - // Unserialize the PRD related information - UNSERIALIZE_SCALAR(curPrd.entry.baseAddr); - UNSERIALIZE_SCALAR(curPrd.entry.byteCount); - UNSERIALIZE_SCALAR(curPrd.entry.endOfTable); - UNSERIALIZE_SCALAR(curPrdAddr); - - // Unserialize current transfer related information - UNSERIALIZE_SCALAR(cmdBytes); - UNSERIALIZE_SCALAR(cmdBytesLeft); - UNSERIALIZE_SCALAR(drqBytesLeft); - UNSERIALIZE_SCALAR(curSector); - UNSERIALIZE_SCALAR(dmaRead); - UNSERIALIZE_SCALAR(dmaInterfaceBytes); - UNSERIALIZE_SCALAR(intrPending); - UNSERIALIZE_ENUM(devState); - UNSERIALIZE_ENUM(dmaState); - UNSERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE); -} - -#ifndef DOXYGEN_SHOULD_SKIP_THIS - -enum DriveID { master, slave }; -static const char *DriveID_strings[] = { "master", "slave" }; -BEGIN_DECLARE_SIM_OBJECT_PARAMS(IdeDisk) - - SimObjectParam<DiskImage *> image; - SimObjectParam<PhysicalMemory *> physmem; - SimpleEnumParam<DriveID> driveID; - Param<int> delay; - -END_DECLARE_SIM_OBJECT_PARAMS(IdeDisk) - -BEGIN_INIT_SIM_OBJECT_PARAMS(IdeDisk) - - INIT_PARAM(image, "Disk image"), - INIT_PARAM(physmem, "Physical memory"), - INIT_ENUM_PARAM(driveID, "Drive ID (0=master 1=slave)", DriveID_strings), - INIT_PARAM_DFLT(delay, "Fixed disk delay in microseconds", 1) - -END_INIT_SIM_OBJECT_PARAMS(IdeDisk) - - -CREATE_SIM_OBJECT(IdeDisk) -{ - return new IdeDisk(getInstanceName(), image, physmem, driveID, delay); -} - -REGISTER_SIM_OBJECT("IdeDisk", IdeDisk) - -#endif //DOXYGEN_SHOULD_SKIP_THIS diff --git a/dev/ide_disk.hh b/dev/ide_disk.hh deleted file mode 100644 index 402ae44ee..000000000 --- a/dev/ide_disk.hh +++ /dev/null @@ -1,373 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** @file - * Device model for an IDE disk - */ - -#ifndef __IDE_DISK_HH__ -#define __IDE_DISK_HH__ - -#include "base/statistics.hh" -#include "dev/disk_image.hh" -#include "dev/ide_atareg.h" -#include "dev/ide_ctrl.hh" -#include "dev/ide_wdcreg.h" -#include "dev/io_device.hh" -#include "sim/eventq.hh" - -#define DMA_BACKOFF_PERIOD 200 - -#define MAX_DMA_SIZE (131072) // 128K -#define MAX_MULTSECT (128) - -#define PRD_BASE_MASK 0xfffffffe -#define PRD_COUNT_MASK 0xfffe -#define PRD_EOT_MASK 0x8000 - -typedef struct PrdEntry { - uint32_t baseAddr; - uint16_t byteCount; - uint16_t endOfTable; -} PrdEntry_t; - -class PrdTableEntry { - public: - PrdEntry_t entry; - - uint32_t getBaseAddr() - { - return (entry.baseAddr & PRD_BASE_MASK); - } - - uint32_t getByteCount() - { - return ((entry.byteCount == 0) ? MAX_DMA_SIZE : - (entry.byteCount & PRD_COUNT_MASK)); - } - - uint16_t getEOT() - { - return (entry.endOfTable & PRD_EOT_MASK); - } -}; - -#define DATA_OFFSET (0) -#define ERROR_OFFSET (1) -#define FEATURES_OFFSET (1) -#define NSECTOR_OFFSET (2) -#define SECTOR_OFFSET (3) -#define LCYL_OFFSET (4) -#define HCYL_OFFSET (5) -#define SELECT_OFFSET (6) -#define DRIVE_OFFSET (6) -#define STATUS_OFFSET (7) -#define COMMAND_OFFSET (7) - -#define CONTROL_OFFSET (2) -#define ALTSTAT_OFFSET (2) - -#define SELECT_DEV_BIT 0x10 -#define CONTROL_RST_BIT 0x04 -#define CONTROL_IEN_BIT 0x02 -#define STATUS_BSY_BIT 0x80 -#define STATUS_DRDY_BIT 0x40 -#define STATUS_DRQ_BIT 0x08 -#define STATUS_SEEK_BIT 0x10 -#define STATUS_DF_BIT 0x20 -#define DRIVE_LBA_BIT 0x40 - -#define DEV0 (0) -#define DEV1 (1) - -typedef struct CommandReg { - uint16_t data; - uint8_t error; - uint8_t sec_count; - uint8_t sec_num; - uint8_t cyl_low; - uint8_t cyl_high; - union { - uint8_t drive; - uint8_t head; - }; - uint8_t command; -} CommandReg_t; - -typedef enum Events { - None = 0, - Transfer, - ReadWait, - WriteWait, - PrdRead, - DmaRead, - DmaWrite -} Events_t; - -typedef enum DevAction { - ACT_NONE = 0, - ACT_CMD_WRITE, - ACT_CMD_COMPLETE, - ACT_CMD_ERROR, - ACT_SELECT_WRITE, - ACT_STAT_READ, - ACT_DATA_READY, - ACT_DATA_READ_BYTE, - ACT_DATA_READ_SHORT, - ACT_DATA_WRITE_BYTE, - ACT_DATA_WRITE_SHORT, - ACT_DMA_READY, - ACT_DMA_DONE, - ACT_SRST_SET, - ACT_SRST_CLEAR -} DevAction_t; - -typedef enum DevState { - // Device idle - Device_Idle_S = 0, - Device_Idle_SI, - Device_Idle_NS, - - // Software reset - Device_Srst, - - // Non-data commands - Command_Execution, - - // PIO data-in (data to host) - Prepare_Data_In, - Data_Ready_INTRQ_In, - Transfer_Data_In, - - // PIO data-out (data from host) - Prepare_Data_Out, - Data_Ready_INTRQ_Out, - Transfer_Data_Out, - - // DMA protocol - Prepare_Data_Dma, - Transfer_Data_Dma -} DevState_t; - -typedef enum DmaState { - Dma_Idle = 0, - Dma_Start, - Dma_Transfer -} DmaState_t; - -class PhysicalMemory; -class IdeController; - -/** - * IDE Disk device model - */ -class IdeDisk : public SimObject -{ - protected: - /** The IDE controller for this disk. */ - IdeController *ctrl; - /** The DMA interface to use for transfers */ - DMAInterface<Bus> *dmaInterface; - /** The image that contains the data of this disk. */ - DiskImage *image; - /** Pointer to physical memory for DMA transfers */ - PhysicalMemory *physmem; - - protected: - /** The disk delay in microseconds. */ - int diskDelay; - - private: - /** Drive identification structure for this disk */ - struct ataparams driveID; - /** Data buffer for transfers */ - uint8_t *dataBuffer; - /** Number of bytes in command data transfer */ - uint32_t cmdBytes; - /** Number of bytes left in command data transfer */ - uint32_t cmdBytesLeft; - /** Number of bytes left in DRQ block */ - uint32_t drqBytesLeft; - /** Current sector in access */ - uint32_t curSector; - /** Command block registers */ - CommandReg_t cmdReg; - /** Status register */ - uint8_t status; - /** Interrupt enable bit */ - bool nIENBit; - /** Device state */ - DevState_t devState; - /** Dma state */ - DmaState_t dmaState; - /** Dma transaction is a read */ - bool dmaRead; - /** PRD table base address */ - uint32_t curPrdAddr; - /** PRD entry */ - PrdTableEntry curPrd; - /** Number of bytes transfered by DMA interface for current transfer */ - uint32_t dmaInterfaceBytes; - /** Device ID (master=0/slave=1) */ - int devID; - /** Interrupt pending */ - bool intrPending; - - Stats::Scalar<> dmaReadFullPages; - Stats::Scalar<> dmaReadBytes; - Stats::Scalar<> dmaReadTxs; - Stats::Scalar<> dmaWriteFullPages; - Stats::Scalar<> dmaWriteBytes; - Stats::Scalar<> dmaWriteTxs; - - public: - /** - * Create and initialize this Disk. - * @param name The name of this disk. - * @param img The disk image of this disk. - * @param phys Pointer to physical memory - * @param id The disk ID (master=0/slave=1) - * @param disk_delay The disk delay in milliseconds - */ - IdeDisk(const std::string &name, DiskImage *img, PhysicalMemory *phys, - int id, Tick disk_delay); - - /** - * Delete the data buffer. - */ - ~IdeDisk(); - - /** - * Reset the device state - */ - void reset(int id); - - /** - * Register statistics. - */ - void regStats(); - - - /** - * Set the controller for this device - * @param c The IDE controller - */ - void setController(IdeController *c, DMAInterface<Bus> *dmaIntr) { - if (ctrl) panic("Cannot change the controller once set!\n"); - ctrl = c; - dmaInterface = dmaIntr; - } - - // Device register read/write - void read(const Addr &offset, IdeRegType regtype, uint8_t *data); - void write(const Addr &offset, IdeRegType regtype, const uint8_t *data); - - // Start/abort functions - void startDma(const uint32_t &prdTableBase); - void abortDma(); - - private: - void startCommand(); - - // Interrupt management - void intrPost(); - void intrClear(); - - // DMA stuff - void doDmaTransfer(); - friend class EventWrapper<IdeDisk, &IdeDisk::doDmaTransfer>; - EventWrapper<IdeDisk, &IdeDisk::doDmaTransfer> dmaTransferEvent; - - void doDmaRead(); - friend class EventWrapper<IdeDisk, &IdeDisk::doDmaRead>; - EventWrapper<IdeDisk, &IdeDisk::doDmaRead> dmaReadWaitEvent; - - void doDmaWrite(); - friend class EventWrapper<IdeDisk, &IdeDisk::doDmaWrite>; - EventWrapper<IdeDisk, &IdeDisk::doDmaWrite> dmaWriteWaitEvent; - - void dmaPrdReadDone(); - friend class EventWrapper<IdeDisk, &IdeDisk::dmaPrdReadDone>; - EventWrapper<IdeDisk, &IdeDisk::dmaPrdReadDone> dmaPrdReadEvent; - - void dmaReadDone(); - friend class EventWrapper<IdeDisk, &IdeDisk::dmaReadDone>; - EventWrapper<IdeDisk, &IdeDisk::dmaReadDone> dmaReadEvent; - - void dmaWriteDone(); - friend class EventWrapper<IdeDisk, &IdeDisk::dmaWriteDone>; - EventWrapper<IdeDisk, &IdeDisk::dmaWriteDone> dmaWriteEvent; - - // Disk image read/write - void readDisk(uint32_t sector, uint8_t *data); - void writeDisk(uint32_t sector, uint8_t *data); - - // State machine management - void updateState(DevAction_t action); - - // Utility functions - bool isBSYSet() { return (status & STATUS_BSY_BIT); } - bool isIENSet() { return nIENBit; } - bool isDEVSelect(); - - void setComplete() - { - // clear out the status byte - status = 0; - // set the DRDY bit - status |= STATUS_DRDY_BIT; - // set the SEEK bit - status |= STATUS_SEEK_BIT; - } - - uint32_t getLBABase() - { - return (Addr)(((cmdReg.head & 0xf) << 24) | (cmdReg.cyl_high << 16) | - (cmdReg.cyl_low << 8) | (cmdReg.sec_num)); - } - - inline Addr pciToDma(Addr pciAddr); - - uint32_t bytesInDmaPage(Addr curAddr, uint32_t bytesLeft); - - /** - * Serialize this object to the given output stream. - * @param os The stream to serialize to. - */ - void serialize(std::ostream &os); - - /** - * Reconstruct the state of this object from a checkpoint. - * @param cp The checkpoint to use. - * @param section The section name describing this object. - */ - void unserialize(Checkpoint *cp, const std::string §ion); -}; - - -#endif // __IDE_DISK_HH__ diff --git a/dev/io_device.cc b/dev/io_device.cc deleted file mode 100644 index 6ab876ab8..000000000 --- a/dev/io_device.cc +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "dev/io_device.hh" -#include "mem/bus/base_interface.hh" -#include "mem/bus/dma_interface.hh" -#include "sim/builder.hh" - -PioDevice::PioDevice(const std::string &name, Platform *p) - : FunctionalMemory(name), platform(p), pioInterface(NULL), pioLatency(0) -{} - -PioDevice::~PioDevice() -{ - if (pioInterface) - delete pioInterface; -} - -DEFINE_SIM_OBJECT_CLASS_NAME("PioDevice", PioDevice) - -DmaDevice::DmaDevice(const std::string &name, Platform *p) - : PioDevice(name, p), dmaInterface(NULL) -{} - -DmaDevice::~DmaDevice() -{ - if (dmaInterface) - delete dmaInterface; -} - -DEFINE_SIM_OBJECT_CLASS_NAME("DmaDevice", DmaDevice) - diff --git a/dev/io_device.hh b/dev/io_device.hh deleted file mode 100644 index bcfd062b9..000000000 --- a/dev/io_device.hh +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __DEV_IO_DEVICE_HH__ -#define __DEV_IO_DEVICE_HH__ - -#include "mem/functional/functional.hh" - -class BaseInterface; -class Bus; -class HierParams; -class Platform; -template <class BusType> class DMAInterface; - -class PioDevice : public FunctionalMemory -{ - protected: - Platform *platform; - BaseInterface *pioInterface; - Tick pioLatency; - - public: - PioDevice(const std::string &name, Platform *p); - virtual ~PioDevice(); -}; - -class DmaDevice : public PioDevice -{ - protected: - DMAInterface<Bus> *dmaInterface; - - public: - DmaDevice(const std::string &name, Platform *p); - virtual ~DmaDevice(); -}; - -#endif // __DEV_IO_DEVICE_HH__ diff --git a/dev/isa_fake.cc b/dev/isa_fake.cc deleted file mode 100644 index 2afebbded..000000000 --- a/dev/isa_fake.cc +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** @file - * Isa Fake Device implementation - */ - -#include <deque> -#include <string> -#include <vector> - -#include "base/trace.hh" -#include "cpu/exec_context.hh" -#include "dev/isa_fake.hh" -#include "mem/bus/bus.hh" -#include "mem/bus/pio_interface.hh" -#include "mem/bus/pio_interface_impl.hh" -#include "mem/functional/memory_control.hh" -#include "sim/builder.hh" -#include "sim/system.hh" - -using namespace std; -using namespace TheISA; - -IsaFake::IsaFake(const string &name, Addr a, MemoryController *mmu, - HierParams *hier, Bus *pio_bus, Addr size) - : PioDevice(name, NULL), addr(a) -{ - mmu->add_child(this, RangeSize(addr, size)); - - if (pio_bus) { - pioInterface = newPioInterface(name + ".pio", hier, pio_bus, this, - &IsaFake::cacheAccess); - pioInterface->addAddrRange(RangeSize(addr, size)); - } -} - -Fault -IsaFake::read(MemReqPtr &req, uint8_t *data) -{ - DPRINTF(Tsunami, "read va=%#x size=%d\n", - req->vaddr, req->size); - -#if TRACING_ON - Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)) >> 6; -#endif - - switch (req->size) { - - case sizeof(uint64_t): - *(uint64_t*)data = 0xFFFFFFFFFFFFFFFFULL; - return NoFault; - case sizeof(uint32_t): - *(uint32_t*)data = 0xFFFFFFFF; - return NoFault; - case sizeof(uint16_t): - *(uint16_t*)data = 0xFFFF; - return NoFault; - case sizeof(uint8_t): - *(uint8_t*)data = 0xFF; - return NoFault; - - default: - panic("invalid access size(?) for PCI configspace!\n"); - } - DPRINTFN("Isa FakeSMC ERROR: read daddr=%#x size=%d\n", daddr, req->size); - - return NoFault; -} - -Fault -IsaFake::write(MemReqPtr &req, const uint8_t *data) -{ - DPRINTF(Tsunami, "write - va=%#x size=%d \n", - req->vaddr, req->size); - - //:Addr daddr = (req->paddr & addr_mask) >> 6; - - return NoFault; -} - -Tick -IsaFake::cacheAccess(MemReqPtr &req) -{ - return curTick; -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(IsaFake) - - SimObjectParam<MemoryController *> mmu; - Param<Addr> addr; - SimObjectParam<Bus*> pio_bus; - Param<Tick> pio_latency; - SimObjectParam<HierParams *> hier; - Param<Addr> size; - -END_DECLARE_SIM_OBJECT_PARAMS(IsaFake) - -BEGIN_INIT_SIM_OBJECT_PARAMS(IsaFake) - - INIT_PARAM(mmu, "Memory Controller"), - INIT_PARAM(addr, "Device Address"), - INIT_PARAM_DFLT(pio_bus, "The IO Bus to attach to", NULL), - INIT_PARAM_DFLT(pio_latency, "Programmed IO latency", 1000), - INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams), - INIT_PARAM_DFLT(size, "Size of address range", 0x8) - -END_INIT_SIM_OBJECT_PARAMS(IsaFake) - -CREATE_SIM_OBJECT(IsaFake) -{ - return new IsaFake(getInstanceName(), addr, mmu, hier, pio_bus, size); -} - -REGISTER_SIM_OBJECT("IsaFake", IsaFake) diff --git a/dev/isa_fake.hh b/dev/isa_fake.hh deleted file mode 100644 index 73e40c681..000000000 --- a/dev/isa_fake.hh +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** @file - * Declaration of a fake device. - */ - -#ifndef __ISA_FAKE_HH__ -#define __ISA_FAKE_HH__ - -#include "dev/tsunami.hh" -#include "base/range.hh" -#include "dev/io_device.hh" - -class MemoryController; - -/** - * IsaFake is a device that returns -1 on all reads and - * accepts all writes. It is meant to be placed at an address range - * so that an mcheck doesn't occur when an os probes a piece of hw - * that doesn't exist (e.g. UARTs1-3). - */ -class IsaFake : public PioDevice -{ - private: - /** The address in memory that we respond to */ - Addr addr; - - public: - /** - * The constructor for Tsunmami Fake just registers itself with the MMU. - * @param name name of this device. - * @param a address to respond to. - * @param mmu the mmu we register with. - * @param size number of addresses to respond to - */ - IsaFake(const std::string &name, Addr a, MemoryController *mmu, - HierParams *hier, Bus *pio_bus, Addr size = 0x8); - - /** - * This read always returns -1. - * @param req The memory request. - * @param data Where to put the data. - */ - virtual Fault read(MemReqPtr &req, uint8_t *data); - - /** - * All writes are simply ignored. - * @param req The memory request. - * @param data the data to not write. - */ - virtual Fault write(MemReqPtr &req, const uint8_t *data); - - /** - * Return how long this access will take. - * @param req the memory request to calcuate - * @return Tick when the request is done - */ - Tick cacheAccess(MemReqPtr &req); -}; - -#endif // __ISA_FAKE_HH__ diff --git a/dev/ns_gige.cc b/dev/ns_gige.cc deleted file mode 100644 index ed8c794f9..000000000 --- a/dev/ns_gige.cc +++ /dev/null @@ -1,3105 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** @file - * Device module for modelling the National Semiconductor - * DP83820 ethernet controller. Does not support priority queueing - */ -#include <cstdio> -#include <deque> -#include <string> - -#include "base/inet.hh" -#include "cpu/exec_context.hh" -#include "dev/etherlink.hh" -#include "dev/ns_gige.hh" -#include "dev/pciconfigall.hh" -#include "mem/bus/bus.hh" -#include "mem/bus/dma_interface.hh" -#include "mem/bus/pio_interface.hh" -#include "mem/bus/pio_interface_impl.hh" -#include "mem/functional/memory_control.hh" -#include "mem/functional/physical.hh" -#include "sim/builder.hh" -#include "sim/debug.hh" -#include "sim/host.hh" -#include "sim/stats.hh" -#include "arch/vtophys.hh" - -const char *NsRxStateStrings[] = -{ - "rxIdle", - "rxDescRefr", - "rxDescRead", - "rxFifoBlock", - "rxFragWrite", - "rxDescWrite", - "rxAdvance" -}; - -const char *NsTxStateStrings[] = -{ - "txIdle", - "txDescRefr", - "txDescRead", - "txFifoBlock", - "txFragRead", - "txDescWrite", - "txAdvance" -}; - -const char *NsDmaState[] = -{ - "dmaIdle", - "dmaReading", - "dmaWriting", - "dmaReadWaiting", - "dmaWriteWaiting" -}; - -using namespace std; -using namespace Net; -using namespace TheISA; - -/////////////////////////////////////////////////////////////////////// -// -// NSGigE PCI Device -// -NSGigE::NSGigE(Params *p) - : PciDev(p), ioEnable(false), - txFifo(p->tx_fifo_size), rxFifo(p->rx_fifo_size), - txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL), - txXferLen(0), rxXferLen(0), clock(p->clock), - txState(txIdle), txEnable(false), CTDD(false), - txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle), - rxEnable(false), CRDD(false), rxPktBytes(0), - rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false), - eepromState(eepromStart), rxDmaReadEvent(this), rxDmaWriteEvent(this), - txDmaReadEvent(this), txDmaWriteEvent(this), - dmaDescFree(p->dma_desc_free), dmaDataFree(p->dma_data_free), - txDelay(p->tx_delay), rxDelay(p->rx_delay), - rxKickTick(0), rxKickEvent(this), txKickTick(0), txKickEvent(this), - txEvent(this), rxFilterEnable(p->rx_filter), acceptBroadcast(false), - acceptMulticast(false), acceptUnicast(false), - acceptPerfect(false), acceptArp(false), multicastHashEnable(false), - physmem(p->pmem), intrTick(0), cpuPendingIntr(false), - intrEvent(0), interface(0) -{ - if (p->pio_bus) { - pioInterface = newPioInterface(name() + ".pio", p->hier, - p->pio_bus, this, - &NSGigE::cacheAccess); - pioLatency = p->pio_latency * p->pio_bus->clockRate; - } - - if (p->header_bus) { - if (p->payload_bus) - dmaInterface = new DMAInterface<Bus>(name() + ".dma", - p->header_bus, - p->payload_bus, 1, - p->dma_no_allocate); - else - dmaInterface = new DMAInterface<Bus>(name() + ".dma", - p->header_bus, - p->header_bus, 1, - p->dma_no_allocate); - } else if (p->payload_bus) - panic("Must define a header bus if defining a payload bus"); - - intrDelay = p->intr_delay; - dmaReadDelay = p->dma_read_delay; - dmaWriteDelay = p->dma_write_delay; - dmaReadFactor = p->dma_read_factor; - dmaWriteFactor = p->dma_write_factor; - - regsReset(); - memcpy(&rom.perfectMatch, p->eaddr.bytes(), ETH_ADDR_LEN); - - memset(&rxDesc32, 0, sizeof(rxDesc32)); - memset(&txDesc32, 0, sizeof(txDesc32)); - memset(&rxDesc64, 0, sizeof(rxDesc64)); - memset(&txDesc64, 0, sizeof(txDesc64)); -} - -NSGigE::~NSGigE() -{} - -void -NSGigE::regStats() -{ - txBytes - .name(name() + ".txBytes") - .desc("Bytes Transmitted") - .prereq(txBytes) - ; - - rxBytes - .name(name() + ".rxBytes") - .desc("Bytes Received") - .prereq(rxBytes) - ; - - txPackets - .name(name() + ".txPackets") - .desc("Number of Packets Transmitted") - .prereq(txBytes) - ; - - rxPackets - .name(name() + ".rxPackets") - .desc("Number of Packets Received") - .prereq(rxBytes) - ; - - txIpChecksums - .name(name() + ".txIpChecksums") - .desc("Number of tx IP Checksums done by device") - .precision(0) - .prereq(txBytes) - ; - - rxIpChecksums - .name(name() + ".rxIpChecksums") - .desc("Number of rx IP Checksums done by device") - .precision(0) - .prereq(rxBytes) - ; - - txTcpChecksums - .name(name() + ".txTcpChecksums") - .desc("Number of tx TCP Checksums done by device") - .precision(0) - .prereq(txBytes) - ; - - rxTcpChecksums - .name(name() + ".rxTcpChecksums") - .desc("Number of rx TCP Checksums done by device") - .precision(0) - .prereq(rxBytes) - ; - - txUdpChecksums - .name(name() + ".txUdpChecksums") - .desc("Number of tx UDP Checksums done by device") - .precision(0) - .prereq(txBytes) - ; - - rxUdpChecksums - .name(name() + ".rxUdpChecksums") - .desc("Number of rx UDP Checksums done by device") - .precision(0) - .prereq(rxBytes) - ; - - descDmaReads - .name(name() + ".descDMAReads") - .desc("Number of descriptors the device read w/ DMA") - .precision(0) - ; - - descDmaWrites - .name(name() + ".descDMAWrites") - .desc("Number of descriptors the device wrote w/ DMA") - .precision(0) - ; - - descDmaRdBytes - .name(name() + ".descDmaReadBytes") - .desc("number of descriptor bytes read w/ DMA") - .precision(0) - ; - - descDmaWrBytes - .name(name() + ".descDmaWriteBytes") - .desc("number of descriptor bytes write w/ DMA") - .precision(0) - ; - - txBandwidth - .name(name() + ".txBandwidth") - .desc("Transmit Bandwidth (bits/s)") - .precision(0) - .prereq(txBytes) - ; - - rxBandwidth - .name(name() + ".rxBandwidth") - .desc("Receive Bandwidth (bits/s)") - .precision(0) - .prereq(rxBytes) - ; - - totBandwidth - .name(name() + ".totBandwidth") - .desc("Total Bandwidth (bits/s)") - .precision(0) - .prereq(totBytes) - ; - - totPackets - .name(name() + ".totPackets") - .desc("Total Packets") - .precision(0) - .prereq(totBytes) - ; - - totBytes - .name(name() + ".totBytes") - .desc("Total Bytes") - .precision(0) - .prereq(totBytes) - ; - - totPacketRate - .name(name() + ".totPPS") - .desc("Total Tranmission Rate (packets/s)") - .precision(0) - .prereq(totBytes) - ; - - txPacketRate - .name(name() + ".txPPS") - .desc("Packet Tranmission Rate (packets/s)") - .precision(0) - .prereq(txBytes) - ; - - rxPacketRate - .name(name() + ".rxPPS") - .desc("Packet Reception Rate (packets/s)") - .precision(0) - .prereq(rxBytes) - ; - - postedSwi - .name(name() + ".postedSwi") - .desc("number of software interrupts posted to CPU") - .precision(0) - ; - - totalSwi - .name(name() + ".totalSwi") - .desc("total number of Swi written to ISR") - .precision(0) - ; - - coalescedSwi - .name(name() + ".coalescedSwi") - .desc("average number of Swi's coalesced into each post") - .precision(0) - ; - - postedRxIdle - .name(name() + ".postedRxIdle") - .desc("number of rxIdle interrupts posted to CPU") - .precision(0) - ; - - totalRxIdle - .name(name() + ".totalRxIdle") - .desc("total number of RxIdle written to ISR") - .precision(0) - ; - - coalescedRxIdle - .name(name() + ".coalescedRxIdle") - .desc("average number of RxIdle's coalesced into each post") - .precision(0) - ; - - postedRxOk - .name(name() + ".postedRxOk") - .desc("number of RxOk interrupts posted to CPU") - .precision(0) - ; - - totalRxOk - .name(name() + ".totalRxOk") - .desc("total number of RxOk written to ISR") - .precision(0) - ; - - coalescedRxOk - .name(name() + ".coalescedRxOk") - .desc("average number of RxOk's coalesced into each post") - .precision(0) - ; - - postedRxDesc - .name(name() + ".postedRxDesc") - .desc("number of RxDesc interrupts posted to CPU") - .precision(0) - ; - - totalRxDesc - .name(name() + ".totalRxDesc") - .desc("total number of RxDesc written to ISR") - .precision(0) - ; - - coalescedRxDesc - .name(name() + ".coalescedRxDesc") - .desc("average number of RxDesc's coalesced into each post") - .precision(0) - ; - - postedTxOk - .name(name() + ".postedTxOk") - .desc("number of TxOk interrupts posted to CPU") - .precision(0) - ; - - totalTxOk - .name(name() + ".totalTxOk") - .desc("total number of TxOk written to ISR") - .precision(0) - ; - - coalescedTxOk - .name(name() + ".coalescedTxOk") - .desc("average number of TxOk's coalesced into each post") - .precision(0) - ; - - postedTxIdle - .name(name() + ".postedTxIdle") - .desc("number of TxIdle interrupts posted to CPU") - .precision(0) - ; - - totalTxIdle - .name(name() + ".totalTxIdle") - .desc("total number of TxIdle written to ISR") - .precision(0) - ; - - coalescedTxIdle - .name(name() + ".coalescedTxIdle") - .desc("average number of TxIdle's coalesced into each post") - .precision(0) - ; - - postedTxDesc - .name(name() + ".postedTxDesc") - .desc("number of TxDesc interrupts posted to CPU") - .precision(0) - ; - - totalTxDesc - .name(name() + ".totalTxDesc") - .desc("total number of TxDesc written to ISR") - .precision(0) - ; - - coalescedTxDesc - .name(name() + ".coalescedTxDesc") - .desc("average number of TxDesc's coalesced into each post") - .precision(0) - ; - - postedRxOrn - .name(name() + ".postedRxOrn") - .desc("number of RxOrn posted to CPU") - .precision(0) - ; - - totalRxOrn - .name(name() + ".totalRxOrn") - .desc("total number of RxOrn written to ISR") - .precision(0) - ; - - coalescedRxOrn - .name(name() + ".coalescedRxOrn") - .desc("average number of RxOrn's coalesced into each post") - .precision(0) - ; - - coalescedTotal - .name(name() + ".coalescedTotal") - .desc("average number of interrupts coalesced into each post") - .precision(0) - ; - - postedInterrupts - .name(name() + ".postedInterrupts") - .desc("number of posts to CPU") - .precision(0) - ; - - droppedPackets - .name(name() + ".droppedPackets") - .desc("number of packets dropped") - .precision(0) - ; - - coalescedSwi = totalSwi / postedInterrupts; - coalescedRxIdle = totalRxIdle / postedInterrupts; - coalescedRxOk = totalRxOk / postedInterrupts; - coalescedRxDesc = totalRxDesc / postedInterrupts; - coalescedTxOk = totalTxOk / postedInterrupts; - coalescedTxIdle = totalTxIdle / postedInterrupts; - coalescedTxDesc = totalTxDesc / postedInterrupts; - coalescedRxOrn = totalRxOrn / postedInterrupts; - - coalescedTotal = (totalSwi + totalRxIdle + totalRxOk + totalRxDesc + - totalTxOk + totalTxIdle + totalTxDesc + - totalRxOrn) / postedInterrupts; - - txBandwidth = txBytes * Stats::constant(8) / simSeconds; - rxBandwidth = rxBytes * Stats::constant(8) / simSeconds; - totBandwidth = txBandwidth + rxBandwidth; - totBytes = txBytes + rxBytes; - totPackets = txPackets + rxPackets; - - txPacketRate = txPackets / simSeconds; - rxPacketRate = rxPackets / simSeconds; -} - -/** - * This is to read the PCI general configuration registers - */ -void -NSGigE::readConfig(int offset, int size, uint8_t *data) -{ - if (offset < PCI_DEVICE_SPECIFIC) - PciDev::readConfig(offset, size, data); - else - panic("Device specific PCI config space not implemented!\n"); -} - -/** - * This is to write to the PCI general configuration registers - */ -void -NSGigE::writeConfig(int offset, int size, const uint8_t* data) -{ - if (offset < PCI_DEVICE_SPECIFIC) - PciDev::writeConfig(offset, size, data); - else - panic("Device specific PCI config space not implemented!\n"); - - // Need to catch writes to BARs to update the PIO interface - switch (offset) { - // seems to work fine without all these PCI settings, but i - // put in the IO to double check, an assertion will fail if we - // need to properly implement it - case PCI_COMMAND: - if (config.data[offset] & PCI_CMD_IOSE) - ioEnable = true; - else - ioEnable = false; - -#if 0 - if (config.data[offset] & PCI_CMD_BME) { - bmEnabled = true; - } - else { - bmEnabled = false; - } - - if (config.data[offset] & PCI_CMD_MSE) { - memEnable = true; - } - else { - memEnable = false; - } -#endif - break; - - case PCI0_BASE_ADDR0: - if (BARAddrs[0] != 0) { - if (pioInterface) - pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0])); - - BARAddrs[0] &= EV5::PAddrUncachedMask; - } - break; - case PCI0_BASE_ADDR1: - if (BARAddrs[1] != 0) { - if (pioInterface) - pioInterface->addAddrRange(RangeSize(BARAddrs[1], BARSize[1])); - - BARAddrs[1] &= EV5::PAddrUncachedMask; - } - break; - } -} - -/** - * This reads the device registers, which are detailed in the NS83820 - * spec sheet - */ -Fault -NSGigE::read(MemReqPtr &req, uint8_t *data) -{ - assert(ioEnable); - - //The mask is to give you only the offset into the device register file - Addr daddr = req->paddr & 0xfff; - DPRINTF(EthernetPIO, "read da=%#x pa=%#x va=%#x size=%d\n", - daddr, req->paddr, req->vaddr, req->size); - - - // there are some reserved registers, you can see ns_gige_reg.h and - // the spec sheet for details - if (daddr > LAST && daddr <= RESERVED) { - panic("Accessing reserved register"); - } else if (daddr > RESERVED && daddr <= 0x3FC) { - readConfig(daddr & 0xff, req->size, data); - return NoFault; - } else if (daddr >= MIB_START && daddr <= MIB_END) { - // don't implement all the MIB's. hopefully the kernel - // doesn't actually DEPEND upon their values - // MIB are just hardware stats keepers - uint32_t ® = *(uint32_t *) data; - reg = 0; - return NoFault; - } else if (daddr > 0x3FC) - panic("Something is messed up!\n"); - - switch (req->size) { - case sizeof(uint32_t): - { - uint32_t ® = *(uint32_t *)data; - uint16_t rfaddr; - - switch (daddr) { - case CR: - reg = regs.command; - //these are supposed to be cleared on a read - reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR); - break; - - case CFGR: - reg = regs.config; - break; - - case MEAR: - reg = regs.mear; - break; - - case PTSCR: - reg = regs.ptscr; - break; - - case ISR: - reg = regs.isr; - devIntrClear(ISR_ALL); - break; - - case IMR: - reg = regs.imr; - break; - - case IER: - reg = regs.ier; - break; - - case IHR: - reg = regs.ihr; - break; - - case TXDP: - reg = regs.txdp; - break; - - case TXDP_HI: - reg = regs.txdp_hi; - break; - - case TX_CFG: - reg = regs.txcfg; - break; - - case GPIOR: - reg = regs.gpior; - break; - - case RXDP: - reg = regs.rxdp; - break; - - case RXDP_HI: - reg = regs.rxdp_hi; - break; - - case RX_CFG: - reg = regs.rxcfg; - break; - - case PQCR: - reg = regs.pqcr; - break; - - case WCSR: - reg = regs.wcsr; - break; - - case PCR: - reg = regs.pcr; - break; - - // see the spec sheet for how RFCR and RFDR work - // basically, you write to RFCR to tell the machine - // what you want to do next, then you act upon RFDR, - // and the device will be prepared b/c of what you - // wrote to RFCR - case RFCR: - reg = regs.rfcr; - break; - - case RFDR: - rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR); - switch (rfaddr) { - // Read from perfect match ROM octets - case 0x000: - reg = rom.perfectMatch[1]; - reg = reg << 8; - reg += rom.perfectMatch[0]; - break; - case 0x002: - reg = rom.perfectMatch[3] << 8; - reg += rom.perfectMatch[2]; - break; - case 0x004: - reg = rom.perfectMatch[5] << 8; - reg += rom.perfectMatch[4]; - break; - default: - // Read filter hash table - if (rfaddr >= FHASH_ADDR && - rfaddr < FHASH_ADDR + FHASH_SIZE) { - - // Only word-aligned reads supported - if (rfaddr % 2) - panic("unaligned read from filter hash table!"); - - reg = rom.filterHash[rfaddr - FHASH_ADDR + 1] << 8; - reg += rom.filterHash[rfaddr - FHASH_ADDR]; - break; - } - - panic("reading RFDR for something other than pattern" - " matching or hashing! %#x\n", rfaddr); - } - break; - - case SRR: - reg = regs.srr; - break; - - case MIBC: - reg = regs.mibc; - reg &= ~(MIBC_MIBS | MIBC_ACLR); - break; - - case VRCR: - reg = regs.vrcr; - break; - - case VTCR: - reg = regs.vtcr; - break; - - case VDR: - reg = regs.vdr; - break; - - case CCSR: - reg = regs.ccsr; - break; - - case TBICR: - reg = regs.tbicr; - break; - - case TBISR: - reg = regs.tbisr; - break; - - case TANAR: - reg = regs.tanar; - break; - - case TANLPAR: - reg = regs.tanlpar; - break; - - case TANER: - reg = regs.taner; - break; - - case TESR: - reg = regs.tesr; - break; - - case M5REG: - reg = 0; - if (params()->rx_thread) - reg |= M5REG_RX_THREAD; - if (params()->tx_thread) - reg |= M5REG_TX_THREAD; - if (params()->rss) - reg |= M5REG_RSS; - break; - - default: - panic("reading unimplemented register: addr=%#x", daddr); - } - - DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n", - daddr, reg, reg); - } - break; - - default: - panic("accessing register with invalid size: addr=%#x, size=%d", - daddr, req->size); - } - - return NoFault; -} - -Fault -NSGigE::write(MemReqPtr &req, const uint8_t *data) -{ - assert(ioEnable); - - Addr daddr = req->paddr & 0xfff; - DPRINTF(EthernetPIO, "write da=%#x pa=%#x va=%#x size=%d\n", - daddr, req->paddr, req->vaddr, req->size); - - if (daddr > LAST && daddr <= RESERVED) { - panic("Accessing reserved register"); - } else if (daddr > RESERVED && daddr <= 0x3FC) { - writeConfig(daddr & 0xff, req->size, data); - return NoFault; - } else if (daddr > 0x3FC) - panic("Something is messed up!\n"); - - if (req->size == sizeof(uint32_t)) { - uint32_t reg = *(uint32_t *)data; - uint16_t rfaddr; - - DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg); - - switch (daddr) { - case CR: - regs.command = reg; - if (reg & CR_TXD) { - txEnable = false; - } else if (reg & CR_TXE) { - txEnable = true; - - // the kernel is enabling the transmit machine - if (txState == txIdle) - txKick(); - } - - if (reg & CR_RXD) { - rxEnable = false; - } else if (reg & CR_RXE) { - rxEnable = true; - - if (rxState == rxIdle) - rxKick(); - } - - if (reg & CR_TXR) - txReset(); - - if (reg & CR_RXR) - rxReset(); - - if (reg & CR_SWI) - devIntrPost(ISR_SWI); - - if (reg & CR_RST) { - txReset(); - rxReset(); - - regsReset(); - } - break; - - case CFGR: - if (reg & CFGR_LNKSTS || - reg & CFGR_SPDSTS || - reg & CFGR_DUPSTS || - reg & CFGR_RESERVED || - reg & CFGR_T64ADDR || - reg & CFGR_PCI64_DET) - - // First clear all writable bits - regs.config &= CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS | - CFGR_RESERVED | CFGR_T64ADDR | - CFGR_PCI64_DET; - // Now set the appropriate writable bits - regs.config |= reg & ~(CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS | - CFGR_RESERVED | CFGR_T64ADDR | - CFGR_PCI64_DET); - -// all these #if 0's are because i don't THINK the kernel needs to -// have these implemented. if there is a problem relating to one of -// these, you may need to add functionality in. - if (reg & CFGR_TBI_EN) ; - if (reg & CFGR_MODE_1000) ; - - if (reg & CFGR_AUTO_1000) - panic("CFGR_AUTO_1000 not implemented!\n"); - - if (reg & CFGR_PINT_DUPSTS || - reg & CFGR_PINT_LNKSTS || - reg & CFGR_PINT_SPDSTS) - ; - - if (reg & CFGR_TMRTEST) ; - if (reg & CFGR_MRM_DIS) ; - if (reg & CFGR_MWI_DIS) ; - - if (reg & CFGR_T64ADDR) ; - // panic("CFGR_T64ADDR is read only register!\n"); - - if (reg & CFGR_PCI64_DET) - panic("CFGR_PCI64_DET is read only register!\n"); - - if (reg & CFGR_DATA64_EN) ; - if (reg & CFGR_M64ADDR) ; - if (reg & CFGR_PHY_RST) ; - if (reg & CFGR_PHY_DIS) ; - - if (reg & CFGR_EXTSTS_EN) - extstsEnable = true; - else - extstsEnable = false; - - if (reg & CFGR_REQALG) ; - if (reg & CFGR_SB) ; - if (reg & CFGR_POW) ; - if (reg & CFGR_EXD) ; - if (reg & CFGR_PESEL) ; - if (reg & CFGR_BROM_DIS) ; - if (reg & CFGR_EXT_125) ; - if (reg & CFGR_BEM) ; - break; - - case MEAR: - // Clear writable bits - regs.mear &= MEAR_EEDO; - // Set appropriate writable bits - regs.mear |= reg & ~MEAR_EEDO; - - // FreeBSD uses the EEPROM to read PMATCH (for the MAC address) - // even though it could get it through RFDR - if (reg & MEAR_EESEL) { - // Rising edge of clock - if (reg & MEAR_EECLK && !eepromClk) - eepromKick(); - } - else { - eepromState = eepromStart; - regs.mear &= ~MEAR_EEDI; - } - - eepromClk = reg & MEAR_EECLK; - - // since phy is completely faked, MEAR_MD* don't matter - if (reg & MEAR_MDIO) ; - if (reg & MEAR_MDDIR) ; - if (reg & MEAR_MDC) ; - break; - - case PTSCR: - regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY); - // these control BISTs for various parts of chip - we - // don't care or do just fake that the BIST is done - if (reg & PTSCR_RBIST_EN) - regs.ptscr |= PTSCR_RBIST_DONE; - if (reg & PTSCR_EEBIST_EN) - regs.ptscr &= ~PTSCR_EEBIST_EN; - if (reg & PTSCR_EELOAD_EN) - regs.ptscr &= ~PTSCR_EELOAD_EN; - break; - - case ISR: /* writing to the ISR has no effect */ - panic("ISR is a read only register!\n"); - - case IMR: - regs.imr = reg; - devIntrChangeMask(); - break; - - case IER: - regs.ier = reg; - break; - - case IHR: - regs.ihr = reg; - /* not going to implement real interrupt holdoff */ - break; - - case TXDP: - regs.txdp = (reg & 0xFFFFFFFC); - assert(txState == txIdle); - CTDD = false; - break; - - case TXDP_HI: - regs.txdp_hi = reg; - break; - - case TX_CFG: - regs.txcfg = reg; -#if 0 - if (reg & TX_CFG_CSI) ; - if (reg & TX_CFG_HBI) ; - if (reg & TX_CFG_MLB) ; - if (reg & TX_CFG_ATP) ; - if (reg & TX_CFG_ECRETRY) { - /* - * this could easily be implemented, but considering - * the network is just a fake pipe, wouldn't make - * sense to do this - */ - } - - if (reg & TX_CFG_BRST_DIS) ; -#endif - -#if 0 - /* we handle our own DMA, ignore the kernel's exhortations */ - if (reg & TX_CFG_MXDMA) ; -#endif - - // also, we currently don't care about fill/drain - // thresholds though this may change in the future with - // more realistic networks or a driver which changes it - // according to feedback - - break; - - case GPIOR: - // Only write writable bits - regs.gpior &= GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN - | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN; - regs.gpior |= reg & ~(GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN - | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN); - /* these just control general purpose i/o pins, don't matter */ - break; - - case RXDP: - regs.rxdp = reg; - CRDD = false; - break; - - case RXDP_HI: - regs.rxdp_hi = reg; - break; - - case RX_CFG: - regs.rxcfg = reg; -#if 0 - if (reg & RX_CFG_AEP) ; - if (reg & RX_CFG_ARP) ; - if (reg & RX_CFG_STRIPCRC) ; - if (reg & RX_CFG_RX_RD) ; - if (reg & RX_CFG_ALP) ; - if (reg & RX_CFG_AIRL) ; - - /* we handle our own DMA, ignore what kernel says about it */ - if (reg & RX_CFG_MXDMA) ; - - //also, we currently don't care about fill/drain thresholds - //though this may change in the future with more realistic - //networks or a driver which changes it according to feedback - if (reg & (RX_CFG_DRTH | RX_CFG_DRTH0)) ; -#endif - break; - - case PQCR: - /* there is no priority queueing used in the linux 2.6 driver */ - regs.pqcr = reg; - break; - - case WCSR: - /* not going to implement wake on LAN */ - regs.wcsr = reg; - break; - - case PCR: - /* not going to implement pause control */ - regs.pcr = reg; - break; - - case RFCR: - regs.rfcr = reg; - - rxFilterEnable = (reg & RFCR_RFEN) ? true : false; - acceptBroadcast = (reg & RFCR_AAB) ? true : false; - acceptMulticast = (reg & RFCR_AAM) ? true : false; - acceptUnicast = (reg & RFCR_AAU) ? true : false; - acceptPerfect = (reg & RFCR_APM) ? true : false; - acceptArp = (reg & RFCR_AARP) ? true : false; - multicastHashEnable = (reg & RFCR_MHEN) ? true : false; - -#if 0 - if (reg & RFCR_APAT) - panic("RFCR_APAT not implemented!\n"); -#endif - if (reg & RFCR_UHEN) - panic("Unicast hash filtering not used by drivers!\n"); - - if (reg & RFCR_ULM) - panic("RFCR_ULM not implemented!\n"); - - break; - - case RFDR: - rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR); - switch (rfaddr) { - case 0x000: - rom.perfectMatch[0] = (uint8_t)reg; - rom.perfectMatch[1] = (uint8_t)(reg >> 8); - break; - case 0x002: - rom.perfectMatch[2] = (uint8_t)reg; - rom.perfectMatch[3] = (uint8_t)(reg >> 8); - break; - case 0x004: - rom.perfectMatch[4] = (uint8_t)reg; - rom.perfectMatch[5] = (uint8_t)(reg >> 8); - break; - default: - - if (rfaddr >= FHASH_ADDR && - rfaddr < FHASH_ADDR + FHASH_SIZE) { - - // Only word-aligned writes supported - if (rfaddr % 2) - panic("unaligned write to filter hash table!"); - - rom.filterHash[rfaddr - FHASH_ADDR] = (uint8_t)reg; - rom.filterHash[rfaddr - FHASH_ADDR + 1] - = (uint8_t)(reg >> 8); - break; - } - panic("writing RFDR for something other than pattern matching\ - or hashing! %#x\n", rfaddr); - } - - case BRAR: - regs.brar = reg; - break; - - case BRDR: - panic("the driver never uses BRDR, something is wrong!\n"); - - case SRR: - panic("SRR is read only register!\n"); - - case MIBC: - panic("the driver never uses MIBC, something is wrong!\n"); - - case VRCR: - regs.vrcr = reg; - break; - - case VTCR: - regs.vtcr = reg; - break; - - case VDR: - panic("the driver never uses VDR, something is wrong!\n"); - - case CCSR: - /* not going to implement clockrun stuff */ - regs.ccsr = reg; - break; - - case TBICR: - regs.tbicr = reg; - if (reg & TBICR_MR_LOOPBACK) - panic("TBICR_MR_LOOPBACK never used, something wrong!\n"); - - if (reg & TBICR_MR_AN_ENABLE) { - regs.tanlpar = regs.tanar; - regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS); - } - -#if 0 - if (reg & TBICR_MR_RESTART_AN) ; -#endif - - break; - - case TBISR: - panic("TBISR is read only register!\n"); - - case TANAR: - // Only write the writable bits - regs.tanar &= TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED; - regs.tanar |= reg & ~(TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED); - - // Pause capability unimplemented -#if 0 - if (reg & TANAR_PS2) ; - if (reg & TANAR_PS1) ; -#endif - - break; - - case TANLPAR: - panic("this should only be written to by the fake phy!\n"); - - case TANER: - panic("TANER is read only register!\n"); - - case TESR: - regs.tesr = reg; - break; - - default: - panic("invalid register access daddr=%#x", daddr); - } - } else { - panic("Invalid Request Size"); - } - - return NoFault; -} - -void -NSGigE::devIntrPost(uint32_t interrupts) -{ - if (interrupts & ISR_RESERVE) - panic("Cannot set a reserved interrupt"); - - if (interrupts & ISR_NOIMPL) - warn("interrupt not implemented %#x\n", interrupts); - - interrupts &= ISR_IMPL; - regs.isr |= interrupts; - - if (interrupts & regs.imr) { - if (interrupts & ISR_SWI) { - totalSwi++; - } - if (interrupts & ISR_RXIDLE) { - totalRxIdle++; - } - if (interrupts & ISR_RXOK) { - totalRxOk++; - } - if (interrupts & ISR_RXDESC) { - totalRxDesc++; - } - if (interrupts & ISR_TXOK) { - totalTxOk++; - } - if (interrupts & ISR_TXIDLE) { - totalTxIdle++; - } - if (interrupts & ISR_TXDESC) { - totalTxDesc++; - } - if (interrupts & ISR_RXORN) { - totalRxOrn++; - } - } - - DPRINTF(EthernetIntr, - "interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n", - interrupts, regs.isr, regs.imr); - - if ((regs.isr & regs.imr)) { - Tick when = curTick; - if ((regs.isr & regs.imr & ISR_NODELAY) == 0) - when += intrDelay; - cpuIntrPost(when); - } -} - -/* writing this interrupt counting stats inside this means that this function - is now limited to being used to clear all interrupts upon the kernel - reading isr and servicing. just telling you in case you were thinking - of expanding use. -*/ -void -NSGigE::devIntrClear(uint32_t interrupts) -{ - if (interrupts & ISR_RESERVE) - panic("Cannot clear a reserved interrupt"); - - if (regs.isr & regs.imr & ISR_SWI) { - postedSwi++; - } - if (regs.isr & regs.imr & ISR_RXIDLE) { - postedRxIdle++; - } - if (regs.isr & regs.imr & ISR_RXOK) { - postedRxOk++; - } - if (regs.isr & regs.imr & ISR_RXDESC) { - postedRxDesc++; - } - if (regs.isr & regs.imr & ISR_TXOK) { - postedTxOk++; - } - if (regs.isr & regs.imr & ISR_TXIDLE) { - postedTxIdle++; - } - if (regs.isr & regs.imr & ISR_TXDESC) { - postedTxDesc++; - } - if (regs.isr & regs.imr & ISR_RXORN) { - postedRxOrn++; - } - - if (regs.isr & regs.imr & ISR_IMPL) - postedInterrupts++; - - interrupts &= ~ISR_NOIMPL; - regs.isr &= ~interrupts; - - DPRINTF(EthernetIntr, - "interrupt cleared from ISR: intr=%x isr=%x imr=%x\n", - interrupts, regs.isr, regs.imr); - - if (!(regs.isr & regs.imr)) - cpuIntrClear(); -} - -void -NSGigE::devIntrChangeMask() -{ - DPRINTF(EthernetIntr, "interrupt mask changed: isr=%x imr=%x masked=%x\n", - regs.isr, regs.imr, regs.isr & regs.imr); - - if (regs.isr & regs.imr) - cpuIntrPost(curTick); - else - cpuIntrClear(); -} - -void -NSGigE::cpuIntrPost(Tick when) -{ - // If the interrupt you want to post is later than an interrupt - // already scheduled, just let it post in the coming one and don't - // schedule another. - // HOWEVER, must be sure that the scheduled intrTick is in the - // future (this was formerly the source of a bug) - /** - * @todo this warning should be removed and the intrTick code should - * be fixed. - */ - assert(when >= curTick); - assert(intrTick >= curTick || intrTick == 0); - if (when > intrTick && intrTick != 0) { - DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n", - intrTick); - return; - } - - intrTick = when; - if (intrTick < curTick) { - debug_break(); - intrTick = curTick; - } - - DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n", - intrTick); - - if (intrEvent) - intrEvent->squash(); - intrEvent = new IntrEvent(this, true); - intrEvent->schedule(intrTick); -} - -void -NSGigE::cpuInterrupt() -{ - assert(intrTick == curTick); - - // Whether or not there's a pending interrupt, we don't care about - // it anymore - intrEvent = 0; - intrTick = 0; - - // Don't send an interrupt if there's already one - if (cpuPendingIntr) { - DPRINTF(EthernetIntr, - "would send an interrupt now, but there's already pending\n"); - } else { - // Send interrupt - cpuPendingIntr = true; - - DPRINTF(EthernetIntr, "posting interrupt\n"); - intrPost(); - } -} - -void -NSGigE::cpuIntrClear() -{ - if (!cpuPendingIntr) - return; - - if (intrEvent) { - intrEvent->squash(); - intrEvent = 0; - } - - intrTick = 0; - - cpuPendingIntr = false; - - DPRINTF(EthernetIntr, "clearing interrupt\n"); - intrClear(); -} - -bool -NSGigE::cpuIntrPending() const -{ return cpuPendingIntr; } - -void -NSGigE::txReset() -{ - - DPRINTF(Ethernet, "transmit reset\n"); - - CTDD = false; - txEnable = false;; - txFragPtr = 0; - assert(txDescCnt == 0); - txFifo.clear(); - txState = txIdle; - assert(txDmaState == dmaIdle); -} - -void -NSGigE::rxReset() -{ - DPRINTF(Ethernet, "receive reset\n"); - - CRDD = false; - assert(rxPktBytes == 0); - rxEnable = false; - rxFragPtr = 0; - assert(rxDescCnt == 0); - assert(rxDmaState == dmaIdle); - rxFifo.clear(); - rxState = rxIdle; -} - -void -NSGigE::regsReset() -{ - memset(®s, 0, sizeof(regs)); - regs.config = (CFGR_LNKSTS | CFGR_TBI_EN | CFGR_MODE_1000); - regs.mear = 0x12; - regs.txcfg = 0x120; // set drain threshold to 1024 bytes and - // fill threshold to 32 bytes - regs.rxcfg = 0x4; // set drain threshold to 16 bytes - regs.srr = 0x0103; // set the silicon revision to rev B or 0x103 - regs.mibc = MIBC_FRZ; - regs.vdr = 0x81; // set the vlan tag type to 802.1q - regs.tesr = 0xc000; // TBI capable of both full and half duplex - regs.brar = 0xffffffff; - - extstsEnable = false; - acceptBroadcast = false; - acceptMulticast = false; - acceptUnicast = false; - acceptPerfect = false; - acceptArp = false; -} - -void -NSGigE::rxDmaReadCopy() -{ - assert(rxDmaState == dmaReading); - - physmem->dma_read((uint8_t *)rxDmaData, rxDmaAddr, rxDmaLen); - rxDmaState = dmaIdle; - - DPRINTF(EthernetDMA, "rx dma read paddr=%#x len=%d\n", - rxDmaAddr, rxDmaLen); - DDUMP(EthernetDMA, rxDmaData, rxDmaLen); -} - -bool -NSGigE::doRxDmaRead() -{ - assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting); - rxDmaState = dmaReading; - - if (dmaInterface && !rxDmaFree) { - if (dmaInterface->busy()) - rxDmaState = dmaReadWaiting; - else - dmaInterface->doDMA(Read, rxDmaAddr, rxDmaLen, curTick, - &rxDmaReadEvent, true); - return true; - } - - if (dmaReadDelay == 0 && dmaReadFactor == 0) { - rxDmaReadCopy(); - return false; - } - - Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor; - Tick start = curTick + dmaReadDelay + factor; - rxDmaReadEvent.schedule(start); - return true; -} - -void -NSGigE::rxDmaReadDone() -{ - assert(rxDmaState == dmaReading); - rxDmaReadCopy(); - - // If the transmit state machine has a pending DMA, let it go first - if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) - txKick(); - - rxKick(); -} - -void -NSGigE::rxDmaWriteCopy() -{ - assert(rxDmaState == dmaWriting); - - physmem->dma_write(rxDmaAddr, (uint8_t *)rxDmaData, rxDmaLen); - rxDmaState = dmaIdle; - - DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n", - rxDmaAddr, rxDmaLen); - DDUMP(EthernetDMA, rxDmaData, rxDmaLen); -} - -bool -NSGigE::doRxDmaWrite() -{ - assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting); - rxDmaState = dmaWriting; - - if (dmaInterface && !rxDmaFree) { - if (dmaInterface->busy()) - rxDmaState = dmaWriteWaiting; - else - dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen, curTick, - &rxDmaWriteEvent, true); - return true; - } - - if (dmaWriteDelay == 0 && dmaWriteFactor == 0) { - rxDmaWriteCopy(); - return false; - } - - Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor; - Tick start = curTick + dmaWriteDelay + factor; - rxDmaWriteEvent.schedule(start); - return true; -} - -void -NSGigE::rxDmaWriteDone() -{ - assert(rxDmaState == dmaWriting); - rxDmaWriteCopy(); - - // If the transmit state machine has a pending DMA, let it go first - if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) - txKick(); - - rxKick(); -} - -void -NSGigE::rxKick() -{ - bool is64bit = (bool)(regs.config & CFGR_M64ADDR); - - DPRINTF(EthernetSM, - "receive kick rxState=%s (rxBuf.size=%d) %d-bit\n", - NsRxStateStrings[rxState], rxFifo.size(), is64bit ? 64 : 32); - - Addr link, bufptr; - uint32_t &cmdsts = is64bit ? rxDesc64.cmdsts : rxDesc32.cmdsts; - uint32_t &extsts = is64bit ? rxDesc64.extsts : rxDesc32.extsts; - - next: - if (clock) { - if (rxKickTick > curTick) { - DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n", - rxKickTick); - - goto exit; - } - - // Go to the next state machine clock tick. - rxKickTick = curTick + cycles(1); - } - - switch(rxDmaState) { - case dmaReadWaiting: - if (doRxDmaRead()) - goto exit; - break; - case dmaWriteWaiting: - if (doRxDmaWrite()) - goto exit; - break; - default: - break; - } - - link = is64bit ? (Addr)rxDesc64.link : (Addr)rxDesc32.link; - bufptr = is64bit ? (Addr)rxDesc64.bufptr : (Addr)rxDesc32.bufptr; - - // see state machine from spec for details - // the way this works is, if you finish work on one state and can - // go directly to another, you do that through jumping to the - // label "next". however, if you have intermediate work, like DMA - // so that you can't go to the next state yet, you go to exit and - // exit the loop. however, when the DMA is done it will trigger - // an event and come back to this loop. - switch (rxState) { - case rxIdle: - if (!rxEnable) { - DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n"); - goto exit; - } - - if (CRDD) { - rxState = rxDescRefr; - - rxDmaAddr = regs.rxdp & 0x3fffffff; - rxDmaData = - is64bit ? (void *)&rxDesc64.link : (void *)&rxDesc32.link; - rxDmaLen = is64bit ? sizeof(rxDesc64.link) : sizeof(rxDesc32.link); - rxDmaFree = dmaDescFree; - - descDmaReads++; - descDmaRdBytes += rxDmaLen; - - if (doRxDmaRead()) - goto exit; - } else { - rxState = rxDescRead; - - rxDmaAddr = regs.rxdp & 0x3fffffff; - rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32; - rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32); - rxDmaFree = dmaDescFree; - - descDmaReads++; - descDmaRdBytes += rxDmaLen; - - if (doRxDmaRead()) - goto exit; - } - break; - - case rxDescRefr: - if (rxDmaState != dmaIdle) - goto exit; - - rxState = rxAdvance; - break; - - case rxDescRead: - if (rxDmaState != dmaIdle) - goto exit; - - DPRINTF(EthernetDesc, "rxDesc: addr=%08x read descriptor\n", - regs.rxdp & 0x3fffffff); - DPRINTF(EthernetDesc, - "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n", - link, bufptr, cmdsts, extsts); - - if (cmdsts & CMDSTS_OWN) { - devIntrPost(ISR_RXIDLE); - rxState = rxIdle; - goto exit; - } else { - rxState = rxFifoBlock; - rxFragPtr = bufptr; - rxDescCnt = cmdsts & CMDSTS_LEN_MASK; - } - break; - - case rxFifoBlock: - if (!rxPacket) { - /** - * @todo in reality, we should be able to start processing - * the packet as it arrives, and not have to wait for the - * full packet ot be in the receive fifo. - */ - if (rxFifo.empty()) - goto exit; - - DPRINTF(EthernetSM, "****processing receive of new packet****\n"); - - // If we don't have a packet, grab a new one from the fifo. - rxPacket = rxFifo.front(); - rxPktBytes = rxPacket->length; - rxPacketBufPtr = rxPacket->data; - -#if TRACING_ON - if (DTRACE(Ethernet)) { - IpPtr ip(rxPacket); - if (ip) { - DPRINTF(Ethernet, "ID is %d\n", ip->id()); - TcpPtr tcp(ip); - if (tcp) { - DPRINTF(Ethernet, - "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", - tcp->sport(), tcp->dport(), tcp->seq(), - tcp->ack()); - } - } - } -#endif - - // sanity check - i think the driver behaves like this - assert(rxDescCnt >= rxPktBytes); - rxFifo.pop(); - } - - - // dont' need the && rxDescCnt > 0 if driver sanity check - // above holds - if (rxPktBytes > 0) { - rxState = rxFragWrite; - // don't need min<>(rxPktBytes,rxDescCnt) if above sanity - // check holds - rxXferLen = rxPktBytes; - - rxDmaAddr = rxFragPtr & 0x3fffffff; - rxDmaData = rxPacketBufPtr; - rxDmaLen = rxXferLen; - rxDmaFree = dmaDataFree; - - if (doRxDmaWrite()) - goto exit; - - } else { - rxState = rxDescWrite; - - //if (rxPktBytes == 0) { /* packet is done */ - assert(rxPktBytes == 0); - DPRINTF(EthernetSM, "done with receiving packet\n"); - - cmdsts |= CMDSTS_OWN; - cmdsts &= ~CMDSTS_MORE; - cmdsts |= CMDSTS_OK; - cmdsts &= 0xffff0000; - cmdsts += rxPacket->length; //i.e. set CMDSTS_SIZE - -#if 0 - /* - * all the driver uses these are for its own stats keeping - * which we don't care about, aren't necessary for - * functionality and doing this would just slow us down. - * if they end up using this in a later version for - * functional purposes, just undef - */ - if (rxFilterEnable) { - cmdsts &= ~CMDSTS_DEST_MASK; - const EthAddr &dst = rxFifoFront()->dst(); - if (dst->unicast()) - cmdsts |= CMDSTS_DEST_SELF; - if (dst->multicast()) - cmdsts |= CMDSTS_DEST_MULTI; - if (dst->broadcast()) - cmdsts |= CMDSTS_DEST_MASK; - } -#endif - - IpPtr ip(rxPacket); - if (extstsEnable && ip) { - extsts |= EXTSTS_IPPKT; - rxIpChecksums++; - if (cksum(ip) != 0) { - DPRINTF(EthernetCksum, "Rx IP Checksum Error\n"); - extsts |= EXTSTS_IPERR; - } - TcpPtr tcp(ip); - UdpPtr udp(ip); - if (tcp) { - extsts |= EXTSTS_TCPPKT; - rxTcpChecksums++; - if (cksum(tcp) != 0) { - DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n"); - extsts |= EXTSTS_TCPERR; - - } - } else if (udp) { - extsts |= EXTSTS_UDPPKT; - rxUdpChecksums++; - if (cksum(udp) != 0) { - DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n"); - extsts |= EXTSTS_UDPERR; - } - } - } - rxPacket = 0; - - /* - * the driver seems to always receive into desc buffers - * of size 1514, so you never have a pkt that is split - * into multiple descriptors on the receive side, so - * i don't implement that case, hence the assert above. - */ - - DPRINTF(EthernetDesc, - "rxDesc: addr=%08x writeback cmdsts extsts\n", - regs.rxdp & 0x3fffffff); - DPRINTF(EthernetDesc, - "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n", - link, bufptr, cmdsts, extsts); - - rxDmaAddr = regs.rxdp & 0x3fffffff; - rxDmaData = &cmdsts; - if (is64bit) { - rxDmaAddr += offsetof(ns_desc64, cmdsts); - rxDmaLen = sizeof(rxDesc64.cmdsts) + sizeof(rxDesc64.extsts); - } else { - rxDmaAddr += offsetof(ns_desc32, cmdsts); - rxDmaLen = sizeof(rxDesc32.cmdsts) + sizeof(rxDesc32.extsts); - } - rxDmaFree = dmaDescFree; - - descDmaWrites++; - descDmaWrBytes += rxDmaLen; - - if (doRxDmaWrite()) - goto exit; - } - break; - - case rxFragWrite: - if (rxDmaState != dmaIdle) - goto exit; - - rxPacketBufPtr += rxXferLen; - rxFragPtr += rxXferLen; - rxPktBytes -= rxXferLen; - - rxState = rxFifoBlock; - break; - - case rxDescWrite: - if (rxDmaState != dmaIdle) - goto exit; - - assert(cmdsts & CMDSTS_OWN); - - assert(rxPacket == 0); - devIntrPost(ISR_RXOK); - - if (cmdsts & CMDSTS_INTR) - devIntrPost(ISR_RXDESC); - - if (!rxEnable) { - DPRINTF(EthernetSM, "Halting the RX state machine\n"); - rxState = rxIdle; - goto exit; - } else - rxState = rxAdvance; - break; - - case rxAdvance: - if (link == 0) { - devIntrPost(ISR_RXIDLE); - rxState = rxIdle; - CRDD = true; - goto exit; - } else { - if (rxDmaState != dmaIdle) - goto exit; - rxState = rxDescRead; - regs.rxdp = link; - CRDD = false; - - rxDmaAddr = regs.rxdp & 0x3fffffff; - rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32; - rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32); - rxDmaFree = dmaDescFree; - - if (doRxDmaRead()) - goto exit; - } - break; - - default: - panic("Invalid rxState!"); - } - - DPRINTF(EthernetSM, "entering next rxState=%s\n", - NsRxStateStrings[rxState]); - goto next; - - exit: - /** - * @todo do we want to schedule a future kick? - */ - DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n", - NsRxStateStrings[rxState]); - - if (clock && !rxKickEvent.scheduled()) - rxKickEvent.schedule(rxKickTick); -} - -void -NSGigE::transmit() -{ - if (txFifo.empty()) { - DPRINTF(Ethernet, "nothing to transmit\n"); - return; - } - - DPRINTF(Ethernet, "Attempt Pkt Transmit: txFifo length=%d\n", - txFifo.size()); - if (interface->sendPacket(txFifo.front())) { -#if TRACING_ON - if (DTRACE(Ethernet)) { - IpPtr ip(txFifo.front()); - if (ip) { - DPRINTF(Ethernet, "ID is %d\n", ip->id()); - TcpPtr tcp(ip); - if (tcp) { - DPRINTF(Ethernet, - "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", - tcp->sport(), tcp->dport(), tcp->seq(), - tcp->ack()); - } - } - } -#endif - - DDUMP(EthernetData, txFifo.front()->data, txFifo.front()->length); - txBytes += txFifo.front()->length; - txPackets++; - - DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n", - txFifo.avail()); - txFifo.pop(); - - /* - * normally do a writeback of the descriptor here, and ONLY - * after that is done, send this interrupt. but since our - * stuff never actually fails, just do this interrupt here, - * otherwise the code has to stray from this nice format. - * besides, it's functionally the same. - */ - devIntrPost(ISR_TXOK); - } - - if (!txFifo.empty() && !txEvent.scheduled()) { - DPRINTF(Ethernet, "reschedule transmit\n"); - txEvent.schedule(curTick + retryTime); - } -} - -void -NSGigE::txDmaReadCopy() -{ - assert(txDmaState == dmaReading); - - physmem->dma_read((uint8_t *)txDmaData, txDmaAddr, txDmaLen); - txDmaState = dmaIdle; - - DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n", - txDmaAddr, txDmaLen); - DDUMP(EthernetDMA, txDmaData, txDmaLen); -} - -bool -NSGigE::doTxDmaRead() -{ - assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting); - txDmaState = dmaReading; - - if (dmaInterface && !txDmaFree) { - if (dmaInterface->busy()) - txDmaState = dmaReadWaiting; - else - dmaInterface->doDMA(Read, txDmaAddr, txDmaLen, curTick, - &txDmaReadEvent, true); - return true; - } - - if (dmaReadDelay == 0 && dmaReadFactor == 0.0) { - txDmaReadCopy(); - return false; - } - - Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor; - Tick start = curTick + dmaReadDelay + factor; - txDmaReadEvent.schedule(start); - return true; -} - -void -NSGigE::txDmaReadDone() -{ - assert(txDmaState == dmaReading); - txDmaReadCopy(); - - // If the receive state machine has a pending DMA, let it go first - if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) - rxKick(); - - txKick(); -} - -void -NSGigE::txDmaWriteCopy() -{ - assert(txDmaState == dmaWriting); - - physmem->dma_write(txDmaAddr, (uint8_t *)txDmaData, txDmaLen); - txDmaState = dmaIdle; - - DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n", - txDmaAddr, txDmaLen); - DDUMP(EthernetDMA, txDmaData, txDmaLen); -} - -bool -NSGigE::doTxDmaWrite() -{ - assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting); - txDmaState = dmaWriting; - - if (dmaInterface && !txDmaFree) { - if (dmaInterface->busy()) - txDmaState = dmaWriteWaiting; - else - dmaInterface->doDMA(WriteInvalidate, txDmaAddr, txDmaLen, curTick, - &txDmaWriteEvent, true); - return true; - } - - if (dmaWriteDelay == 0 && dmaWriteFactor == 0.0) { - txDmaWriteCopy(); - return false; - } - - Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor; - Tick start = curTick + dmaWriteDelay + factor; - txDmaWriteEvent.schedule(start); - return true; -} - -void -NSGigE::txDmaWriteDone() -{ - assert(txDmaState == dmaWriting); - txDmaWriteCopy(); - - // If the receive state machine has a pending DMA, let it go first - if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) - rxKick(); - - txKick(); -} - -void -NSGigE::txKick() -{ - bool is64bit = (bool)(regs.config & CFGR_M64ADDR); - - DPRINTF(EthernetSM, "transmit kick txState=%s %d-bit\n", - NsTxStateStrings[txState], is64bit ? 64 : 32); - - Addr link, bufptr; - uint32_t &cmdsts = is64bit ? txDesc64.cmdsts : txDesc32.cmdsts; - uint32_t &extsts = is64bit ? txDesc64.extsts : txDesc32.extsts; - - next: - if (clock) { - if (txKickTick > curTick) { - DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n", - txKickTick); - goto exit; - } - - // Go to the next state machine clock tick. - txKickTick = curTick + cycles(1); - } - - switch(txDmaState) { - case dmaReadWaiting: - if (doTxDmaRead()) - goto exit; - break; - case dmaWriteWaiting: - if (doTxDmaWrite()) - goto exit; - break; - default: - break; - } - - link = is64bit ? (Addr)txDesc64.link : (Addr)txDesc32.link; - bufptr = is64bit ? (Addr)txDesc64.bufptr : (Addr)txDesc32.bufptr; - switch (txState) { - case txIdle: - if (!txEnable) { - DPRINTF(EthernetSM, "Transmit disabled. Nothing to do.\n"); - goto exit; - } - - if (CTDD) { - txState = txDescRefr; - - txDmaAddr = regs.txdp & 0x3fffffff; - txDmaData = - is64bit ? (void *)&txDesc64.link : (void *)&txDesc32.link; - txDmaLen = is64bit ? sizeof(txDesc64.link) : sizeof(txDesc32.link); - txDmaFree = dmaDescFree; - - descDmaReads++; - descDmaRdBytes += txDmaLen; - - if (doTxDmaRead()) - goto exit; - - } else { - txState = txDescRead; - - txDmaAddr = regs.txdp & 0x3fffffff; - txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32; - txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32); - txDmaFree = dmaDescFree; - - descDmaReads++; - descDmaRdBytes += txDmaLen; - - if (doTxDmaRead()) - goto exit; - } - break; - - case txDescRefr: - if (txDmaState != dmaIdle) - goto exit; - - txState = txAdvance; - break; - - case txDescRead: - if (txDmaState != dmaIdle) - goto exit; - - DPRINTF(EthernetDesc, "txDesc: addr=%08x read descriptor\n", - regs.txdp & 0x3fffffff); - DPRINTF(EthernetDesc, - "txDesc: link=%#x bufptr=%#x cmdsts=%#08x extsts=%#08x\n", - link, bufptr, cmdsts, extsts); - - if (cmdsts & CMDSTS_OWN) { - txState = txFifoBlock; - txFragPtr = bufptr; - txDescCnt = cmdsts & CMDSTS_LEN_MASK; - } else { - devIntrPost(ISR_TXIDLE); - txState = txIdle; - goto exit; - } - break; - - case txFifoBlock: - if (!txPacket) { - DPRINTF(EthernetSM, "****starting the tx of a new packet****\n"); - txPacket = new PacketData(16384); - txPacketBufPtr = txPacket->data; - } - - if (txDescCnt == 0) { - DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n"); - if (cmdsts & CMDSTS_MORE) { - DPRINTF(EthernetSM, "there are more descriptors to come\n"); - txState = txDescWrite; - - cmdsts &= ~CMDSTS_OWN; - - txDmaAddr = regs.txdp & 0x3fffffff; - txDmaData = &cmdsts; - if (is64bit) { - txDmaAddr += offsetof(ns_desc64, cmdsts); - txDmaLen = sizeof(txDesc64.cmdsts); - } else { - txDmaAddr += offsetof(ns_desc32, cmdsts); - txDmaLen = sizeof(txDesc32.cmdsts); - } - txDmaFree = dmaDescFree; - - if (doTxDmaWrite()) - goto exit; - - } else { /* this packet is totally done */ - DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n"); - /* deal with the the packet that just finished */ - if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) { - IpPtr ip(txPacket); - if (extsts & EXTSTS_UDPPKT) { - UdpPtr udp(ip); - udp->sum(0); - udp->sum(cksum(udp)); - txUdpChecksums++; - } else if (extsts & EXTSTS_TCPPKT) { - TcpPtr tcp(ip); - tcp->sum(0); - tcp->sum(cksum(tcp)); - txTcpChecksums++; - } - if (extsts & EXTSTS_IPPKT) { - ip->sum(0); - ip->sum(cksum(ip)); - txIpChecksums++; - } - } - - txPacket->length = txPacketBufPtr - txPacket->data; - // this is just because the receive can't handle a - // packet bigger want to make sure - if (txPacket->length > 1514) - panic("transmit packet too large, %s > 1514\n", - txPacket->length); - -#ifndef NDEBUG - bool success = -#endif - txFifo.push(txPacket); - assert(success); - - /* - * this following section is not tqo spec, but - * functionally shouldn't be any different. normally, - * the chip will wait til the transmit has occurred - * before writing back the descriptor because it has - * to wait to see that it was successfully transmitted - * to decide whether to set CMDSTS_OK or not. - * however, in the simulator since it is always - * successfully transmitted, and writing it exactly to - * spec would complicate the code, we just do it here - */ - - cmdsts &= ~CMDSTS_OWN; - cmdsts |= CMDSTS_OK; - - DPRINTF(EthernetDesc, - "txDesc writeback: cmdsts=%08x extsts=%08x\n", - cmdsts, extsts); - - txDmaFree = dmaDescFree; - txDmaAddr = regs.txdp & 0x3fffffff; - txDmaData = &cmdsts; - if (is64bit) { - txDmaAddr += offsetof(ns_desc64, cmdsts); - txDmaLen = - sizeof(txDesc64.cmdsts) + sizeof(txDesc64.extsts); - } else { - txDmaAddr += offsetof(ns_desc32, cmdsts); - txDmaLen = - sizeof(txDesc32.cmdsts) + sizeof(txDesc32.extsts); - } - - descDmaWrites++; - descDmaWrBytes += txDmaLen; - - transmit(); - txPacket = 0; - - if (!txEnable) { - DPRINTF(EthernetSM, "halting TX state machine\n"); - txState = txIdle; - goto exit; - } else - txState = txAdvance; - - if (doTxDmaWrite()) - goto exit; - } - } else { - DPRINTF(EthernetSM, "this descriptor isn't done yet\n"); - if (!txFifo.full()) { - txState = txFragRead; - - /* - * The number of bytes transferred is either whatever - * is left in the descriptor (txDescCnt), or if there - * is not enough room in the fifo, just whatever room - * is left in the fifo - */ - txXferLen = min<uint32_t>(txDescCnt, txFifo.avail()); - - txDmaAddr = txFragPtr & 0x3fffffff; - txDmaData = txPacketBufPtr; - txDmaLen = txXferLen; - txDmaFree = dmaDataFree; - - if (doTxDmaRead()) - goto exit; - } else { - txState = txFifoBlock; - transmit(); - - goto exit; - } - - } - break; - - case txFragRead: - if (txDmaState != dmaIdle) - goto exit; - - txPacketBufPtr += txXferLen; - txFragPtr += txXferLen; - txDescCnt -= txXferLen; - txFifo.reserve(txXferLen); - - txState = txFifoBlock; - break; - - case txDescWrite: - if (txDmaState != dmaIdle) - goto exit; - - if (cmdsts & CMDSTS_INTR) - devIntrPost(ISR_TXDESC); - - if (!txEnable) { - DPRINTF(EthernetSM, "halting TX state machine\n"); - txState = txIdle; - goto exit; - } else - txState = txAdvance; - break; - - case txAdvance: - if (link == 0) { - devIntrPost(ISR_TXIDLE); - txState = txIdle; - goto exit; - } else { - if (txDmaState != dmaIdle) - goto exit; - txState = txDescRead; - regs.txdp = link; - CTDD = false; - - txDmaAddr = link & 0x3fffffff; - txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32; - txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32); - txDmaFree = dmaDescFree; - - if (doTxDmaRead()) - goto exit; - } - break; - - default: - panic("invalid state"); - } - - DPRINTF(EthernetSM, "entering next txState=%s\n", - NsTxStateStrings[txState]); - goto next; - - exit: - /** - * @todo do we want to schedule a future kick? - */ - DPRINTF(EthernetSM, "tx state machine exited txState=%s\n", - NsTxStateStrings[txState]); - - if (clock && !txKickEvent.scheduled()) - txKickEvent.schedule(txKickTick); -} - -/** - * Advance the EEPROM state machine - * Called on rising edge of EEPROM clock bit in MEAR - */ -void -NSGigE::eepromKick() -{ - switch (eepromState) { - - case eepromStart: - - // Wait for start bit - if (regs.mear & MEAR_EEDI) { - // Set up to get 2 opcode bits - eepromState = eepromGetOpcode; - eepromBitsToRx = 2; - eepromOpcode = 0; - } - break; - - case eepromGetOpcode: - eepromOpcode <<= 1; - eepromOpcode += (regs.mear & MEAR_EEDI) ? 1 : 0; - --eepromBitsToRx; - - // Done getting opcode - if (eepromBitsToRx == 0) { - if (eepromOpcode != EEPROM_READ) - panic("only EEPROM reads are implemented!"); - - // Set up to get address - eepromState = eepromGetAddress; - eepromBitsToRx = 6; - eepromAddress = 0; - } - break; - - case eepromGetAddress: - eepromAddress <<= 1; - eepromAddress += (regs.mear & MEAR_EEDI) ? 1 : 0; - --eepromBitsToRx; - - // Done getting address - if (eepromBitsToRx == 0) { - - if (eepromAddress >= EEPROM_SIZE) - panic("EEPROM read access out of range!"); - - switch (eepromAddress) { - - case EEPROM_PMATCH2_ADDR: - eepromData = rom.perfectMatch[5]; - eepromData <<= 8; - eepromData += rom.perfectMatch[4]; - break; - - case EEPROM_PMATCH1_ADDR: - eepromData = rom.perfectMatch[3]; - eepromData <<= 8; - eepromData += rom.perfectMatch[2]; - break; - - case EEPROM_PMATCH0_ADDR: - eepromData = rom.perfectMatch[1]; - eepromData <<= 8; - eepromData += rom.perfectMatch[0]; - break; - - default: - panic("FreeBSD driver only uses EEPROM to read PMATCH!"); - } - // Set up to read data - eepromState = eepromRead; - eepromBitsToRx = 16; - - // Clear data in bit - regs.mear &= ~MEAR_EEDI; - } - break; - - case eepromRead: - // Clear Data Out bit - regs.mear &= ~MEAR_EEDO; - // Set bit to value of current EEPROM bit - regs.mear |= (eepromData & 0x8000) ? MEAR_EEDO : 0x0; - - eepromData <<= 1; - --eepromBitsToRx; - - // All done - if (eepromBitsToRx == 0) { - eepromState = eepromStart; - } - break; - - default: - panic("invalid EEPROM state"); - } - -} - -void -NSGigE::transferDone() -{ - if (txFifo.empty()) { - DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n"); - return; - } - - DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n"); - - if (txEvent.scheduled()) - txEvent.reschedule(curTick + cycles(1)); - else - txEvent.schedule(curTick + cycles(1)); -} - -bool -NSGigE::rxFilter(const PacketPtr &packet) -{ - EthPtr eth = packet; - bool drop = true; - string type; - - const EthAddr &dst = eth->dst(); - if (dst.unicast()) { - // If we're accepting all unicast addresses - if (acceptUnicast) - drop = false; - - // If we make a perfect match - if (acceptPerfect && dst == rom.perfectMatch) - drop = false; - - if (acceptArp && eth->type() == ETH_TYPE_ARP) - drop = false; - - } else if (dst.broadcast()) { - // if we're accepting broadcasts - if (acceptBroadcast) - drop = false; - - } else if (dst.multicast()) { - // if we're accepting all multicasts - if (acceptMulticast) - drop = false; - - // Multicast hashing faked - all packets accepted - if (multicastHashEnable) - drop = false; - } - - if (drop) { - DPRINTF(Ethernet, "rxFilter drop\n"); - DDUMP(EthernetData, packet->data, packet->length); - } - - return drop; -} - -bool -NSGigE::recvPacket(PacketPtr packet) -{ - rxBytes += packet->length; - rxPackets++; - - DPRINTF(Ethernet, "Receiving packet from wire, rxFifoAvail=%d\n", - rxFifo.avail()); - - if (!rxEnable) { - DPRINTF(Ethernet, "receive disabled...packet dropped\n"); - return true; - } - - if (!rxFilterEnable) { - DPRINTF(Ethernet, - "receive packet filtering disabled . . . packet dropped\n"); - return true; - } - - if (rxFilter(packet)) { - DPRINTF(Ethernet, "packet filtered...dropped\n"); - return true; - } - - if (rxFifo.avail() < packet->length) { -#if TRACING_ON - IpPtr ip(packet); - TcpPtr tcp(ip); - if (ip) { - DPRINTF(Ethernet, - "packet won't fit in receive buffer...pkt ID %d dropped\n", - ip->id()); - if (tcp) { - DPRINTF(Ethernet, "Seq=%d\n", tcp->seq()); - } - } -#endif - droppedPackets++; - devIntrPost(ISR_RXORN); - return false; - } - - rxFifo.push(packet); - - rxKick(); - return true; -} - -//===================================================================== -// -// -void -NSGigE::serialize(ostream &os) -{ - // Serialize the PciDev base class - PciDev::serialize(os); - - /* - * Finalize any DMA events now. - */ - if (rxDmaReadEvent.scheduled()) - rxDmaReadCopy(); - if (rxDmaWriteEvent.scheduled()) - rxDmaWriteCopy(); - if (txDmaReadEvent.scheduled()) - txDmaReadCopy(); - if (txDmaWriteEvent.scheduled()) - txDmaWriteCopy(); - - /* - * Serialize the device registers - */ - SERIALIZE_SCALAR(regs.command); - SERIALIZE_SCALAR(regs.config); - SERIALIZE_SCALAR(regs.mear); - SERIALIZE_SCALAR(regs.ptscr); - SERIALIZE_SCALAR(regs.isr); - SERIALIZE_SCALAR(regs.imr); - SERIALIZE_SCALAR(regs.ier); - SERIALIZE_SCALAR(regs.ihr); - SERIALIZE_SCALAR(regs.txdp); - SERIALIZE_SCALAR(regs.txdp_hi); - SERIALIZE_SCALAR(regs.txcfg); - SERIALIZE_SCALAR(regs.gpior); - SERIALIZE_SCALAR(regs.rxdp); - SERIALIZE_SCALAR(regs.rxdp_hi); - SERIALIZE_SCALAR(regs.rxcfg); - SERIALIZE_SCALAR(regs.pqcr); - SERIALIZE_SCALAR(regs.wcsr); - SERIALIZE_SCALAR(regs.pcr); - SERIALIZE_SCALAR(regs.rfcr); - SERIALIZE_SCALAR(regs.rfdr); - SERIALIZE_SCALAR(regs.brar); - SERIALIZE_SCALAR(regs.brdr); - SERIALIZE_SCALAR(regs.srr); - SERIALIZE_SCALAR(regs.mibc); - SERIALIZE_SCALAR(regs.vrcr); - SERIALIZE_SCALAR(regs.vtcr); - SERIALIZE_SCALAR(regs.vdr); - SERIALIZE_SCALAR(regs.ccsr); - SERIALIZE_SCALAR(regs.tbicr); - SERIALIZE_SCALAR(regs.tbisr); - SERIALIZE_SCALAR(regs.tanar); - SERIALIZE_SCALAR(regs.tanlpar); - SERIALIZE_SCALAR(regs.taner); - SERIALIZE_SCALAR(regs.tesr); - - SERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN); - SERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE); - - SERIALIZE_SCALAR(ioEnable); - - /* - * Serialize the data Fifos - */ - rxFifo.serialize("rxFifo", os); - txFifo.serialize("txFifo", os); - - /* - * Serialize the various helper variables - */ - bool txPacketExists = txPacket; - SERIALIZE_SCALAR(txPacketExists); - if (txPacketExists) { - txPacket->length = txPacketBufPtr - txPacket->data; - txPacket->serialize("txPacket", os); - uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data); - SERIALIZE_SCALAR(txPktBufPtr); - } - - bool rxPacketExists = rxPacket; - SERIALIZE_SCALAR(rxPacketExists); - if (rxPacketExists) { - rxPacket->serialize("rxPacket", os); - uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data); - SERIALIZE_SCALAR(rxPktBufPtr); - } - - SERIALIZE_SCALAR(txXferLen); - SERIALIZE_SCALAR(rxXferLen); - - /* - * Serialize Cached Descriptors - */ - SERIALIZE_SCALAR(rxDesc64.link); - SERIALIZE_SCALAR(rxDesc64.bufptr); - SERIALIZE_SCALAR(rxDesc64.cmdsts); - SERIALIZE_SCALAR(rxDesc64.extsts); - SERIALIZE_SCALAR(txDesc64.link); - SERIALIZE_SCALAR(txDesc64.bufptr); - SERIALIZE_SCALAR(txDesc64.cmdsts); - SERIALIZE_SCALAR(txDesc64.extsts); - SERIALIZE_SCALAR(rxDesc32.link); - SERIALIZE_SCALAR(rxDesc32.bufptr); - SERIALIZE_SCALAR(rxDesc32.cmdsts); - SERIALIZE_SCALAR(rxDesc32.extsts); - SERIALIZE_SCALAR(txDesc32.link); - SERIALIZE_SCALAR(txDesc32.bufptr); - SERIALIZE_SCALAR(txDesc32.cmdsts); - SERIALIZE_SCALAR(txDesc32.extsts); - SERIALIZE_SCALAR(extstsEnable); - - /* - * Serialize tx state machine - */ - int txState = this->txState; - SERIALIZE_SCALAR(txState); - SERIALIZE_SCALAR(txEnable); - SERIALIZE_SCALAR(CTDD); - SERIALIZE_SCALAR(txFragPtr); - SERIALIZE_SCALAR(txDescCnt); - int txDmaState = this->txDmaState; - SERIALIZE_SCALAR(txDmaState); - SERIALIZE_SCALAR(txKickTick); - - /* - * Serialize rx state machine - */ - int rxState = this->rxState; - SERIALIZE_SCALAR(rxState); - SERIALIZE_SCALAR(rxEnable); - SERIALIZE_SCALAR(CRDD); - SERIALIZE_SCALAR(rxPktBytes); - SERIALIZE_SCALAR(rxFragPtr); - SERIALIZE_SCALAR(rxDescCnt); - int rxDmaState = this->rxDmaState; - SERIALIZE_SCALAR(rxDmaState); - SERIALIZE_SCALAR(rxKickTick); - - /* - * Serialize EEPROM state machine - */ - int eepromState = this->eepromState; - SERIALIZE_SCALAR(eepromState); - SERIALIZE_SCALAR(eepromClk); - SERIALIZE_SCALAR(eepromBitsToRx); - SERIALIZE_SCALAR(eepromOpcode); - SERIALIZE_SCALAR(eepromAddress); - SERIALIZE_SCALAR(eepromData); - - /* - * If there's a pending transmit, store the time so we can - * reschedule it later - */ - Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0; - SERIALIZE_SCALAR(transmitTick); - - /* - * receive address filter settings - */ - SERIALIZE_SCALAR(rxFilterEnable); - SERIALIZE_SCALAR(acceptBroadcast); - SERIALIZE_SCALAR(acceptMulticast); - SERIALIZE_SCALAR(acceptUnicast); - SERIALIZE_SCALAR(acceptPerfect); - SERIALIZE_SCALAR(acceptArp); - SERIALIZE_SCALAR(multicastHashEnable); - - /* - * Keep track of pending interrupt status. - */ - SERIALIZE_SCALAR(intrTick); - SERIALIZE_SCALAR(cpuPendingIntr); - Tick intrEventTick = 0; - if (intrEvent) - intrEventTick = intrEvent->when(); - SERIALIZE_SCALAR(intrEventTick); - -} - -void -NSGigE::unserialize(Checkpoint *cp, const std::string §ion) -{ - // Unserialize the PciDev base class - PciDev::unserialize(cp, section); - - UNSERIALIZE_SCALAR(regs.command); - UNSERIALIZE_SCALAR(regs.config); - UNSERIALIZE_SCALAR(regs.mear); - UNSERIALIZE_SCALAR(regs.ptscr); - UNSERIALIZE_SCALAR(regs.isr); - UNSERIALIZE_SCALAR(regs.imr); - UNSERIALIZE_SCALAR(regs.ier); - UNSERIALIZE_SCALAR(regs.ihr); - UNSERIALIZE_SCALAR(regs.txdp); - UNSERIALIZE_SCALAR(regs.txdp_hi); - UNSERIALIZE_SCALAR(regs.txcfg); - UNSERIALIZE_SCALAR(regs.gpior); - UNSERIALIZE_SCALAR(regs.rxdp); - UNSERIALIZE_SCALAR(regs.rxdp_hi); - UNSERIALIZE_SCALAR(regs.rxcfg); - UNSERIALIZE_SCALAR(regs.pqcr); - UNSERIALIZE_SCALAR(regs.wcsr); - UNSERIALIZE_SCALAR(regs.pcr); - UNSERIALIZE_SCALAR(regs.rfcr); - UNSERIALIZE_SCALAR(regs.rfdr); - UNSERIALIZE_SCALAR(regs.brar); - UNSERIALIZE_SCALAR(regs.brdr); - UNSERIALIZE_SCALAR(regs.srr); - UNSERIALIZE_SCALAR(regs.mibc); - UNSERIALIZE_SCALAR(regs.vrcr); - UNSERIALIZE_SCALAR(regs.vtcr); - UNSERIALIZE_SCALAR(regs.vdr); - UNSERIALIZE_SCALAR(regs.ccsr); - UNSERIALIZE_SCALAR(regs.tbicr); - UNSERIALIZE_SCALAR(regs.tbisr); - UNSERIALIZE_SCALAR(regs.tanar); - UNSERIALIZE_SCALAR(regs.tanlpar); - UNSERIALIZE_SCALAR(regs.taner); - UNSERIALIZE_SCALAR(regs.tesr); - - UNSERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN); - UNSERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE); - - UNSERIALIZE_SCALAR(ioEnable); - - /* - * unserialize the data fifos - */ - rxFifo.unserialize("rxFifo", cp, section); - txFifo.unserialize("txFifo", cp, section); - - /* - * unserialize the various helper variables - */ - bool txPacketExists; - UNSERIALIZE_SCALAR(txPacketExists); - if (txPacketExists) { - txPacket = new PacketData(16384); - txPacket->unserialize("txPacket", cp, section); - uint32_t txPktBufPtr; - UNSERIALIZE_SCALAR(txPktBufPtr); - txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr; - } else - txPacket = 0; - - bool rxPacketExists; - UNSERIALIZE_SCALAR(rxPacketExists); - rxPacket = 0; - if (rxPacketExists) { - rxPacket = new PacketData(16384); - rxPacket->unserialize("rxPacket", cp, section); - uint32_t rxPktBufPtr; - UNSERIALIZE_SCALAR(rxPktBufPtr); - rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr; - } else - rxPacket = 0; - - UNSERIALIZE_SCALAR(txXferLen); - UNSERIALIZE_SCALAR(rxXferLen); - - /* - * Unserialize Cached Descriptors - */ - UNSERIALIZE_SCALAR(rxDesc64.link); - UNSERIALIZE_SCALAR(rxDesc64.bufptr); - UNSERIALIZE_SCALAR(rxDesc64.cmdsts); - UNSERIALIZE_SCALAR(rxDesc64.extsts); - UNSERIALIZE_SCALAR(txDesc64.link); - UNSERIALIZE_SCALAR(txDesc64.bufptr); - UNSERIALIZE_SCALAR(txDesc64.cmdsts); - UNSERIALIZE_SCALAR(txDesc64.extsts); - UNSERIALIZE_SCALAR(rxDesc32.link); - UNSERIALIZE_SCALAR(rxDesc32.bufptr); - UNSERIALIZE_SCALAR(rxDesc32.cmdsts); - UNSERIALIZE_SCALAR(rxDesc32.extsts); - UNSERIALIZE_SCALAR(txDesc32.link); - UNSERIALIZE_SCALAR(txDesc32.bufptr); - UNSERIALIZE_SCALAR(txDesc32.cmdsts); - UNSERIALIZE_SCALAR(txDesc32.extsts); - UNSERIALIZE_SCALAR(extstsEnable); - - /* - * unserialize tx state machine - */ - int txState; - UNSERIALIZE_SCALAR(txState); - this->txState = (TxState) txState; - UNSERIALIZE_SCALAR(txEnable); - UNSERIALIZE_SCALAR(CTDD); - UNSERIALIZE_SCALAR(txFragPtr); - UNSERIALIZE_SCALAR(txDescCnt); - int txDmaState; - UNSERIALIZE_SCALAR(txDmaState); - this->txDmaState = (DmaState) txDmaState; - UNSERIALIZE_SCALAR(txKickTick); - if (txKickTick) - txKickEvent.schedule(txKickTick); - - /* - * unserialize rx state machine - */ - int rxState; - UNSERIALIZE_SCALAR(rxState); - this->rxState = (RxState) rxState; - UNSERIALIZE_SCALAR(rxEnable); - UNSERIALIZE_SCALAR(CRDD); - UNSERIALIZE_SCALAR(rxPktBytes); - UNSERIALIZE_SCALAR(rxFragPtr); - UNSERIALIZE_SCALAR(rxDescCnt); - int rxDmaState; - UNSERIALIZE_SCALAR(rxDmaState); - this->rxDmaState = (DmaState) rxDmaState; - UNSERIALIZE_SCALAR(rxKickTick); - if (rxKickTick) - rxKickEvent.schedule(rxKickTick); - - /* - * Unserialize EEPROM state machine - */ - int eepromState; - UNSERIALIZE_SCALAR(eepromState); - this->eepromState = (EEPROMState) eepromState; - UNSERIALIZE_SCALAR(eepromClk); - UNSERIALIZE_SCALAR(eepromBitsToRx); - UNSERIALIZE_SCALAR(eepromOpcode); - UNSERIALIZE_SCALAR(eepromAddress); - UNSERIALIZE_SCALAR(eepromData); - - /* - * If there's a pending transmit, reschedule it now - */ - Tick transmitTick; - UNSERIALIZE_SCALAR(transmitTick); - if (transmitTick) - txEvent.schedule(curTick + transmitTick); - - /* - * unserialize receive address filter settings - */ - UNSERIALIZE_SCALAR(rxFilterEnable); - UNSERIALIZE_SCALAR(acceptBroadcast); - UNSERIALIZE_SCALAR(acceptMulticast); - UNSERIALIZE_SCALAR(acceptUnicast); - UNSERIALIZE_SCALAR(acceptPerfect); - UNSERIALIZE_SCALAR(acceptArp); - UNSERIALIZE_SCALAR(multicastHashEnable); - - /* - * Keep track of pending interrupt status. - */ - UNSERIALIZE_SCALAR(intrTick); - UNSERIALIZE_SCALAR(cpuPendingIntr); - Tick intrEventTick; - UNSERIALIZE_SCALAR(intrEventTick); - if (intrEventTick) { - intrEvent = new IntrEvent(this, true); - intrEvent->schedule(intrEventTick); - } - - /* - * re-add addrRanges to bus bridges - */ - if (pioInterface) { - pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0])); - pioInterface->addAddrRange(RangeSize(BARAddrs[1], BARSize[1])); - } -} - -Tick -NSGigE::cacheAccess(MemReqPtr &req) -{ - DPRINTF(EthernetPIO, "timing access to paddr=%#x (daddr=%#x)\n", - req->paddr, req->paddr & 0xfff); - - return curTick + pioLatency; -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt) - - SimObjectParam<EtherInt *> peer; - SimObjectParam<NSGigE *> device; - -END_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt) - -BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigEInt) - - INIT_PARAM_DFLT(peer, "peer interface", NULL), - INIT_PARAM(device, "Ethernet device of this interface") - -END_INIT_SIM_OBJECT_PARAMS(NSGigEInt) - -CREATE_SIM_OBJECT(NSGigEInt) -{ - NSGigEInt *dev_int = new NSGigEInt(getInstanceName(), device); - - EtherInt *p = (EtherInt *)peer; - if (p) { - dev_int->setPeer(p); - p->setPeer(dev_int); - } - - return dev_int; -} - -REGISTER_SIM_OBJECT("NSGigEInt", NSGigEInt) - - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE) - - Param<Tick> clock; - - Param<Addr> addr; - SimObjectParam<MemoryController *> mmu; - SimObjectParam<PhysicalMemory *> physmem; - SimObjectParam<PciConfigAll *> configspace; - SimObjectParam<PciConfigData *> configdata; - SimObjectParam<Platform *> platform; - Param<uint32_t> pci_bus; - Param<uint32_t> pci_dev; - Param<uint32_t> pci_func; - - SimObjectParam<HierParams *> hier; - SimObjectParam<Bus*> pio_bus; - SimObjectParam<Bus*> dma_bus; - SimObjectParam<Bus*> payload_bus; - Param<bool> dma_desc_free; - Param<bool> dma_data_free; - Param<Tick> dma_read_delay; - Param<Tick> dma_write_delay; - Param<Tick> dma_read_factor; - Param<Tick> dma_write_factor; - Param<bool> dma_no_allocate; - Param<Tick> pio_latency; - Param<Tick> intr_delay; - - Param<Tick> rx_delay; - Param<Tick> tx_delay; - Param<uint32_t> rx_fifo_size; - Param<uint32_t> tx_fifo_size; - - Param<bool> rx_filter; - Param<string> hardware_address; - Param<bool> rx_thread; - Param<bool> tx_thread; - Param<bool> rss; - -END_DECLARE_SIM_OBJECT_PARAMS(NSGigE) - -BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE) - - INIT_PARAM(clock, "State machine processor frequency"), - - INIT_PARAM(addr, "Device Address"), - INIT_PARAM(mmu, "Memory Controller"), - INIT_PARAM(physmem, "Physical Memory"), - INIT_PARAM(configspace, "PCI Configspace"), - INIT_PARAM(configdata, "PCI Config data"), - INIT_PARAM(platform, "Platform"), - INIT_PARAM(pci_bus, "PCI bus"), - INIT_PARAM(pci_dev, "PCI device number"), - INIT_PARAM(pci_func, "PCI function code"), - - INIT_PARAM(hier, "Hierarchy global variables"), - INIT_PARAM(pio_bus, ""), - INIT_PARAM(dma_bus, ""), - INIT_PARAM(payload_bus, "The IO Bus to attach to for payload"), - INIT_PARAM(dma_desc_free, "DMA of Descriptors is free"), - INIT_PARAM(dma_data_free, "DMA of Data is free"), - INIT_PARAM(dma_read_delay, "fixed delay for dma reads"), - INIT_PARAM(dma_write_delay, "fixed delay for dma writes"), - INIT_PARAM(dma_read_factor, "multiplier for dma reads"), - INIT_PARAM(dma_write_factor, "multiplier for dma writes"), - INIT_PARAM(dma_no_allocate, "Should DMA reads allocate cache lines"), - INIT_PARAM(pio_latency, "Programmed IO latency in bus cycles"), - INIT_PARAM(intr_delay, "Interrupt Delay in microseconds"), - - INIT_PARAM(rx_delay, "Receive Delay"), - INIT_PARAM(tx_delay, "Transmit Delay"), - INIT_PARAM(rx_fifo_size, "max size in bytes of rxFifo"), - INIT_PARAM(tx_fifo_size, "max size in bytes of txFifo"), - - INIT_PARAM(rx_filter, "Enable Receive Filter"), - INIT_PARAM(hardware_address, "Ethernet Hardware Address"), - INIT_PARAM(rx_thread, ""), - INIT_PARAM(tx_thread, ""), - INIT_PARAM(rss, "") - -END_INIT_SIM_OBJECT_PARAMS(NSGigE) - - -CREATE_SIM_OBJECT(NSGigE) -{ - NSGigE::Params *params = new NSGigE::Params; - - params->name = getInstanceName(); - - params->clock = clock; - - params->mmu = mmu; - params->pmem = physmem; - params->configSpace = configspace; - params->configData = configdata; - params->plat = platform; - params->busNum = pci_bus; - params->deviceNum = pci_dev; - params->functionNum = pci_func; - - params->hier = hier; - params->pio_bus = pio_bus; - params->header_bus = dma_bus; - params->payload_bus = payload_bus; - params->dma_desc_free = dma_desc_free; - params->dma_data_free = dma_data_free; - params->dma_read_delay = dma_read_delay; - params->dma_write_delay = dma_write_delay; - params->dma_read_factor = dma_read_factor; - params->dma_write_factor = dma_write_factor; - params->dma_no_allocate = dma_no_allocate; - params->pio_latency = pio_latency; - params->intr_delay = intr_delay; - - params->rx_delay = rx_delay; - params->tx_delay = tx_delay; - params->rx_fifo_size = rx_fifo_size; - params->tx_fifo_size = tx_fifo_size; - - params->rx_filter = rx_filter; - params->eaddr = hardware_address; - params->rx_thread = rx_thread; - params->tx_thread = tx_thread; - params->rss = rss; - - return new NSGigE(params); -} - -REGISTER_SIM_OBJECT("NSGigE", NSGigE) diff --git a/dev/ns_gige.hh b/dev/ns_gige.hh deleted file mode 100644 index 59c55056e..000000000 --- a/dev/ns_gige.hh +++ /dev/null @@ -1,487 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** @file - * Device module for modelling the National Semiconductor - * DP83820 ethernet controller - */ - -#ifndef __DEV_NS_GIGE_HH__ -#define __DEV_NS_GIGE_HH__ - -#include "base/inet.hh" -#include "base/statistics.hh" -#include "dev/etherint.hh" -#include "dev/etherpkt.hh" -#include "dev/io_device.hh" -#include "dev/ns_gige_reg.h" -#include "dev/pcidev.hh" -#include "dev/pktfifo.hh" -#include "mem/bus/bus.hh" -#include "sim/eventq.hh" - -// Hash filtering constants -const uint16_t FHASH_ADDR = 0x100; -const uint16_t FHASH_SIZE = 0x100; - -// EEPROM constants -const uint8_t EEPROM_READ = 0x2; -const uint8_t EEPROM_SIZE = 64; // Size in words of NSC93C46 EEPROM -const uint8_t EEPROM_PMATCH2_ADDR = 0xA; // EEPROM Address of PMATCH word 2 -const uint8_t EEPROM_PMATCH1_ADDR = 0xB; // EEPROM Address of PMATCH word 1 -const uint8_t EEPROM_PMATCH0_ADDR = 0xC; // EEPROM Address of PMATCH word 0 - -/** - * Ethernet device registers - */ -struct dp_regs { - uint32_t command; - uint32_t config; - uint32_t mear; - uint32_t ptscr; - uint32_t isr; - uint32_t imr; - uint32_t ier; - uint32_t ihr; - uint32_t txdp; - uint32_t txdp_hi; - uint32_t txcfg; - uint32_t gpior; - uint32_t rxdp; - uint32_t rxdp_hi; - uint32_t rxcfg; - uint32_t pqcr; - uint32_t wcsr; - uint32_t pcr; - uint32_t rfcr; - uint32_t rfdr; - uint32_t brar; - uint32_t brdr; - uint32_t srr; - uint32_t mibc; - uint32_t vrcr; - uint32_t vtcr; - uint32_t vdr; - uint32_t ccsr; - uint32_t tbicr; - uint32_t tbisr; - uint32_t tanar; - uint32_t tanlpar; - uint32_t taner; - uint32_t tesr; -}; - -struct dp_rom { - /** - * for perfect match memory. - * the linux driver doesn't use any other ROM - */ - uint8_t perfectMatch[ETH_ADDR_LEN]; - - /** - * for hash table memory. - * used by the freebsd driver - */ - uint8_t filterHash[FHASH_SIZE]; -}; - -class NSGigEInt; -class PhysicalMemory; -class BaseInterface; -class HierParams; -class Bus; -class PciConfigAll; - -/** - * NS DP83820 Ethernet device model - */ -class NSGigE : public PciDev -{ - public: - /** Transmit State Machine states */ - enum TxState - { - txIdle, - txDescRefr, - txDescRead, - txFifoBlock, - txFragRead, - txDescWrite, - txAdvance - }; - - /** Receive State Machine States */ - enum RxState - { - rxIdle, - rxDescRefr, - rxDescRead, - rxFifoBlock, - rxFragWrite, - rxDescWrite, - rxAdvance - }; - - enum DmaState - { - dmaIdle, - dmaReading, - dmaWriting, - dmaReadWaiting, - dmaWriteWaiting - }; - - /** EEPROM State Machine States */ - enum EEPROMState - { - eepromStart, - eepromGetOpcode, - eepromGetAddress, - eepromRead - }; - - private: - Addr addr; - static const Addr size = sizeof(dp_regs); - - protected: - /** device register file */ - dp_regs regs; - dp_rom rom; - - /** pci settings */ - bool ioEnable; -#if 0 - bool memEnable; - bool bmEnable; -#endif - - /*** BASIC STRUCTURES FOR TX/RX ***/ - /* Data FIFOs */ - PacketFifo txFifo; - PacketFifo rxFifo; - - /** various helper vars */ - PacketPtr txPacket; - PacketPtr rxPacket; - uint8_t *txPacketBufPtr; - uint8_t *rxPacketBufPtr; - uint32_t txXferLen; - uint32_t rxXferLen; - bool rxDmaFree; - bool txDmaFree; - - /** DescCaches */ - ns_desc32 txDesc32; - ns_desc32 rxDesc32; - ns_desc64 txDesc64; - ns_desc64 rxDesc64; - - /* state machine cycle time */ - Tick clock; - inline Tick cycles(int numCycles) const { return numCycles * clock; } - - /* tx State Machine */ - TxState txState; - bool txEnable; - - /** Current Transmit Descriptor Done */ - bool CTDD; - /** halt the tx state machine after next packet */ - bool txHalt; - /** ptr to the next byte in the current fragment */ - Addr txFragPtr; - /** count of bytes remaining in the current descriptor */ - uint32_t txDescCnt; - DmaState txDmaState; - - /** rx State Machine */ - RxState rxState; - bool rxEnable; - - /** Current Receive Descriptor Done */ - bool CRDD; - /** num of bytes in the current packet being drained from rxDataFifo */ - uint32_t rxPktBytes; - /** halt the rx state machine after current packet */ - bool rxHalt; - /** ptr to the next byte in current fragment */ - Addr rxFragPtr; - /** count of bytes remaining in the current descriptor */ - uint32_t rxDescCnt; - DmaState rxDmaState; - - bool extstsEnable; - - /** EEPROM State Machine */ - EEPROMState eepromState; - bool eepromClk; - uint8_t eepromBitsToRx; - uint8_t eepromOpcode; - uint8_t eepromAddress; - uint16_t eepromData; - - protected: - Tick dmaReadDelay; - Tick dmaWriteDelay; - - Tick dmaReadFactor; - Tick dmaWriteFactor; - - void *rxDmaData; - Addr rxDmaAddr; - int rxDmaLen; - bool doRxDmaRead(); - bool doRxDmaWrite(); - void rxDmaReadCopy(); - void rxDmaWriteCopy(); - - void *txDmaData; - Addr txDmaAddr; - int txDmaLen; - bool doTxDmaRead(); - bool doTxDmaWrite(); - void txDmaReadCopy(); - void txDmaWriteCopy(); - - void rxDmaReadDone(); - friend class EventWrapper<NSGigE, &NSGigE::rxDmaReadDone>; - EventWrapper<NSGigE, &NSGigE::rxDmaReadDone> rxDmaReadEvent; - - void rxDmaWriteDone(); - friend class EventWrapper<NSGigE, &NSGigE::rxDmaWriteDone>; - EventWrapper<NSGigE, &NSGigE::rxDmaWriteDone> rxDmaWriteEvent; - - void txDmaReadDone(); - friend class EventWrapper<NSGigE, &NSGigE::txDmaReadDone>; - EventWrapper<NSGigE, &NSGigE::txDmaReadDone> txDmaReadEvent; - - void txDmaWriteDone(); - friend class EventWrapper<NSGigE, &NSGigE::txDmaWriteDone>; - EventWrapper<NSGigE, &NSGigE::txDmaWriteDone> txDmaWriteEvent; - - bool dmaDescFree; - bool dmaDataFree; - - protected: - Tick txDelay; - Tick rxDelay; - - void txReset(); - void rxReset(); - void regsReset(); - - void rxKick(); - Tick rxKickTick; - typedef EventWrapper<NSGigE, &NSGigE::rxKick> RxKickEvent; - friend void RxKickEvent::process(); - RxKickEvent rxKickEvent; - - void txKick(); - Tick txKickTick; - typedef EventWrapper<NSGigE, &NSGigE::txKick> TxKickEvent; - friend void TxKickEvent::process(); - TxKickEvent txKickEvent; - - void eepromKick(); - - /** - * Retransmit event - */ - void transmit(); - void txEventTransmit() - { - transmit(); - if (txState == txFifoBlock) - txKick(); - } - typedef EventWrapper<NSGigE, &NSGigE::txEventTransmit> TxEvent; - friend void TxEvent::process(); - TxEvent txEvent; - - void txDump() const; - void rxDump() const; - - /** - * receive address filter - */ - bool rxFilterEnable; - bool rxFilter(const PacketPtr &packet); - bool acceptBroadcast; - bool acceptMulticast; - bool acceptUnicast; - bool acceptPerfect; - bool acceptArp; - bool multicastHashEnable; - - PhysicalMemory *physmem; - - /** - * Interrupt management - */ - void devIntrPost(uint32_t interrupts); - void devIntrClear(uint32_t interrupts); - void devIntrChangeMask(); - - Tick intrDelay; - Tick intrTick; - bool cpuPendingIntr; - void cpuIntrPost(Tick when); - void cpuInterrupt(); - void cpuIntrClear(); - - typedef EventWrapper<NSGigE, &NSGigE::cpuInterrupt> IntrEvent; - friend void IntrEvent::process(); - IntrEvent *intrEvent; - NSGigEInt *interface; - - public: - struct Params : public PciDev::Params - { - PhysicalMemory *pmem; - HierParams *hier; - Bus *pio_bus; - Bus *header_bus; - Bus *payload_bus; - Tick clock; - Tick intr_delay; - Tick tx_delay; - Tick rx_delay; - Tick pio_latency; - bool dma_desc_free; - bool dma_data_free; - Tick dma_read_delay; - Tick dma_write_delay; - Tick dma_read_factor; - Tick dma_write_factor; - bool rx_filter; - Net::EthAddr eaddr; - uint32_t tx_fifo_size; - uint32_t rx_fifo_size; - bool rx_thread; - bool tx_thread; - bool rss; - bool dma_no_allocate; - }; - - NSGigE(Params *params); - ~NSGigE(); - const Params *params() const { return (const Params *)_params; } - - virtual void writeConfig(int offset, int size, const uint8_t *data); - virtual void readConfig(int offset, int size, uint8_t *data); - - virtual Fault read(MemReqPtr &req, uint8_t *data); - virtual Fault write(MemReqPtr &req, const uint8_t *data); - - bool cpuIntrPending() const; - void cpuIntrAck() { cpuIntrClear(); } - - bool recvPacket(PacketPtr packet); - void transferDone(); - - void setInterface(NSGigEInt *i) { assert(!interface); interface = i; } - - virtual void serialize(std::ostream &os); - virtual void unserialize(Checkpoint *cp, const std::string §ion); - - public: - void regStats(); - - private: - Stats::Scalar<> txBytes; - Stats::Scalar<> rxBytes; - Stats::Scalar<> txPackets; - Stats::Scalar<> rxPackets; - Stats::Scalar<> txIpChecksums; - Stats::Scalar<> rxIpChecksums; - Stats::Scalar<> txTcpChecksums; - Stats::Scalar<> rxTcpChecksums; - Stats::Scalar<> txUdpChecksums; - Stats::Scalar<> rxUdpChecksums; - Stats::Scalar<> descDmaReads; - Stats::Scalar<> descDmaWrites; - Stats::Scalar<> descDmaRdBytes; - Stats::Scalar<> descDmaWrBytes; - Stats::Formula totBandwidth; - Stats::Formula totPackets; - Stats::Formula totBytes; - Stats::Formula totPacketRate; - Stats::Formula txBandwidth; - Stats::Formula rxBandwidth; - Stats::Formula txPacketRate; - Stats::Formula rxPacketRate; - Stats::Scalar<> postedSwi; - Stats::Formula coalescedSwi; - Stats::Scalar<> totalSwi; - Stats::Scalar<> postedRxIdle; - Stats::Formula coalescedRxIdle; - Stats::Scalar<> totalRxIdle; - Stats::Scalar<> postedRxOk; - Stats::Formula coalescedRxOk; - Stats::Scalar<> totalRxOk; - Stats::Scalar<> postedRxDesc; - Stats::Formula coalescedRxDesc; - Stats::Scalar<> totalRxDesc; - Stats::Scalar<> postedTxOk; - Stats::Formula coalescedTxOk; - Stats::Scalar<> totalTxOk; - Stats::Scalar<> postedTxIdle; - Stats::Formula coalescedTxIdle; - Stats::Scalar<> totalTxIdle; - Stats::Scalar<> postedTxDesc; - Stats::Formula coalescedTxDesc; - Stats::Scalar<> totalTxDesc; - Stats::Scalar<> postedRxOrn; - Stats::Formula coalescedRxOrn; - Stats::Scalar<> totalRxOrn; - Stats::Formula coalescedTotal; - Stats::Scalar<> postedInterrupts; - Stats::Scalar<> droppedPackets; - - public: - Tick cacheAccess(MemReqPtr &req); -}; - -/* - * Ethernet Interface for an Ethernet Device - */ -class NSGigEInt : public EtherInt -{ - private: - NSGigE *dev; - - public: - NSGigEInt(const std::string &name, NSGigE *d) - : EtherInt(name), dev(d) { dev->setInterface(this); } - - virtual bool recvPacket(PacketPtr pkt) { return dev->recvPacket(pkt); } - virtual void sendDone() { dev->transferDone(); } -}; - -#endif // __DEV_NS_GIGE_HH__ diff --git a/dev/pciconfigall.cc b/dev/pciconfigall.cc deleted file mode 100644 index d55084fa5..000000000 --- a/dev/pciconfigall.cc +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* @file - * PCI Configspace implementation - */ - -#include <deque> -#include <string> -#include <vector> -#include <bitset> - -#include "base/trace.hh" -#include "dev/pciconfigall.hh" -#include "dev/pcidev.hh" -#include "dev/pcireg.h" -#include "mem/bus/bus.hh" -#include "mem/bus/pio_interface.hh" -#include "mem/bus/pio_interface_impl.hh" -#include "mem/functional/memory_control.hh" -#include "sim/builder.hh" -#include "sim/system.hh" - -using namespace std; -using namespace TheISA; - -PciConfigAll::PciConfigAll(const string &name, - Addr a, MemoryController *mmu, - HierParams *hier, Bus *pio_bus, Tick pio_latency) - : PioDevice(name, NULL), addr(a) -{ - mmu->add_child(this, RangeSize(addr, size)); - - if (pio_bus) { - pioInterface = newPioInterface(name + ".pio", hier, pio_bus, this, - &PciConfigAll::cacheAccess); - pioInterface->addAddrRange(RangeSize(addr, size)); - pioLatency = pio_latency * pio_bus->clockRate; - } - - // Make all the pointers to devices null - for(int x=0; x < MAX_PCI_DEV; x++) - for(int y=0; y < MAX_PCI_FUNC; y++) - devices[x][y] = NULL; -} - -// If two interrupts share the same line largely bad things will happen. -// Since we don't track how many times an interrupt was set and correspondingly -// cleared two devices on the same interrupt line and assert and deassert each -// others interrupt "line". Interrupts will not work correctly. -void -PciConfigAll::startup() -{ - bitset<256> intLines; - PciDev *tempDev; - uint8_t intline; - - for (int x = 0; x < MAX_PCI_DEV; x++) { - for (int y = 0; y < MAX_PCI_FUNC; y++) { - if (devices[x][y] != NULL) { - tempDev = devices[x][y]; - intline = tempDev->interruptLine(); - if (intLines.test(intline)) - warn("Interrupt line %#X is used multiple times" - "(You probably want to fix this).\n", (uint32_t)intline); - else - intLines.set(intline); - } // devices != NULL - } // PCI_FUNC - } // PCI_DEV - -} - -Fault -PciConfigAll::read(MemReqPtr &req, uint8_t *data) -{ - - Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)); - - DPRINTF(PciConfigAll, "read va=%#x da=%#x size=%d\n", - req->vaddr, daddr, req->size); - - int device = (daddr >> 11) & 0x1F; - int func = (daddr >> 8) & 0x7; - int reg = daddr & 0xFF; - - if (devices[device][func] == NULL) { - switch (req->size) { - // case sizeof(uint64_t): - // *(uint64_t*)data = 0xFFFFFFFFFFFFFFFF; - // return NoFault; - case sizeof(uint32_t): - *(uint32_t*)data = 0xFFFFFFFF; - return NoFault; - case sizeof(uint16_t): - *(uint16_t*)data = 0xFFFF; - return NoFault; - case sizeof(uint8_t): - *(uint8_t*)data = 0xFF; - return NoFault; - default: - panic("invalid access size(?) for PCI configspace!\n"); - } - } else { - switch (req->size) { - case sizeof(uint32_t): - case sizeof(uint16_t): - case sizeof(uint8_t): - devices[device][func]->readConfig(reg, req->size, data); - return NoFault; - default: - panic("invalid access size(?) for PCI configspace!\n"); - } - } - - DPRINTFN("PCI Configspace ERROR: read daddr=%#x size=%d\n", - daddr, req->size); - - return NoFault; -} - -Fault -PciConfigAll::write(MemReqPtr &req, const uint8_t *data) -{ - Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)); - - int device = (daddr >> 11) & 0x1F; - int func = (daddr >> 8) & 0x7; - int reg = daddr & 0xFF; - - if (devices[device][func] == NULL) - panic("Attempting to write to config space on non-existant device\n"); - else if (req->size != sizeof(uint8_t) && - req->size != sizeof(uint16_t) && - req->size != sizeof(uint32_t)) - panic("invalid access size(?) for PCI configspace!\n"); - - DPRINTF(PciConfigAll, "write - va=%#x size=%d data=%#x\n", - req->vaddr, req->size, *(uint32_t*)data); - - devices[device][func]->writeConfig(reg, req->size, data); - - return NoFault; -} - -void -PciConfigAll::serialize(std::ostream &os) -{ - /* - * There is no state associated with this object that requires - * serialization. The only real state are the device pointers - * which are all setup by the constructor of the PciDev class - */ -} - -void -PciConfigAll::unserialize(Checkpoint *cp, const std::string §ion) -{ - /* - * There is no state associated with this object that requires - * serialization. The only real state are the device pointers - * which are all setup by the constructor of the PciDev class - */ -} - -Tick -PciConfigAll::cacheAccess(MemReqPtr &req) -{ - return curTick + pioLatency; -} - -#ifndef DOXYGEN_SHOULD_SKIP_THIS - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(PciConfigAll) - - SimObjectParam<MemoryController *> mmu; - Param<Addr> addr; - Param<Addr> mask; - SimObjectParam<Bus*> pio_bus; - Param<Tick> pio_latency; - SimObjectParam<HierParams *> hier; - -END_DECLARE_SIM_OBJECT_PARAMS(PciConfigAll) - -BEGIN_INIT_SIM_OBJECT_PARAMS(PciConfigAll) - - INIT_PARAM(mmu, "Memory Controller"), - INIT_PARAM(addr, "Device Address"), - INIT_PARAM(mask, "Address Mask"), - INIT_PARAM_DFLT(pio_bus, "The IO Bus to attach to", NULL), - INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1), - INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams) - -END_INIT_SIM_OBJECT_PARAMS(PciConfigAll) - -CREATE_SIM_OBJECT(PciConfigAll) -{ - return new PciConfigAll(getInstanceName(), addr, mmu, hier, pio_bus, - pio_latency); -} - -REGISTER_SIM_OBJECT("PciConfigAll", PciConfigAll) - -#endif // DOXYGEN_SHOULD_SKIP_THIS diff --git a/dev/pciconfigall.hh b/dev/pciconfigall.hh deleted file mode 100644 index c6a0241d8..000000000 --- a/dev/pciconfigall.hh +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * @file - * PCI Config space implementation. - */ - -#ifndef __PCICONFIGALL_HH__ -#define __PCICONFIGALL_HH__ - -#include "dev/pcireg.h" -#include "base/range.hh" -#include "dev/io_device.hh" - - -static const uint32_t MAX_PCI_DEV = 32; -static const uint32_t MAX_PCI_FUNC = 8; - -class PciDev; -class MemoryController; - -/** - * PCI Config Space - * All of PCI config space needs to return -1 on Tsunami, except - * the devices that exist. This device maps the entire bus config - * space and passes the requests on to TsunamiPCIDev devices as - * appropriate. - */ -class PciConfigAll : public PioDevice -{ - private: - Addr addr; - static const Addr size = 0xffffff; - - /** - * Pointers to all the devices that are registered with this - * particular config space. - */ - PciDev* devices[MAX_PCI_DEV][MAX_PCI_FUNC]; - - public: - /** - * Constructor for PCIConfigAll - * @param name name of the object - * @param a base address of the write - * @param mmu the memory controller - * @param hier object to store parameters universal the device hierarchy - * @param bus The bus that this device is attached to - */ - PciConfigAll(const std::string &name, Addr a, MemoryController *mmu, - HierParams *hier, Bus *pio_bus, Tick pio_latency); - - - /** - * Check if a device exists. - * @param pcidev PCI device to check - * @param pcifunc PCI function to check - * @return true if device exists, false otherwise - */ - bool deviceExists(uint32_t pcidev, uint32_t pcifunc) - { return devices[pcidev][pcifunc] != NULL ? true : false; } - - /** - * Registers a device with the config space object. - * @param pcidev PCI device to register - * @param pcifunc PCI function to register - * @param device device to register - */ - void registerDevice(uint8_t pcidev, uint8_t pcifunc, PciDev *device) - { devices[pcidev][pcifunc] = device; } - - /** - * Read something in PCI config space. If the device does not exist - * -1 is returned, if the device does exist its PciDev::ReadConfig (or the - * virtual function that overrides) it is called. - * @param req Contains the address of the field to read. - * @param data Return the field read. - * @return The fault condition of the access. - */ - virtual Fault read(MemReqPtr &req, uint8_t *data); - - /** - * Write to PCI config spcae. If the device does not exit the simulator - * panics. If it does it is passed on the PciDev::WriteConfig (or the virtual - * function that overrides it). - * @param req Contains the address to write to. - * @param data The data to write. - * @return The fault condition of the access. - */ - - virtual Fault write(MemReqPtr &req, const uint8_t *data); - - /** - * Start up function to check if more than one person is using an interrupt line - * and print a warning if such a case exists - */ - virtual void startup(); - - /** - * Serialize this object to the given output stream. - * @param os The stream to serialize to. - */ - virtual void serialize(std::ostream &os); - - /** - * Reconstruct the state of this object from a checkpoint. - * @param cp The checkpoint use. - * @param section The section name of this object - */ - virtual void unserialize(Checkpoint *cp, const std::string §ion); - - /** - * Return how long this access will take. - * @param req the memory request to calcuate - * @return Tick when the request is done - */ - Tick cacheAccess(MemReqPtr &req); - -}; - -#endif // __PCICONFIGALL_HH__ diff --git a/dev/pcidev.cc b/dev/pcidev.cc deleted file mode 100644 index a05ee3803..000000000 --- a/dev/pcidev.cc +++ /dev/null @@ -1,427 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* @file - * A single PCI device configuration space entry. - */ - -#include <list> -#include <sstream> -#include <string> -#include <vector> - -#include "base/inifile.hh" -#include "base/misc.hh" -#include "base/str.hh" // for to_number -#include "base/trace.hh" -#include "dev/pcidev.hh" -#include "dev/pciconfigall.hh" -#include "mem/bus/bus.hh" -#include "mem/functional/memory_control.hh" -#include "sim/builder.hh" -#include "sim/param.hh" -#include "sim/root.hh" -#include "dev/tsunamireg.h" - -using namespace std; - -PciDev::PciDev(Params *p) - : DmaDevice(p->name, p->plat), _params(p), plat(p->plat), - configData(p->configData) -{ - // copy the config data from the PciConfigData object - if (configData) { - memcpy(config.data, configData->config.data, sizeof(config.data)); - memcpy(BARSize, configData->BARSize, sizeof(BARSize)); - memcpy(BARAddrs, configData->BARAddrs, sizeof(BARAddrs)); - } else - panic("NULL pointer to configuration data"); - - // Setup pointer in config space to point to this entry - if (p->configSpace->deviceExists(p->deviceNum, p->functionNum)) - panic("Two PCI devices occuping same dev: %#x func: %#x", - p->deviceNum, p->functionNum); - else - p->configSpace->registerDevice(p->deviceNum, p->functionNum, this); -} - -Fault -PciDev::read(MemReqPtr &req, uint8_t *data) -{ return NoFault; } - -Fault -PciDev::write(MemReqPtr &req, const uint8_t *data) -{ return NoFault; } - -Fault -PciDev::readBar0(MemReqPtr &req, Addr daddr, uint8_t *data) -{ panic("not implemented"); } - -Fault -PciDev::readBar1(MemReqPtr &req, Addr daddr, uint8_t *data) -{ panic("not implemented"); } - -Fault -PciDev::readBar2(MemReqPtr &req, Addr daddr, uint8_t *data) -{ panic("not implemented"); } - -Fault -PciDev::readBar3(MemReqPtr &req, Addr daddr, uint8_t *data) -{ panic("not implemented"); } - -Fault -PciDev::readBar4(MemReqPtr &req, Addr daddr, uint8_t *data) -{ panic("not implemented"); } - -Fault -PciDev::readBar5(MemReqPtr &req, Addr daddr, uint8_t *data) -{ panic("not implemented"); } - -Fault -PciDev::writeBar0(MemReqPtr &req, Addr daddr, const uint8_t *data) -{ panic("not implemented"); } - -Fault -PciDev::writeBar1(MemReqPtr &req, Addr daddr, const uint8_t *data) -{ panic("not implemented"); } - -Fault -PciDev::writeBar2(MemReqPtr &req, Addr daddr, const uint8_t *data) -{ panic("not implemented"); } - -Fault -PciDev::writeBar3(MemReqPtr &req, Addr daddr, const uint8_t *data) -{ panic("not implemented"); } - -Fault -PciDev::writeBar4(MemReqPtr &req, Addr daddr, const uint8_t *data) -{ panic("not implemented"); } - -Fault -PciDev::writeBar5(MemReqPtr &req, Addr daddr, const uint8_t *data) -{ panic("not implemented"); } - -void -PciDev::readConfig(int offset, int size, uint8_t *data) -{ - if (offset >= PCI_DEVICE_SPECIFIC) - panic("Device specific PCI config space not implemented!\n"); - - switch(size) { - case sizeof(uint8_t): - *data = config.data[offset]; - break; - case sizeof(uint16_t): - *(uint16_t*)data = *(uint16_t*)&config.data[offset]; - break; - case sizeof(uint32_t): - *(uint32_t*)data = *(uint32_t*)&config.data[offset]; - break; - default: - panic("Invalid PCI configuration read size!\n"); - } - - DPRINTF(PCIDEV, - "read device: %#x function: %#x register: %#x %d bytes: data: %#x\n", - params()->deviceNum, params()->functionNum, offset, size, - *(uint32_t*)data); -} - -void -PciDev::writeConfig(int offset, int size, const uint8_t *data) -{ - if (offset >= PCI_DEVICE_SPECIFIC) - panic("Device specific PCI config space not implemented!\n"); - - uint8_t &data8 = *(uint8_t*)data; - uint16_t &data16 = *(uint16_t*)data; - uint32_t &data32 = *(uint32_t*)data; - - DPRINTF(PCIDEV, - "write device: %#x function: %#x reg: %#x size: %d data: %#x\n", - params()->deviceNum, params()->functionNum, offset, size, data32); - - switch (size) { - case sizeof(uint8_t): // 1-byte access - switch (offset) { - case PCI0_INTERRUPT_LINE: - config.interruptLine = data8; - case PCI_CACHE_LINE_SIZE: - config.cacheLineSize = data8; - case PCI_LATENCY_TIMER: - config.latencyTimer = data8; - break; - /* Do nothing for these read-only registers */ - case PCI0_INTERRUPT_PIN: - case PCI0_MINIMUM_GRANT: - case PCI0_MAXIMUM_LATENCY: - case PCI_CLASS_CODE: - case PCI_REVISION_ID: - break; - default: - panic("writing to a read only register"); - } - break; - - case sizeof(uint16_t): // 2-byte access - switch (offset) { - case PCI_COMMAND: - config.command = data16; - case PCI_STATUS: - config.status = data16; - case PCI_CACHE_LINE_SIZE: - config.cacheLineSize = data16; - break; - default: - panic("writing to a read only register"); - } - break; - - case sizeof(uint32_t): // 4-byte access - switch (offset) { - case PCI0_BASE_ADDR0: - case PCI0_BASE_ADDR1: - case PCI0_BASE_ADDR2: - case PCI0_BASE_ADDR3: - case PCI0_BASE_ADDR4: - case PCI0_BASE_ADDR5: - - uint32_t barnum, bar_mask; - Addr base_addr, base_size, space_base; - - barnum = BAR_NUMBER(offset); - - if (BAR_IO_SPACE(letoh(config.baseAddr[barnum]))) { - bar_mask = BAR_IO_MASK; - space_base = TSUNAMI_PCI0_IO; - } else { - bar_mask = BAR_MEM_MASK; - space_base = TSUNAMI_PCI0_MEMORY; - } - - // Writing 0xffffffff to a BAR tells the card to set the - // value of the bar to size of memory it needs - if (letoh(data32) == 0xffffffff) { - // This is I/O Space, bottom two bits are read only - - config.baseAddr[barnum] = letoh( - (~(BARSize[barnum] - 1) & ~bar_mask) | - (letoh(config.baseAddr[barnum]) & bar_mask)); - } else { - MemoryController *mmu = params()->mmu; - - config.baseAddr[barnum] = letoh( - (letoh(data32) & ~bar_mask) | - (letoh(config.baseAddr[barnum]) & bar_mask)); - - if (letoh(config.baseAddr[barnum]) & ~bar_mask) { - base_addr = (letoh(data32) & ~bar_mask) + space_base; - base_size = BARSize[barnum]; - - // It's never been set - if (BARAddrs[barnum] == 0) - mmu->add_child((FunctionalMemory *)this, - RangeSize(base_addr, base_size)); - else - mmu->update_child((FunctionalMemory *)this, - RangeSize(BARAddrs[barnum], base_size), - RangeSize(base_addr, base_size)); - - BARAddrs[barnum] = base_addr; - } - } - break; - - case PCI0_ROM_BASE_ADDR: - if (letoh(data32) == 0xfffffffe) - config.expansionROM = htole((uint32_t)0xffffffff); - else - config.expansionROM = data32; - break; - - case PCI_COMMAND: - // This could also clear some of the error bits in the Status - // register. However they should never get set, so lets ignore - // it for now - config.command = data16; - break; - - default: - DPRINTF(PCIDEV, "Writing to a read only register"); - } - break; - - default: - panic("invalid access size"); - } -} - -void -PciDev::serialize(ostream &os) -{ - SERIALIZE_ARRAY(BARSize, sizeof(BARSize) / sizeof(BARSize[0])); - SERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs) / sizeof(BARAddrs[0])); - SERIALIZE_ARRAY(config.data, sizeof(config.data) / sizeof(config.data[0])); -} - -void -PciDev::unserialize(Checkpoint *cp, const std::string §ion) -{ - UNSERIALIZE_ARRAY(BARSize, sizeof(BARSize) / sizeof(BARSize[0])); - UNSERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs) / sizeof(BARAddrs[0])); - UNSERIALIZE_ARRAY(config.data, - sizeof(config.data) / sizeof(config.data[0])); - - // Add the MMU mappings for the BARs - for (int i=0; i < 6; i++) { - if (BARAddrs[i] != 0) - params()->mmu->add_child(this, RangeSize(BARAddrs[i], BARSize[i])); - } -} - -#ifndef DOXYGEN_SHOULD_SKIP_THIS - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(PciConfigData) - - Param<uint16_t> VendorID; - Param<uint16_t> DeviceID; - Param<uint16_t> Command; - Param<uint16_t> Status; - Param<uint8_t> Revision; - Param<uint8_t> ProgIF; - Param<uint8_t> SubClassCode; - Param<uint8_t> ClassCode; - Param<uint8_t> CacheLineSize; - Param<uint8_t> LatencyTimer; - Param<uint8_t> HeaderType; - Param<uint8_t> BIST; - Param<uint32_t> BAR0; - Param<uint32_t> BAR1; - Param<uint32_t> BAR2; - Param<uint32_t> BAR3; - Param<uint32_t> BAR4; - Param<uint32_t> BAR5; - Param<uint32_t> CardbusCIS; - Param<uint16_t> SubsystemVendorID; - Param<uint16_t> SubsystemID; - Param<uint32_t> ExpansionROM; - Param<uint8_t> InterruptLine; - Param<uint8_t> InterruptPin; - Param<uint8_t> MinimumGrant; - Param<uint8_t> MaximumLatency; - Param<uint32_t> BAR0Size; - Param<uint32_t> BAR1Size; - Param<uint32_t> BAR2Size; - Param<uint32_t> BAR3Size; - Param<uint32_t> BAR4Size; - Param<uint32_t> BAR5Size; - -END_DECLARE_SIM_OBJECT_PARAMS(PciConfigData) - -BEGIN_INIT_SIM_OBJECT_PARAMS(PciConfigData) - - INIT_PARAM(VendorID, "Vendor ID"), - INIT_PARAM(DeviceID, "Device ID"), - INIT_PARAM_DFLT(Command, "Command Register", 0x00), - INIT_PARAM_DFLT(Status, "Status Register", 0x00), - INIT_PARAM_DFLT(Revision, "Device Revision", 0x00), - INIT_PARAM_DFLT(ProgIF, "Programming Interface", 0x00), - INIT_PARAM(SubClassCode, "Sub-Class Code"), - INIT_PARAM(ClassCode, "Class Code"), - INIT_PARAM_DFLT(CacheLineSize, "System Cacheline Size", 0x00), - INIT_PARAM_DFLT(LatencyTimer, "PCI Latency Timer", 0x00), - INIT_PARAM_DFLT(HeaderType, "PCI Header Type", 0x00), - INIT_PARAM_DFLT(BIST, "Built In Self Test", 0x00), - INIT_PARAM_DFLT(BAR0, "Base Address Register 0", 0x00), - INIT_PARAM_DFLT(BAR1, "Base Address Register 1", 0x00), - INIT_PARAM_DFLT(BAR2, "Base Address Register 2", 0x00), - INIT_PARAM_DFLT(BAR3, "Base Address Register 3", 0x00), - INIT_PARAM_DFLT(BAR4, "Base Address Register 4", 0x00), - INIT_PARAM_DFLT(BAR5, "Base Address Register 5", 0x00), - INIT_PARAM_DFLT(CardbusCIS, "Cardbus Card Information Structure", 0x00), - INIT_PARAM_DFLT(SubsystemVendorID, "Subsystem Vendor ID", 0x00), - INIT_PARAM_DFLT(SubsystemID, "Subsystem ID", 0x00), - INIT_PARAM_DFLT(ExpansionROM, "Expansion ROM Base Address Register", 0x00), - INIT_PARAM(InterruptLine, "Interrupt Line Register"), - INIT_PARAM(InterruptPin, "Interrupt Pin Register"), - INIT_PARAM_DFLT(MinimumGrant, "Minimum Grant", 0x00), - INIT_PARAM_DFLT(MaximumLatency, "Maximum Latency", 0x00), - INIT_PARAM_DFLT(BAR0Size, "Base Address Register 0 Size", 0x00), - INIT_PARAM_DFLT(BAR1Size, "Base Address Register 1 Size", 0x00), - INIT_PARAM_DFLT(BAR2Size, "Base Address Register 2 Size", 0x00), - INIT_PARAM_DFLT(BAR3Size, "Base Address Register 3 Size", 0x00), - INIT_PARAM_DFLT(BAR4Size, "Base Address Register 4 Size", 0x00), - INIT_PARAM_DFLT(BAR5Size, "Base Address Register 5 Size", 0x00) - -END_INIT_SIM_OBJECT_PARAMS(PciConfigData) - -CREATE_SIM_OBJECT(PciConfigData) -{ - PciConfigData *data = new PciConfigData(getInstanceName()); - - data->config.vendor = htole(VendorID); - data->config.device = htole(DeviceID); - data->config.command = htole(Command); - data->config.status = htole(Status); - data->config.revision = htole(Revision); - data->config.progIF = htole(ProgIF); - data->config.subClassCode = htole(SubClassCode); - data->config.classCode = htole(ClassCode); - data->config.cacheLineSize = htole(CacheLineSize); - data->config.latencyTimer = htole(LatencyTimer); - data->config.headerType = htole(HeaderType); - data->config.bist = htole(BIST); - - data->config.baseAddr0 = htole(BAR0); - data->config.baseAddr1 = htole(BAR1); - data->config.baseAddr2 = htole(BAR2); - data->config.baseAddr3 = htole(BAR3); - data->config.baseAddr4 = htole(BAR4); - data->config.baseAddr5 = htole(BAR5); - data->config.cardbusCIS = htole(CardbusCIS); - data->config.subsystemVendorID = htole(SubsystemVendorID); - data->config.subsystemID = htole(SubsystemVendorID); - data->config.expansionROM = htole(ExpansionROM); - data->config.interruptLine = htole(InterruptLine); - data->config.interruptPin = htole(InterruptPin); - data->config.minimumGrant = htole(MinimumGrant); - data->config.maximumLatency = htole(MaximumLatency); - - data->BARSize[0] = BAR0Size; - data->BARSize[1] = BAR1Size; - data->BARSize[2] = BAR2Size; - data->BARSize[3] = BAR3Size; - data->BARSize[4] = BAR4Size; - data->BARSize[5] = BAR5Size; - - return data; -} - -REGISTER_SIM_OBJECT("PciConfigData", PciConfigData) - -#endif // DOXYGEN_SHOULD_SKIP_THIS diff --git a/dev/pcidev.hh b/dev/pcidev.hh deleted file mode 100644 index bdfc6b932..000000000 --- a/dev/pcidev.hh +++ /dev/null @@ -1,298 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* @file - * Interface for devices using PCI configuration - */ - -#ifndef __DEV_PCIDEV_HH__ -#define __DEV_PCIDEV_HH__ - -#include "dev/io_device.hh" -#include "dev/pcireg.h" -#include "dev/platform.hh" - -#define BAR_IO_MASK 0x3 -#define BAR_MEM_MASK 0xF -#define BAR_IO_SPACE_BIT 0x1 -#define BAR_IO_SPACE(x) ((x) & BAR_IO_SPACE_BIT) -#define BAR_NUMBER(x) (((x) - PCI0_BASE_ADDR0) >> 0x2); - -class PciConfigAll; -class MemoryController; - - -/** - * This class encapulates the first 64 bytes of a singles PCI - * devices config space that in configured by the configuration file. - */ -class PciConfigData : public SimObject -{ - public: - /** - * Constructor to initialize the devices config space to 0. - */ - PciConfigData(const std::string &name) - : SimObject(name) - { - memset(config.data, 0, sizeof(config.data)); - memset(BARAddrs, 0, sizeof(BARAddrs)); - memset(BARSize, 0, sizeof(BARSize)); - } - - /** The first 64 bytes */ - PCIConfig config; - - /** The size of the BARs */ - uint32_t BARSize[6]; - - /** The addresses of the BARs */ - Addr BARAddrs[6]; -}; - -/** - * PCI device, base implemnation is only config space. - * Each device is connected to a PCIConfigSpace device - * which returns -1 for everything but the pcidevs that - * register with it. This object registers with the PCIConfig space - * object. - */ -class PciDev : public DmaDevice -{ - public: - struct Params - { - std::string name; - Platform *plat; - MemoryController *mmu; - - /** - * A pointer to the configspace all object that calls us when - * a read comes to this particular device/function. - */ - PciConfigAll *configSpace; - - /** - * A pointer to the object that contains the first 64 bytes of - * config space - */ - PciConfigData *configData; - - /** The bus number we are on */ - uint32_t busNum; - - /** The device number we have */ - uint32_t deviceNum; - - /** The function number */ - uint32_t functionNum; - }; - - protected: - Params *_params; - - public: - const Params *params() const { return _params; } - - protected: - /** The current config space. Unlike the PciConfigData this is - * updated during simulation while continues to reflect what was - * in the config file. - */ - PCIConfig config; - - /** The size of the BARs */ - uint32_t BARSize[6]; - - /** The current address mapping of the BARs */ - Addr BARAddrs[6]; - - bool - isBAR(Addr addr, int bar) const - { - assert(bar >= 0 && bar < 6); - return BARAddrs[bar] <= addr && addr < BARAddrs[bar] + BARSize[bar]; - } - - int - getBAR(Addr addr) - { - for (int i = 0; i <= 5; ++i) - if (isBAR(addr, i)) - return i; - - return -1; - } - - bool - getBAR(Addr paddr, Addr &daddr, int &bar) - { - int b = getBAR(paddr); - if (b < 0) - return false; - - daddr = paddr - BARAddrs[b]; - bar = b; - return true; - } - - protected: - Platform *plat; - PciConfigData *configData; - - public: - Addr pciToDma(Addr pciAddr) const - { return plat->pciToDma(pciAddr); } - - void - intrPost() - { plat->postPciInt(configData->config.interruptLine); } - - void - intrClear() - { plat->clearPciInt(configData->config.interruptLine); } - - uint8_t - interruptLine() - { return configData->config.interruptLine; } - - public: - /** - * Constructor for PCI Dev. This function copies data from the - * config file object PCIConfigData and registers the device with - * a PciConfigAll object. - */ - PciDev(Params *params); - - virtual Fault read(MemReqPtr &req, uint8_t *data); - virtual Fault write(MemReqPtr &req, const uint8_t *data); - - public: - /** - * Implement the read/write as BAR accesses - */ - Fault readBar(MemReqPtr &req, uint8_t *data); - Fault writeBar(MemReqPtr &req, const uint8_t *data); - - public: - /** - * Read from a specific BAR - */ - virtual Fault readBar0(MemReqPtr &req, Addr daddr, uint8_t *data); - virtual Fault readBar1(MemReqPtr &req, Addr daddr, uint8_t *data); - virtual Fault readBar2(MemReqPtr &req, Addr daddr, uint8_t *data); - virtual Fault readBar3(MemReqPtr &req, Addr daddr, uint8_t *data); - virtual Fault readBar4(MemReqPtr &req, Addr daddr, uint8_t *data); - virtual Fault readBar5(MemReqPtr &req, Addr daddr, uint8_t *data); - - public: - /** - * Write to a specific BAR - */ - virtual Fault writeBar0(MemReqPtr &req, Addr daddr, const uint8_t *data); - virtual Fault writeBar1(MemReqPtr &req, Addr daddr, const uint8_t *data); - virtual Fault writeBar2(MemReqPtr &req, Addr daddr, const uint8_t *data); - virtual Fault writeBar3(MemReqPtr &req, Addr daddr, const uint8_t *data); - virtual Fault writeBar4(MemReqPtr &req, Addr daddr, const uint8_t *data); - virtual Fault writeBar5(MemReqPtr &req, Addr daddr, const uint8_t *data); - - public: - /** - * Write to the PCI config space data that is stored locally. This may be - * overridden by the device but at some point it will eventually call this - * for normal operations that it does not need to override. - * @param offset the offset into config space - * @param size the size of the write - * @param data the data to write - */ - virtual void writeConfig(int offset, int size, const uint8_t* data); - - - /** - * Read from the PCI config space data that is stored locally. This may be - * overridden by the device but at some point it will eventually call this - * for normal operations that it does not need to override. - * @param offset the offset into config space - * @param size the size of the read - * @param data pointer to the location where the read value should be stored - */ - virtual void readConfig(int offset, int size, uint8_t *data); - - /** - * Serialize this object to the given output stream. - * @param os The stream to serialize to. - */ - virtual void serialize(std::ostream &os); - - /** - * Reconstruct the state of this object from a checkpoint. - * @param cp The checkpoint use. - * @param section The section name of this object - */ - virtual void unserialize(Checkpoint *cp, const std::string §ion); -}; - -inline Fault -PciDev::readBar(MemReqPtr &req, uint8_t *data) -{ - using namespace TheISA; - if (isBAR(req->paddr, 0)) - return readBar0(req, req->paddr - BARAddrs[0], data); - if (isBAR(req->paddr, 1)) - return readBar1(req, req->paddr - BARAddrs[1], data); - if (isBAR(req->paddr, 2)) - return readBar2(req, req->paddr - BARAddrs[2], data); - if (isBAR(req->paddr, 3)) - return readBar3(req, req->paddr - BARAddrs[3], data); - if (isBAR(req->paddr, 4)) - return readBar4(req, req->paddr - BARAddrs[4], data); - if (isBAR(req->paddr, 5)) - return readBar5(req, req->paddr - BARAddrs[5], data); - return genMachineCheckFault(); -} - -inline Fault -PciDev::writeBar(MemReqPtr &req, const uint8_t *data) -{ - using namespace TheISA; - if (isBAR(req->paddr, 0)) - return writeBar0(req, req->paddr - BARAddrs[0], data); - if (isBAR(req->paddr, 1)) - return writeBar1(req, req->paddr - BARAddrs[1], data); - if (isBAR(req->paddr, 2)) - return writeBar2(req, req->paddr - BARAddrs[2], data); - if (isBAR(req->paddr, 3)) - return writeBar3(req, req->paddr - BARAddrs[3], data); - if (isBAR(req->paddr, 4)) - return writeBar4(req, req->paddr - BARAddrs[4], data); - if (isBAR(req->paddr, 5)) - return writeBar5(req, req->paddr - BARAddrs[5], data); - return genMachineCheckFault(); -} - -#endif // __DEV_PCIDEV_HH__ diff --git a/dev/pktfifo.cc b/dev/pktfifo.cc deleted file mode 100644 index 639009be9..000000000 --- a/dev/pktfifo.cc +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "base/misc.hh" -#include "dev/pktfifo.hh" - -using namespace std; - -bool -PacketFifo::copyout(void *dest, int offset, int len) -{ - char *data = (char *)dest; - if (offset + len >= size()) - return false; - - list<PacketPtr>::iterator p = fifo.begin(); - list<PacketPtr>::iterator end = fifo.end(); - while (len > 0) { - while (offset >= (*p)->length) { - offset -= (*p)->length; - ++p; - } - - if (p == end) - panic("invalid fifo"); - - int size = min((*p)->length - offset, len); - memcpy(data, (*p)->data, size); - offset = 0; - len -= size; - data += size; - ++p; - } - - return true; -} - - -void -PacketFifo::serialize(const string &base, ostream &os) -{ - paramOut(os, base + ".size", _size); - paramOut(os, base + ".maxsize", _maxsize); - paramOut(os, base + ".reserved", _reserved); - paramOut(os, base + ".packets", fifo.size()); - - int i = 0; - list<PacketPtr>::iterator p = fifo.begin(); - list<PacketPtr>::iterator end = fifo.end(); - while (p != end) { - (*p)->serialize(csprintf("%s.packet%d", base, i), os); - ++p; - ++i; - } -} - -void -PacketFifo::unserialize(const string &base, Checkpoint *cp, - const string §ion) -{ - paramIn(cp, section, base + ".size", _size); -// paramIn(cp, section, base + ".maxsize", _maxsize); - paramIn(cp, section, base + ".reserved", _reserved); - int fifosize; - paramIn(cp, section, base + ".packets", fifosize); - - fifo.clear(); - - for (int i = 0; i < fifosize; ++i) { - PacketPtr p = new PacketData(16384); - p->unserialize(csprintf("%s.packet%d", base, i), cp, section); - fifo.push_back(p); - } -} diff --git a/dev/pktfifo.hh b/dev/pktfifo.hh deleted file mode 100644 index e245840a8..000000000 --- a/dev/pktfifo.hh +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __DEV_PKTFIFO_HH__ -#define __DEV_PKTFIFO_HH__ - -#include <iosfwd> -#include <list> -#include <string> - -#include "dev/etherpkt.hh" -#include "sim/serialize.hh" - -class Checkpoint; -class PacketFifo -{ - public: - typedef std::list<PacketPtr> fifo_list; - typedef fifo_list::iterator iterator; - - protected: - std::list<PacketPtr> fifo; - int _maxsize; - int _size; - int _reserved; - - public: - explicit PacketFifo(int max) : _maxsize(max), _size(0), _reserved(0) {} - virtual ~PacketFifo() {} - - int packets() const { return fifo.size(); } - int maxsize() const { return _maxsize; } - int size() const { return _size; } - int reserved() const { return _reserved; } - int avail() const { return _maxsize - _size - _reserved; } - bool empty() const { return size() <= 0; } - bool full() const { return avail() <= 0; } - - int reserve(int len = 0) - { - _reserved += len; - assert(avail() >= 0); - return _reserved; - } - - iterator begin() { return fifo.begin(); } - iterator end() { return fifo.end(); } - - PacketPtr front() { return fifo.front(); } - - bool push(PacketPtr ptr) - { - assert(ptr->length); - assert(_reserved <= ptr->length); - assert(ptr->slack == 0); - if (avail() < ptr->length - _reserved) - return false; - - _size += ptr->length; - fifo.push_back(ptr); - _reserved = 0; - return true; - } - - void pop() - { - if (empty()) - return; - - PacketPtr &packet = fifo.front(); - _size -= packet->length; - _size -= packet->slack; - packet->slack = 0; - packet = NULL; - fifo.pop_front(); - } - - void clear() - { - for (iterator i = begin(); i != end(); ++i) - (*i)->slack = 0; - fifo.clear(); - _size = 0; - _reserved = 0; - } - - void remove(iterator i) - { - PacketPtr &packet = *i; - if (i != fifo.begin()) { - iterator prev = i; - --prev; - assert(prev != fifo.end()); - (*prev)->slack += packet->length; - } else { - _size -= packet->length; - _size -= packet->slack; - } - - packet->slack = 0; - packet = NULL; - fifo.erase(i); - } - - bool copyout(void *dest, int offset, int len); - - int countPacketsBefore(iterator end) - { - iterator i = fifo.begin(); - int count = 0; - - while (i != end) { - ++count; - ++i; - } - - return count; - } - - int countPacketsAfter(iterator i) - { - iterator end = fifo.end(); - int count = 0; - - while (i != end) { - ++count; - ++i; - } - - return count; - } - - -/** - * Serialization stuff - */ - public: - void serialize(const std::string &base, std::ostream &os); - void unserialize(const std::string &base, - Checkpoint *cp, const std::string §ion); -}; - -#endif // __DEV_PKTFIFO_HH__ diff --git a/dev/platform.cc b/dev/platform.cc deleted file mode 100644 index 5b667b12c..000000000 --- a/dev/platform.cc +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "dev/platform.hh" -#include "sim/builder.hh" -#include "sim/sim_exit.hh" - -using namespace std; -using namespace TheISA; - -Platform::Platform(const string &name, IntrControl *intctrl, PciConfigAll *pci) - : SimObject(name), intrctrl(intctrl), pciconfig(pci) -{ -} - -Platform::~Platform() -{ -} - -void -Platform::postPciInt(int line) -{ - panic("No PCI interrupt support in platform."); -} - -void -Platform::clearPciInt(int line) -{ - panic("No PCI interrupt support in platform."); -} - -Addr -Platform::pciToDma(Addr pciAddr) const -{ - panic("No PCI dma support in platform."); -} - -DEFINE_SIM_OBJECT_CLASS_NAME("Platform", Platform) - diff --git a/dev/platform.hh b/dev/platform.hh deleted file mode 100644 index 1ee645454..000000000 --- a/dev/platform.hh +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * Generic interface for platforms - */ - -#ifndef __DEV_PLATFORM_HH__ -#define __DEV_PLATFORM_HH__ - -#include "sim/sim_object.hh" -#include "arch/isa_traits.hh" - -class PciConfigAll; -class IntrControl; -class SimConsole; -class Uart; - -class Platform : public SimObject -{ - public: - /** Pointer to the interrupt controller */ - IntrControl *intrctrl; - - /** Pointer to the PCI configuration space */ - PciConfigAll *pciconfig; - - /** Pointer to the UART, set by the uart */ - Uart *uart; - - public: - Platform(const std::string &name, IntrControl *intctrl, PciConfigAll *pci); - virtual ~Platform(); - virtual void postConsoleInt() = 0; - virtual void clearConsoleInt() = 0; - virtual Tick intrFrequency() = 0; - virtual void postPciInt(int line); - virtual void clearPciInt(int line); - virtual Addr pciToDma(Addr pciAddr) const; -}; - -#endif // __DEV_PLATFORM_HH__ diff --git a/dev/simconsole.cc b/dev/simconsole.cc deleted file mode 100644 index b818e61f4..000000000 --- a/dev/simconsole.cc +++ /dev/null @@ -1,415 +0,0 @@ -/* - * Copyright (c) 2001-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* @file - * Implements the user interface to a serial console - */ - -#include <sys/ioctl.h> -#include <sys/termios.h> -#include <sys/types.h> -#include <errno.h> -#include <poll.h> -#include <unistd.h> - -#include <iostream> -#include <fstream> -#include <sstream> -#include <string> - -#include "base/misc.hh" -#include "base/output.hh" -#include "base/socket.hh" -#include "base/trace.hh" -#include "dev/platform.hh" -#include "dev/simconsole.hh" -#include "dev/uart.hh" -#include "mem/functional/memory_control.hh" -#include "sim/builder.hh" - -using namespace std; - -//////////////////////////////////////////////////////////////////////// -// -// - -SimConsole::Event::Event(SimConsole *c, int fd, int e) - : PollEvent(fd, e), cons(c) -{ -} - -void -SimConsole::Event::process(int revent) -{ - if (revent & POLLIN) - cons->data(); - else if (revent & POLLNVAL) - cons->detach(); -} - -SimConsole::SimConsole(const string &name, ostream *os, int num) - : SimObject(name), event(NULL), number(num), in_fd(-1), out_fd(-1), - listener(NULL), txbuf(16384), rxbuf(16384), outfile(os) -#if TRACING_ON == 1 - , linebuf(16384) -#endif -{ - if (outfile) - outfile->setf(ios::unitbuf); -} - -SimConsole::~SimConsole() -{ - close(); -} - -void -SimConsole::close() -{ - if (in_fd != -1) - ::close(in_fd); - - if (out_fd != in_fd && out_fd != -1) - ::close(out_fd); -} - -void -SimConsole::attach(int in, int out, ConsoleListener *l) -{ - in_fd = in; - out_fd = out; - listener = l; - - event = new Event(this, in, POLLIN); - pollQueue.schedule(event); - - stringstream stream; - ccprintf(stream, "==== m5 slave console: Console %d ====", number); - - // we need an actual carriage return followed by a newline for the - // terminal - stream << "\r\n"; - - write((const uint8_t *)stream.str().c_str(), stream.str().size()); - - - DPRINTFN("attach console %d\n", number); - - txbuf.readall(out); -} - -void -SimConsole::detach() -{ - close(); - in_fd = -1; - out_fd = -1; - - pollQueue.remove(event); - - if (listener) { - listener->add(this); - listener = NULL; - } - - DPRINTFN("detach console %d\n", number); -} - -void -SimConsole::data() -{ - uint8_t buf[1024]; - int len; - - len = read(buf, sizeof(buf)); - if (len) { - rxbuf.write((char *)buf, len); - // Inform the UART there is data available - uart->dataAvailable(); - } -} - -size_t -SimConsole::read(uint8_t *buf, size_t len) -{ - if (in_fd < 0) - panic("Console not properly attached.\n"); - - size_t ret; - do { - ret = ::read(in_fd, buf, len); - } while (ret == -1 && errno == EINTR); - - - if (ret < 0) - DPRINTFN("Read failed.\n"); - - if (ret <= 0) { - detach(); - return 0; - } - - return ret; -} - -// Console output. -size_t -SimConsole::write(const uint8_t *buf, size_t len) -{ - if (out_fd < 0) - panic("Console not properly attached.\n"); - - size_t ret; - for (;;) { - ret = ::write(out_fd, buf, len); - - if (ret >= 0) - break; - - if (errno != EINTR) - detach(); - } - - return ret; -} - -#define MORE_PENDING (ULL(1) << 61) -#define RECEIVE_SUCCESS (ULL(0) << 62) -#define RECEIVE_NONE (ULL(2) << 62) -#define RECEIVE_ERROR (ULL(3) << 62) - -bool -SimConsole::in(uint8_t &c) -{ - bool empty, ret; - - empty = rxbuf.empty(); - ret = !empty; - if (!empty) { - rxbuf.read((char *)&c, 1); - empty = rxbuf.empty(); - } - - DPRINTF(ConsoleVerbose, "in: \'%c\' %#02x more: %d, return: %d\n", - isprint(c) ? c : ' ', c, !empty, ret); - - return ret; -} - -uint64_t -SimConsole::console_in() -{ - uint8_t c; - uint64_t value; - - if (in(c)) { - value = RECEIVE_SUCCESS | c; - if (!rxbuf.empty()) - value |= MORE_PENDING; - } else { - value = RECEIVE_NONE; - } - - DPRINTF(ConsoleVerbose, "console_in: return: %#x\n", value); - - return value; -} - -void -SimConsole::out(char c) -{ -#if TRACING_ON == 1 - if (DTRACE(Console)) { - static char last = '\0'; - - if (c != '\n' && c != '\r' || - last != '\n' && last != '\r') { - if (c == '\n' || c == '\r') { - int size = linebuf.size(); - char *buffer = new char[size + 1]; - linebuf.read(buffer, size); - buffer[size] = '\0'; - DPRINTF(Console, "%s\n", buffer); - delete [] buffer; - } else { - linebuf.write(c); - } - } - - last = c; - } -#endif - - txbuf.write(c); - - if (out_fd >= 0) - write(c); - - if (outfile) - outfile->write(&c, 1); - - DPRINTF(ConsoleVerbose, "out: \'%c\' %#02x\n", - isprint(c) ? c : ' ', (int)c); - -} - - -void -SimConsole::serialize(ostream &os) -{ -} - -void -SimConsole::unserialize(Checkpoint *cp, const std::string §ion) -{ -} - - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimConsole) - - SimObjectParam<ConsoleListener *> listener; - SimObjectParam<IntrControl *> intr_control; - Param<string> output; - Param<bool> append_name; - Param<int> number; - -END_DECLARE_SIM_OBJECT_PARAMS(SimConsole) - -BEGIN_INIT_SIM_OBJECT_PARAMS(SimConsole) - - INIT_PARAM(listener, "console listener"), - INIT_PARAM(intr_control, "interrupt controller"), - INIT_PARAM(output, "file to dump output to"), - INIT_PARAM_DFLT(append_name, "append name() to filename", true), - INIT_PARAM_DFLT(number, "console number", 0) - -END_INIT_SIM_OBJECT_PARAMS(SimConsole) - -CREATE_SIM_OBJECT(SimConsole) -{ - string filename = output; - ostream *stream = NULL; - - if (!filename.empty()) { - if (append_name) - filename += "." + getInstanceName(); - stream = simout.find(filename); - } - - SimConsole *console = new SimConsole(getInstanceName(), stream, number); - ((ConsoleListener *)listener)->add(console); - - return console; -} - -REGISTER_SIM_OBJECT("SimConsole", SimConsole) - -//////////////////////////////////////////////////////////////////////// -// -// - -ConsoleListener::ConsoleListener(const string &name) - : SimObject(name), event(NULL) -{} - -ConsoleListener::~ConsoleListener() -{ - if (event) - delete event; -} - -void -ConsoleListener::Event::process(int revent) -{ - listener->accept(); -} - -/////////////////////////////////////////////////////////////////////// -// socket creation and console attach -// - -void -ConsoleListener::listen(int port) -{ - while (!listener.listen(port, true)) { - DPRINTF(Console, - ": can't bind address console port %d inuse PID %d\n", - port, getpid()); - port++; - } - - ccprintf(cerr, "Listening for console connection on port %d\n", port); - - event = new Event(this, listener.getfd(), POLLIN); - pollQueue.schedule(event); -} - -void -ConsoleListener::add(SimConsole *cons) -{ ConsoleList.push_back(cons);} - -void -ConsoleListener::accept() -{ - if (!listener.islistening()) - panic("%s: cannot accept a connection if not listening!", name()); - - int sfd = listener.accept(true); - if (sfd != -1) { - iter_t i = ConsoleList.begin(); - iter_t end = ConsoleList.end(); - if (i == end) { - close(sfd); - } else { - (*i)->attach(sfd, this); - i = ConsoleList.erase(i); - } - } -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(ConsoleListener) - - Param<int> port; - -END_DECLARE_SIM_OBJECT_PARAMS(ConsoleListener) - -BEGIN_INIT_SIM_OBJECT_PARAMS(ConsoleListener) - - INIT_PARAM_DFLT(port, "listen port", 3456) - -END_INIT_SIM_OBJECT_PARAMS(ConsoleListener) - -CREATE_SIM_OBJECT(ConsoleListener) -{ - ConsoleListener *listener = new ConsoleListener(getInstanceName()); - listener->listen(port); - - return listener; -} - -REGISTER_SIM_OBJECT("ConsoleListener", ConsoleListener) diff --git a/dev/simconsole.hh b/dev/simconsole.hh deleted file mode 100644 index cf0641f9e..000000000 --- a/dev/simconsole.hh +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright (c) 2001-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* @file - * User Console Interface - */ - -#ifndef __CONSOLE_HH__ -#define __CONSOLE_HH__ - -#include <iostream> - -#include "base/circlebuf.hh" -#include "cpu/intr_control.hh" -#include "base/pollevent.hh" -#include "base/socket.hh" -#include "sim/sim_object.hh" - -class ConsoleListener; -class Uart; - -class SimConsole : public SimObject -{ - public: - Uart *uart; - - protected: - class Event : public PollEvent - { - protected: - SimConsole *cons; - - public: - Event(SimConsole *c, int fd, int e); - void process(int revent); - }; - - friend class Event; - Event *event; - - protected: - int number; - int in_fd; - int out_fd; - ConsoleListener *listener; - - public: - SimConsole(const std::string &name, std::ostream *os, int num); - ~SimConsole(); - - protected: - CircleBuf txbuf; - CircleBuf rxbuf; - std::ostream *outfile; -#if TRACING_ON == 1 - CircleBuf linebuf; -#endif - - public: - /////////////////////// - // Terminal Interface - - void attach(int fd, ConsoleListener *l = NULL) { attach(fd, fd, l); } - void attach(int in, int out, ConsoleListener *l = NULL); - void detach(); - - void data(); - - void close(); - void read(uint8_t &c) { read(&c, 1); } - size_t read(uint8_t *buf, size_t len); - void write(uint8_t c) { write(&c, 1); } - size_t write(const uint8_t *buf, size_t len); - - public: - ///////////////// - // OS interface - - // Get a character from the console. - bool in(uint8_t &value); - - // get a character from the console in the console specific format - // corresponds to GETC: - // retval<63:61> - // 000: success: character received - // 001: success: character received, more pending - // 100: failure: no character ready - // 110: failure: character received with error - // 111: failure: character received with error, more pending - // retval<31:0> - // character read from console - // - // Interrupts are cleared when the buffer is empty. - uint64_t console_in(); - - // Send a character to the console - void out(char c); - - //Ask the console if data is available - bool dataAvailable() { return !rxbuf.empty(); } - - virtual void serialize(std::ostream &os); - virtual void unserialize(Checkpoint *cp, const std::string §ion); -}; - -class ConsoleListener : public SimObject -{ - protected: - class Event : public PollEvent - { - protected: - ConsoleListener *listener; - - public: - Event(ConsoleListener *l, int fd, int e) - : PollEvent(fd, e), listener(l) {} - void process(int revent); - }; - - friend class Event; - Event *event; - - typedef std::list<SimConsole *> list_t; - typedef list_t::iterator iter_t; - list_t ConsoleList; - - protected: - ListenSocket listener; - - public: - ConsoleListener(const std::string &name); - ~ConsoleListener(); - - void add(SimConsole *cons); - - void accept(); - void listen(int port); -}; - -#endif // __CONSOLE_HH__ diff --git a/dev/simple_disk.cc b/dev/simple_disk.cc deleted file mode 100644 index b8c5d44ab..000000000 --- a/dev/simple_disk.cc +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2001-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* @file - * Simple disk interface for the system console - */ - -#include <sys/types.h> -#include <sys/uio.h> -#include <fcntl.h> -#include <unistd.h> - -#include <cstring> -#include <string> - -#include "base/misc.hh" -#include "base/trace.hh" -#include "dev/disk_image.hh" -#include "dev/simple_disk.hh" -#include "mem/functional/physical.hh" -#include "sim/builder.hh" - -using namespace std; - -SimpleDisk::SimpleDisk(const string &name, PhysicalMemory *pmem, - DiskImage *img) - : SimObject(name), physmem(pmem), image(img) -{} - -SimpleDisk::~SimpleDisk() -{} - - -void -SimpleDisk::read(Addr addr, baddr_t block, int count) const -{ - uint8_t *data = physmem->dma_addr(addr, count); - if (!data) - panic("dma out of range! read addr=%#x count=%d\n", addr, count); - - if (count & (SectorSize - 1)) - panic("Not reading a multiple of a sector (count = %d)", count); - - for (int i = 0, j = 0; i < count; i += SectorSize, j++) - image->read(data + i, block + j); - - DPRINTF(SimpleDisk, "read block=%#x len=%d\n", (uint64_t)block, count); - DDUMP(SimpleDiskData, data, count); -} - -void -SimpleDisk::write(Addr addr, baddr_t block, int count) -{ - panic("unimplemented!\n"); - -#if 0 - uint8_t *data = physmem->dma_addr(addr, count); - if (!data) - panic("dma out of range! write addr=%#x count=%d\n", addr, count); - - image->write(data, block, count); -#endif -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleDisk) - - SimObjectParam<PhysicalMemory *> physmem; - SimObjectParam<DiskImage *> disk; - -END_DECLARE_SIM_OBJECT_PARAMS(SimpleDisk) - -BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleDisk) - - INIT_PARAM(physmem, "Physical Memory"), - INIT_PARAM(disk, "Disk Image") - -END_INIT_SIM_OBJECT_PARAMS(SimpleDisk) - -CREATE_SIM_OBJECT(SimpleDisk) -{ - return new SimpleDisk(getInstanceName(), physmem, disk); -} - -REGISTER_SIM_OBJECT("SimpleDisk", SimpleDisk) diff --git a/dev/simple_disk.hh b/dev/simple_disk.hh deleted file mode 100644 index 57f81c5a9..000000000 --- a/dev/simple_disk.hh +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2001-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* @file - * Simple disk interface for the system console - */ - -#ifndef __DEV_SIMPLE_DISK_HH__ -#define __DEV_SIMPLE_DISK_HH__ - -#include "sim/sim_object.hh" -#include "arch/isa_traits.hh" - -class DiskImage; -class PhysicalMemory; - -/* - * Trivial interface to a disk image used by the System Console - */ -class SimpleDisk : public SimObject -{ - public: - typedef uint64_t baddr_t; - - protected: - PhysicalMemory *physmem; - DiskImage *image; - - public: - SimpleDisk(const std::string &name, PhysicalMemory *pmem, DiskImage *img); - ~SimpleDisk(); - - void read(Addr addr, baddr_t block, int count) const; - void write(Addr addr, baddr_t block, int count); -}; - -#endif // __DEV_SIMPLE_DISK_HH__ diff --git a/dev/sinic.cc b/dev/sinic.cc deleted file mode 100644 index 0853717ba..000000000 --- a/dev/sinic.cc +++ /dev/null @@ -1,1905 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <cstdio> -#include <deque> -#include <string> - -#include "base/inet.hh" -#include "cpu/exec_context.hh" -#include "cpu/intr_control.hh" -#include "dev/etherlink.hh" -#include "dev/sinic.hh" -#include "dev/pciconfigall.hh" -#include "mem/bus/bus.hh" -#include "mem/bus/dma_interface.hh" -#include "mem/bus/pio_interface.hh" -#include "mem/bus/pio_interface_impl.hh" -#include "mem/functional/memory_control.hh" -#include "mem/functional/physical.hh" -#include "sim/builder.hh" -#include "sim/debug.hh" -#include "sim/eventq.hh" -#include "sim/host.hh" -#include "sim/stats.hh" -#include "arch/vtophys.hh" - -using namespace Net; -using namespace TheISA; - -namespace Sinic { - -const char *RxStateStrings[] = -{ - "rxIdle", - "rxFifoBlock", - "rxBeginCopy", - "rxCopy", - "rxCopyDone" -}; - -const char *TxStateStrings[] = -{ - "txIdle", - "txFifoBlock", - "txBeginCopy", - "txCopy", - "txCopyDone" -}; - - -/////////////////////////////////////////////////////////////////////// -// -// Sinic PCI Device -// -Base::Base(Params *p) - : PciDev(p), rxEnable(false), txEnable(false), clock(p->clock), - intrDelay(p->intr_delay), intrTick(0), cpuIntrEnable(false), - cpuPendingIntr(false), intrEvent(0), interface(NULL) -{ -} - -Device::Device(Params *p) - : Base(p), plat(p->plat), physmem(p->physmem), rxUnique(0), txUnique(0), - virtualRegs(p->virtual_count < 1 ? 1 : p->virtual_count), - rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size), - rxKickTick(0), txKickTick(0), - txEvent(this), rxDmaEvent(this), txDmaEvent(this), - dmaReadDelay(p->dma_read_delay), dmaReadFactor(p->dma_read_factor), - dmaWriteDelay(p->dma_write_delay), dmaWriteFactor(p->dma_write_factor) -{ - reset(); - - if (p->pio_bus) { - pioInterface = newPioInterface(p->name + ".pio", p->hier, p->pio_bus, - this, &Device::cacheAccess); - pioLatency = p->pio_latency * p->pio_bus->clockRate; - } - - if (p->header_bus) { - if (p->payload_bus) - dmaInterface = new DMAInterface<Bus>(p->name + ".dma", - p->header_bus, - p->payload_bus, 1, - p->dma_no_allocate); - else - dmaInterface = new DMAInterface<Bus>(p->name + ".dma", - p->header_bus, - p->header_bus, 1, - p->dma_no_allocate); - } else if (p->payload_bus) - panic("must define a header bus if defining a payload bus"); -} - -Device::~Device() -{} - -void -Device::regStats() -{ - rxBytes - .name(name() + ".rxBytes") - .desc("Bytes Received") - .prereq(rxBytes) - ; - - rxBandwidth - .name(name() + ".rxBandwidth") - .desc("Receive Bandwidth (bits/s)") - .precision(0) - .prereq(rxBytes) - ; - - rxPackets - .name(name() + ".rxPackets") - .desc("Number of Packets Received") - .prereq(rxBytes) - ; - - rxPacketRate - .name(name() + ".rxPPS") - .desc("Packet Reception Rate (packets/s)") - .precision(0) - .prereq(rxBytes) - ; - - rxIpPackets - .name(name() + ".rxIpPackets") - .desc("Number of IP Packets Received") - .prereq(rxBytes) - ; - - rxTcpPackets - .name(name() + ".rxTcpPackets") - .desc("Number of Packets Received") - .prereq(rxBytes) - ; - - rxUdpPackets - .name(name() + ".rxUdpPackets") - .desc("Number of UDP Packets Received") - .prereq(rxBytes) - ; - - rxIpChecksums - .name(name() + ".rxIpChecksums") - .desc("Number of rx IP Checksums done by device") - .precision(0) - .prereq(rxBytes) - ; - - rxTcpChecksums - .name(name() + ".rxTcpChecksums") - .desc("Number of rx TCP Checksums done by device") - .precision(0) - .prereq(rxBytes) - ; - - rxUdpChecksums - .name(name() + ".rxUdpChecksums") - .desc("Number of rx UDP Checksums done by device") - .precision(0) - .prereq(rxBytes) - ; - - totBandwidth - .name(name() + ".totBandwidth") - .desc("Total Bandwidth (bits/s)") - .precision(0) - .prereq(totBytes) - ; - - totPackets - .name(name() + ".totPackets") - .desc("Total Packets") - .precision(0) - .prereq(totBytes) - ; - - totBytes - .name(name() + ".totBytes") - .desc("Total Bytes") - .precision(0) - .prereq(totBytes) - ; - - totPacketRate - .name(name() + ".totPPS") - .desc("Total Tranmission Rate (packets/s)") - .precision(0) - .prereq(totBytes) - ; - - txBytes - .name(name() + ".txBytes") - .desc("Bytes Transmitted") - .prereq(txBytes) - ; - - txBandwidth - .name(name() + ".txBandwidth") - .desc("Transmit Bandwidth (bits/s)") - .precision(0) - .prereq(txBytes) - ; - - txPackets - .name(name() + ".txPackets") - .desc("Number of Packets Transmitted") - .prereq(txBytes) - ; - - txPacketRate - .name(name() + ".txPPS") - .desc("Packet Tranmission Rate (packets/s)") - .precision(0) - .prereq(txBytes) - ; - - txIpPackets - .name(name() + ".txIpPackets") - .desc("Number of IP Packets Transmitted") - .prereq(txBytes) - ; - - txTcpPackets - .name(name() + ".txTcpPackets") - .desc("Number of TCP Packets Transmitted") - .prereq(txBytes) - ; - - txUdpPackets - .name(name() + ".txUdpPackets") - .desc("Number of Packets Transmitted") - .prereq(txBytes) - ; - - txIpChecksums - .name(name() + ".txIpChecksums") - .desc("Number of tx IP Checksums done by device") - .precision(0) - .prereq(txBytes) - ; - - txTcpChecksums - .name(name() + ".txTcpChecksums") - .desc("Number of tx TCP Checksums done by device") - .precision(0) - .prereq(txBytes) - ; - - txUdpChecksums - .name(name() + ".txUdpChecksums") - .desc("Number of tx UDP Checksums done by device") - .precision(0) - .prereq(txBytes) - ; - - txBandwidth = txBytes * Stats::constant(8) / simSeconds; - rxBandwidth = rxBytes * Stats::constant(8) / simSeconds; - totBandwidth = txBandwidth + rxBandwidth; - totBytes = txBytes + rxBytes; - totPackets = txPackets + rxPackets; - txPacketRate = txPackets / simSeconds; - rxPacketRate = rxPackets / simSeconds; -} - -/** - * This is to write to the PCI general configuration registers - */ -void -Device::writeConfig(int offset, int size, const uint8_t *data) -{ - switch (offset) { - case PCI0_BASE_ADDR0: - // Need to catch writes to BARs to update the PIO interface - PciDev::writeConfig(offset, size, data); - if (BARAddrs[0] != 0) { - if (pioInterface) - pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0])); - - BARAddrs[0] &= EV5::PAddrUncachedMask; - } - break; - - default: - PciDev::writeConfig(offset, size, data); - } -} - -void -Device::prepareIO(int cpu, int index) -{ - int size = virtualRegs.size(); - if (index > size) - panic("Trying to access a vnic that doesn't exist %d > %d\n", - index, size); -} - -void -Device::prepareRead(int cpu, int index) -{ - using namespace Regs; - prepareIO(cpu, index); - - VirtualReg &vnic = virtualRegs[index]; - - // update rx registers - uint64_t rxdone = vnic.RxDone; - rxdone = set_RxDone_Packets(rxdone, rxFifo.countPacketsAfter(rxFifoPtr)); - rxdone = set_RxDone_Empty(rxdone, rxFifo.empty()); - rxdone = set_RxDone_High(rxdone, rxFifo.size() > regs.RxFifoMark); - rxdone = set_RxDone_NotHigh(rxdone, rxLow); - regs.RxData = vnic.RxData; - regs.RxDone = rxdone; - regs.RxWait = rxdone; - - // update tx regsiters - uint64_t txdone = vnic.TxDone; - txdone = set_TxDone_Packets(txdone, txFifo.packets()); - txdone = set_TxDone_Full(txdone, txFifo.avail() < regs.TxMaxCopy); - txdone = set_TxDone_Low(txdone, txFifo.size() < regs.TxFifoMark); - regs.TxData = vnic.TxData; - regs.TxDone = txdone; - regs.TxWait = txdone; -} - -void -Device::prepareWrite(int cpu, int index) -{ - prepareIO(cpu, index); -} - -/** - * I/O read of device register - */ -Fault -Device::read(MemReqPtr &req, uint8_t *data) -{ - assert(config.command & PCI_CMD_MSE); - Fault fault = readBar(req, data); - - if (fault && fault->isMachineCheckFault()) { - panic("address does not map to a BAR pa=%#x va=%#x size=%d", - req->paddr, req->vaddr, req->size); - - return genMachineCheckFault(); - } - - return fault; -} - -Fault -Device::readBar0(MemReqPtr &req, Addr daddr, uint8_t *data) -{ - int cpu = (req->xc->readMiscReg(TheISA::IPR_PALtemp16) >> 8) & 0xff; - Addr index = daddr >> Regs::VirtualShift; - Addr raddr = daddr & Regs::VirtualMask; - - if (!regValid(raddr)) - panic("invalid register: cpu=%d vnic=%d da=%#x pa=%#x va=%#x size=%d", - cpu, index, daddr, req->paddr, req->vaddr, req->size); - - const Regs::Info &info = regInfo(raddr); - if (!info.read) - panic("read %s (write only): " - "cpu=%d vnic=%d da=%#x pa=%#x va=%#x size=%d", - info.name, cpu, index, daddr, req->paddr, req->vaddr, req->size); - - if (req->size != info.size) - panic("read %s (invalid size): " - "cpu=%d vnic=%d da=%#x pa=%#x va=%#x size=%d", - info.name, cpu, index, daddr, req->paddr, req->vaddr, req->size); - - prepareRead(cpu, index); - - uint64_t value = 0; - if (req->size == 4) { - uint32_t ® = *(uint32_t *)data; - reg = regData32(raddr); - value = reg; - } - - if (req->size == 8) { - uint64_t ® = *(uint64_t *)data; - reg = regData64(raddr); - value = reg; - } - - DPRINTF(EthernetPIO, - "read %s: cpu=%d vnic=%d da=%#x pa=%#x va=%#x size=%d val=%#x\n", - info.name, cpu, index, daddr, req->paddr, req->vaddr, req->size, - value); - - // reading the interrupt status register has the side effect of - // clearing it - if (raddr == Regs::IntrStatus) - devIntrClear(); - - return NoFault; -} - -/** - * IPR read of device register - */ -Fault -Device::iprRead(Addr daddr, int cpu, uint64_t &result) -{ - if (!regValid(daddr)) - panic("invalid address: da=%#x", daddr); - - const Regs::Info &info = regInfo(daddr); - if (!info.read) - panic("reading %s (write only): cpu=%d da=%#x", info.name, cpu, daddr); - - DPRINTF(EthernetPIO, "IPR read %s: cpu=%d da=%#x\n", - info.name, cpu, daddr); - - prepareRead(cpu, 0); - - if (info.size == 4) - result = regData32(daddr); - - if (info.size == 8) - result = regData64(daddr); - - DPRINTF(EthernetPIO, "IPR read %s: cpu=%s da=%#x val=%#x\n", - info.name, cpu, result); - - return NoFault; -} - -/** - * I/O write of device register - */ -Fault -Device::write(MemReqPtr &req, const uint8_t *data) -{ - assert(config.command & PCI_CMD_MSE); - Fault fault = writeBar(req, data); - - if (fault && fault->isMachineCheckFault()) { - panic("address does not map to a BAR pa=%#x va=%#x size=%d", - req->paddr, req->vaddr, req->size); - - return genMachineCheckFault(); - } - - return fault; -} - -Fault -Device::writeBar0(MemReqPtr &req, Addr daddr, const uint8_t *data) -{ - int cpu = (req->xc->readMiscReg(TheISA::IPR_PALtemp16) >> 8) & 0xff; - Addr index = daddr >> Regs::VirtualShift; - Addr raddr = daddr & Regs::VirtualMask; - - if (!regValid(raddr)) - panic("invalid address: cpu=%d da=%#x pa=%#x va=%#x size=%d", - cpu, daddr, req->paddr, req->vaddr, req->size); - - const Regs::Info &info = regInfo(raddr); - if (!info.write) - panic("write %s (read only): " - "cpu=%d vnic=%d da=%#x pa=%#x va=%#x size=%d", - info.name, cpu, index, daddr, req->paddr, req->vaddr, req->size); - - if (req->size != info.size) - panic("write %s (invalid size): " - "cpu=%d vnic=%d da=%#x pa=%#x va=%#x size=%d", - info.name, cpu, index, daddr, req->paddr, req->vaddr, req->size); - - uint32_t reg32 = *(uint32_t *)data; - uint64_t reg64 = *(uint64_t *)data; - VirtualReg &vnic = virtualRegs[index]; - - DPRINTF(EthernetPIO, - "write %s vnic %d: cpu=%d val=%#x da=%#x pa=%#x va=%#x size=%d\n", - info.name, index, cpu, info.size == 4 ? reg32 : reg64, daddr, - req->paddr, req->vaddr, req->size); - - prepareWrite(cpu, index); - - switch (raddr) { - case Regs::Config: - changeConfig(reg32); - break; - - case Regs::Command: - command(reg32); - break; - - case Regs::IntrStatus: - devIntrClear(regs.IntrStatus & reg32); - break; - - case Regs::IntrMask: - devIntrChangeMask(reg32); - break; - - case Regs::RxData: - if (Regs::get_RxDone_Busy(vnic.RxDone)) - panic("receive machine busy with another request! rxState=%s", - RxStateStrings[rxState]); - - vnic.rxUnique = rxUnique++; - vnic.RxDone = Regs::RxDone_Busy; - vnic.RxData = reg64; - - if (Regs::get_RxData_Vaddr(reg64)) { - Addr vaddr = Regs::get_RxData_Addr(reg64); - Addr paddr = vtophys(req->xc, vaddr); - DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d): " - "vaddr=%#x, paddr=%#x\n", - index, vnic.rxUnique, vaddr, paddr); - - vnic.RxData = Regs::set_RxData_Addr(vnic.RxData, paddr); - } else { - DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d)\n", - index, vnic.rxUnique); - } - - if (vnic.rxPacket == rxFifo.end()) { - DPRINTF(EthernetPIO, "request new packet...appending to rxList\n"); - rxList.push_back(index); - } else { - DPRINTF(EthernetPIO, "packet exists...appending to rxBusy\n"); - rxBusy.push_back(index); - } - - if (rxEnable && (rxState == rxIdle || rxState == rxFifoBlock)) { - rxState = rxFifoBlock; - rxKick(); - } - break; - - case Regs::TxData: - if (Regs::get_TxDone_Busy(vnic.TxDone)) - panic("transmit machine busy with another request! txState=%s", - TxStateStrings[txState]); - - vnic.txUnique = txUnique++; - vnic.TxDone = Regs::TxDone_Busy; - vnic.TxData = reg64; - - if (Regs::get_TxData_Vaddr(reg64)) { - Addr vaddr = Regs::get_TxData_Addr(reg64); - Addr paddr = vtophys(req->xc, vaddr); - DPRINTF(EthernetPIO, "write TxData vnic %d (rxunique %d): " - "vaddr=%#x, paddr=%#x\n", - index, vnic.txUnique, vaddr, paddr); - - vnic.TxData = Regs::set_TxData_Addr(vnic.TxData, paddr); - } else { - DPRINTF(EthernetPIO, "write TxData vnic %d (rxunique %d)\n", - index, vnic.txUnique); - } - - if (txList.empty() || txList.front() != index) - txList.push_back(index); - if (txEnable && txState == txIdle && txList.front() == index) { - txState = txFifoBlock; - txKick(); - } - break; - } - - return NoFault; -} - -void -Device::devIntrPost(uint32_t interrupts) -{ - if ((interrupts & Regs::Intr_Res)) - panic("Cannot set a reserved interrupt"); - - regs.IntrStatus |= interrupts; - - DPRINTF(EthernetIntr, - "interrupt written to intStatus: intr=%#x status=%#x mask=%#x\n", - interrupts, regs.IntrStatus, regs.IntrMask); - - interrupts = regs.IntrStatus & regs.IntrMask; - - // Intr_RxHigh is special, we only signal it if we've emptied the fifo - // and then filled it above the high watermark - if (rxEmpty) - rxEmpty = false; - else - interrupts &= ~Regs::Intr_RxHigh; - - // Intr_TxLow is special, we only signal it if we've filled up the fifo - // and then dropped below the low watermark - if (txFull) - txFull = false; - else - interrupts &= ~Regs::Intr_TxLow; - - if (interrupts) { - Tick when = curTick; - if ((interrupts & Regs::Intr_NoDelay) == 0) - when += intrDelay; - cpuIntrPost(when); - } -} - -void -Device::devIntrClear(uint32_t interrupts) -{ - if ((interrupts & Regs::Intr_Res)) - panic("Cannot clear a reserved interrupt"); - - regs.IntrStatus &= ~interrupts; - - DPRINTF(EthernetIntr, - "interrupt cleared from intStatus: intr=%x status=%x mask=%x\n", - interrupts, regs.IntrStatus, regs.IntrMask); - - if (!(regs.IntrStatus & regs.IntrMask)) - cpuIntrClear(); -} - -void -Device::devIntrChangeMask(uint32_t newmask) -{ - if (regs.IntrMask == newmask) - return; - - regs.IntrMask = newmask; - - DPRINTF(EthernetIntr, - "interrupt mask changed: intStatus=%x intMask=%x masked=%x\n", - regs.IntrStatus, regs.IntrMask, regs.IntrStatus & regs.IntrMask); - - if (regs.IntrStatus & regs.IntrMask) - cpuIntrPost(curTick); - else - cpuIntrClear(); -} - -void -Base::cpuIntrPost(Tick when) -{ - // If the interrupt you want to post is later than an interrupt - // already scheduled, just let it post in the coming one and don't - // schedule another. - // HOWEVER, must be sure that the scheduled intrTick is in the - // future (this was formerly the source of a bug) - /** - * @todo this warning should be removed and the intrTick code should - * be fixed. - */ - assert(when >= curTick); - assert(intrTick >= curTick || intrTick == 0); - if (!cpuIntrEnable) { - DPRINTF(EthernetIntr, "interrupts not enabled.\n", - intrTick); - return; - } - - if (when > intrTick && intrTick != 0) { - DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n", - intrTick); - return; - } - - intrTick = when; - if (intrTick < curTick) { - debug_break(); - intrTick = curTick; - } - - DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n", - intrTick); - - if (intrEvent) - intrEvent->squash(); - intrEvent = new IntrEvent(this, true); - intrEvent->schedule(intrTick); -} - -void -Base::cpuInterrupt() -{ - assert(intrTick == curTick); - - // Whether or not there's a pending interrupt, we don't care about - // it anymore - intrEvent = 0; - intrTick = 0; - - // Don't send an interrupt if there's already one - if (cpuPendingIntr) { - DPRINTF(EthernetIntr, - "would send an interrupt now, but there's already pending\n"); - } else { - // Send interrupt - cpuPendingIntr = true; - - DPRINTF(EthernetIntr, "posting interrupt\n"); - intrPost(); - } -} - -void -Base::cpuIntrClear() -{ - if (!cpuPendingIntr) - return; - - if (intrEvent) { - intrEvent->squash(); - intrEvent = 0; - } - - intrTick = 0; - - cpuPendingIntr = false; - - DPRINTF(EthernetIntr, "clearing cchip interrupt\n"); - intrClear(); -} - -bool -Base::cpuIntrPending() const -{ return cpuPendingIntr; } - -void -Device::changeConfig(uint32_t newconf) -{ - uint32_t changed = regs.Config ^ newconf; - if (!changed) - return; - - regs.Config = newconf; - - if ((changed & Regs::Config_IntEn)) { - cpuIntrEnable = regs.Config & Regs::Config_IntEn; - if (cpuIntrEnable) { - if (regs.IntrStatus & regs.IntrMask) - cpuIntrPost(curTick); - } else { - cpuIntrClear(); - } - } - - if ((changed & Regs::Config_TxEn)) { - txEnable = regs.Config & Regs::Config_TxEn; - if (txEnable) - txKick(); - } - - if ((changed & Regs::Config_RxEn)) { - rxEnable = regs.Config & Regs::Config_RxEn; - if (rxEnable) - rxKick(); - } -} - -void -Device::command(uint32_t command) -{ - if (command & Regs::Command_Intr) - devIntrPost(Regs::Intr_Soft); - - if (command & Regs::Command_Reset) - reset(); -} - -void -Device::reset() -{ - using namespace Regs; - - memset(®s, 0, sizeof(regs)); - - regs.Config = 0; - if (params()->rx_thread) - regs.Config |= Config_RxThread; - if (params()->tx_thread) - regs.Config |= Config_TxThread; - if (params()->rss) - regs.Config |= Config_RSS; - if (params()->zero_copy) - regs.Config |= Config_ZeroCopy; - if (params()->delay_copy) - regs.Config |= Config_DelayCopy; - if (params()->virtual_addr) - regs.Config |= Config_Vaddr; - - if (params()->delay_copy && params()->zero_copy) - panic("Can't delay copy and zero copy"); - - regs.IntrMask = Intr_Soft | Intr_RxHigh | Intr_RxPacket | Intr_TxLow; - regs.RxMaxCopy = params()->rx_max_copy; - regs.TxMaxCopy = params()->tx_max_copy; - regs.RxMaxIntr = params()->rx_max_intr; - regs.VirtualCount = params()->virtual_count; - regs.RxFifoSize = params()->rx_fifo_size; - regs.TxFifoSize = params()->tx_fifo_size; - regs.RxFifoMark = params()->rx_fifo_threshold; - regs.TxFifoMark = params()->tx_fifo_threshold; - regs.HwAddr = params()->eaddr; - - rxList.clear(); - rxBusy.clear(); - rxActive = -1; - txList.clear(); - - rxState = rxIdle; - txState = txIdle; - - rxFifo.clear(); - rxFifoPtr = rxFifo.end(); - txFifo.clear(); - rxEmpty = false; - rxLow = true; - txFull = false; - - int size = virtualRegs.size(); - virtualRegs.clear(); - virtualRegs.resize(size); - for (int i = 0; i < size; ++i) - virtualRegs[i].rxPacket = rxFifo.end(); -} - -void -Device::rxDmaCopy() -{ - assert(rxState == rxCopy); - rxState = rxCopyDone; - DPRINTF(EthernetDMA, "begin rx dma write paddr=%#x len=%d\n", - rxDmaAddr, rxDmaLen); - physmem->dma_write(rxDmaAddr, (uint8_t *)rxDmaData, rxDmaLen); - DPRINTF(EthernetDMA, "end rx dma write paddr=%#x len=%d\n", - rxDmaAddr, rxDmaLen); - DDUMP(EthernetData, rxDmaData, rxDmaLen); -} - -void -Device::rxDmaDone() -{ - rxDmaCopy(); - - // If the transmit state machine has a pending DMA, let it go first - if (txState == txBeginCopy) - txKick(); - - rxKick(); -} - -void -Device::rxKick() -{ - VirtualReg *vnic = NULL; - - DPRINTF(EthernetSM, "rxKick: rxState=%s (rxFifo.size=%d)\n", - RxStateStrings[rxState], rxFifo.size()); - - if (rxKickTick > curTick) { - DPRINTF(EthernetSM, "rxKick: exiting, can't run till %d\n", - rxKickTick); - return; - } - - next: - if (rxState == rxIdle) - goto exit; - - if (rxActive == -1) { - if (rxState != rxFifoBlock) - panic("no active vnic while in state %s", RxStateStrings[rxState]); - - DPRINTF(EthernetSM, "processing rxState=%s\n", - RxStateStrings[rxState]); - } else { - vnic = &virtualRegs[rxActive]; - DPRINTF(EthernetSM, - "processing rxState=%s for vnic %d (rxunique %d)\n", - RxStateStrings[rxState], rxActive, vnic->rxUnique); - } - - switch (rxState) { - case rxFifoBlock: - if (DTRACE(EthernetSM)) { - PacketFifo::iterator end = rxFifo.end(); - int size = virtualRegs.size(); - for (int i = 0; i < size; ++i) { - VirtualReg *vn = &virtualRegs[i]; - if (vn->rxPacket != end && - !Regs::get_RxDone_Busy(vn->RxDone)) { - DPRINTF(EthernetSM, - "vnic %d (rxunique %d), has outstanding packet %d\n", - i, vn->rxUnique, - rxFifo.countPacketsBefore(vn->rxPacket)); - } - } - } - - if (!rxBusy.empty()) { - rxActive = rxBusy.front(); - rxBusy.pop_front(); - vnic = &virtualRegs[rxActive]; - - if (vnic->rxPacket == rxFifo.end()) - panic("continuing vnic without packet\n"); - - DPRINTF(EthernetSM, - "continue processing for vnic %d (rxunique %d)\n", - rxActive, vnic->rxUnique); - - rxState = rxBeginCopy; - - break; - } - - if (rxFifoPtr == rxFifo.end()) { - DPRINTF(EthernetSM, "receive waiting for data. Nothing to do.\n"); - goto exit; - } - - if (rxList.empty()) - panic("Not idle, but nothing to do!"); - - assert(!rxFifo.empty()); - - rxActive = rxList.front(); - rxList.pop_front(); - vnic = &virtualRegs[rxActive]; - - DPRINTF(EthernetSM, - "processing new packet for vnic %d (rxunique %d)\n", - rxActive, vnic->rxUnique); - - // Grab a new packet from the fifo. - vnic->rxPacket = rxFifoPtr++; - vnic->rxPacketOffset = 0; - vnic->rxPacketBytes = (*vnic->rxPacket)->length; - assert(vnic->rxPacketBytes); - - vnic->rxDoneData = 0; - /* scope for variables */ { - IpPtr ip(*vnic->rxPacket); - if (ip) { - DPRINTF(Ethernet, "ID is %d\n", ip->id()); - vnic->rxDoneData |= Regs::RxDone_IpPacket; - rxIpChecksums++; - if (cksum(ip) != 0) { - DPRINTF(EthernetCksum, "Rx IP Checksum Error\n"); - vnic->rxDoneData |= Regs::RxDone_IpError; - } - TcpPtr tcp(ip); - UdpPtr udp(ip); - if (tcp) { - DPRINTF(Ethernet, - "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", - tcp->sport(), tcp->dport(), tcp->seq(), - tcp->ack()); - vnic->rxDoneData |= Regs::RxDone_TcpPacket; - rxTcpChecksums++; - if (cksum(tcp) != 0) { - DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n"); - vnic->rxDoneData |= Regs::RxDone_TcpError; - } - } else if (udp) { - vnic->rxDoneData |= Regs::RxDone_UdpPacket; - rxUdpChecksums++; - if (cksum(udp) != 0) { - DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n"); - vnic->rxDoneData |= Regs::RxDone_UdpError; - } - } - } - } - rxState = rxBeginCopy; - break; - - case rxBeginCopy: - if (dmaInterface && dmaInterface->busy()) - goto exit; - - rxDmaAddr = plat->pciToDma(Regs::get_RxData_Addr(vnic->RxData)); - rxDmaLen = min<int>(Regs::get_RxData_Len(vnic->RxData), - vnic->rxPacketBytes); - rxDmaData = (*vnic->rxPacket)->data + vnic->rxPacketOffset; - rxState = rxCopy; - - if (rxDmaAddr == 1LL) { - rxState = rxCopyDone; - break; - } - - if (dmaInterface) { - dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen, - curTick, &rxDmaEvent, true); - goto exit; - } - - if (dmaWriteDelay != 0 || dmaWriteFactor != 0) { - Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor; - Tick start = curTick + dmaWriteDelay + factor; - rxDmaEvent.schedule(start); - goto exit; - } - - rxDmaCopy(); - break; - - case rxCopy: - DPRINTF(EthernetSM, "receive machine still copying\n"); - goto exit; - - case rxCopyDone: - vnic->RxDone = vnic->rxDoneData; - vnic->RxDone |= Regs::RxDone_Complete; - - if (vnic->rxPacketBytes == rxDmaLen) { - // Packet is complete. Indicate how many bytes were copied - vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone, rxDmaLen); - - DPRINTF(EthernetSM, - "rxKick: packet complete on vnic %d (rxunique %d)\n", - rxActive, vnic->rxUnique); - rxFifo.remove(vnic->rxPacket); - vnic->rxPacket = rxFifo.end(); - } else { - vnic->rxPacketBytes -= rxDmaLen; - vnic->rxPacketOffset += rxDmaLen; - vnic->RxDone |= Regs::RxDone_More; - vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone, - vnic->rxPacketBytes); - DPRINTF(EthernetSM, - "rxKick: packet not complete on vnic %d (rxunique %d): " - "%d bytes left\n", - rxActive, vnic->rxUnique, vnic->rxPacketBytes); - } - - rxActive = -1; - rxState = rxBusy.empty() && rxList.empty() ? rxIdle : rxFifoBlock; - - if (rxFifo.empty()) { - devIntrPost(Regs::Intr_RxEmpty); - rxEmpty = true; - } - - if (rxFifo.size() < params()->rx_fifo_low_mark) - rxLow = true; - - if (rxFifo.size() > params()->rx_fifo_threshold) - rxLow = false; - - devIntrPost(Regs::Intr_RxDMA); - break; - - default: - panic("Invalid rxState!"); - } - - DPRINTF(EthernetSM, "entering next rxState=%s\n", - RxStateStrings[rxState]); - - goto next; - - exit: - /** - * @todo do we want to schedule a future kick? - */ - DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n", - RxStateStrings[rxState]); -} - -void -Device::txDmaCopy() -{ - assert(txState == txCopy); - txState = txCopyDone; - physmem->dma_read((uint8_t *)txDmaData, txDmaAddr, txDmaLen); - DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n", - txDmaAddr, txDmaLen); - DDUMP(EthernetData, txDmaData, txDmaLen); -} - -void -Device::txDmaDone() -{ - txDmaCopy(); - - // If the receive state machine has a pending DMA, let it go first - if (rxState == rxBeginCopy) - rxKick(); - - txKick(); -} - -void -Device::transmit() -{ - if (txFifo.empty()) { - DPRINTF(Ethernet, "nothing to transmit\n"); - return; - } - - uint32_t interrupts; - PacketPtr packet = txFifo.front(); - if (!interface->sendPacket(packet)) { - DPRINTF(Ethernet, "Packet Transmit: failed txFifo available %d\n", - txFifo.avail()); - goto reschedule; - } - - txFifo.pop(); -#if TRACING_ON - if (DTRACE(Ethernet)) { - IpPtr ip(packet); - if (ip) { - DPRINTF(Ethernet, "ID is %d\n", ip->id()); - TcpPtr tcp(ip); - if (tcp) { - DPRINTF(Ethernet, - "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", - tcp->sport(), tcp->dport(), tcp->seq(), - tcp->ack()); - } - } - } -#endif - - DDUMP(EthernetData, packet->data, packet->length); - txBytes += packet->length; - txPackets++; - - DPRINTF(Ethernet, "Packet Transmit: successful txFifo Available %d\n", - txFifo.avail()); - - interrupts = Regs::Intr_TxPacket; - if (txFifo.size() < regs.TxFifoMark) - interrupts |= Regs::Intr_TxLow; - devIntrPost(interrupts); - - reschedule: - if (!txFifo.empty() && !txEvent.scheduled()) { - DPRINTF(Ethernet, "reschedule transmit\n"); - txEvent.schedule(curTick + retryTime); - } -} - -void -Device::txKick() -{ - VirtualReg *vnic; - DPRINTF(EthernetSM, "txKick: txState=%s (txFifo.size=%d)\n", - TxStateStrings[txState], txFifo.size()); - - if (txKickTick > curTick) { - DPRINTF(EthernetSM, "txKick: exiting, can't run till %d\n", - txKickTick); - return; - } - - next: - if (txState == txIdle) - goto exit; - - assert(!txList.empty()); - vnic = &virtualRegs[txList.front()]; - - switch (txState) { - case txFifoBlock: - assert(Regs::get_TxDone_Busy(vnic->TxDone)); - if (!txPacket) { - // Grab a new packet from the fifo. - txPacket = new PacketData(16384); - txPacketOffset = 0; - } - - if (txFifo.avail() - txPacket->length < - Regs::get_TxData_Len(vnic->TxData)) { - DPRINTF(EthernetSM, "transmit fifo full. Nothing to do.\n"); - goto exit; - } - - txState = txBeginCopy; - break; - - case txBeginCopy: - if (dmaInterface && dmaInterface->busy()) - goto exit; - - txDmaAddr = plat->pciToDma(Regs::get_TxData_Addr(vnic->TxData)); - txDmaLen = Regs::get_TxData_Len(vnic->TxData); - txDmaData = txPacket->data + txPacketOffset; - txState = txCopy; - - if (dmaInterface) { - dmaInterface->doDMA(Read, txDmaAddr, txDmaLen, - curTick, &txDmaEvent, true); - goto exit; - } - - if (dmaReadDelay != 0 || dmaReadFactor != 0) { - Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor; - Tick start = curTick + dmaReadDelay + factor; - txDmaEvent.schedule(start); - goto exit; - } - - txDmaCopy(); - break; - - case txCopy: - DPRINTF(EthernetSM, "transmit machine still copying\n"); - goto exit; - - case txCopyDone: - vnic->TxDone = txDmaLen | Regs::TxDone_Complete; - txPacket->length += txDmaLen; - if ((vnic->TxData & Regs::TxData_More)) { - txPacketOffset += txDmaLen; - txState = txIdle; - devIntrPost(Regs::Intr_TxDMA); - break; - } - - assert(txPacket->length <= txFifo.avail()); - if ((vnic->TxData & Regs::TxData_Checksum)) { - IpPtr ip(txPacket); - if (ip) { - TcpPtr tcp(ip); - if (tcp) { - tcp->sum(0); - tcp->sum(cksum(tcp)); - txTcpChecksums++; - } - - UdpPtr udp(ip); - if (udp) { - udp->sum(0); - udp->sum(cksum(udp)); - txUdpChecksums++; - } - - ip->sum(0); - ip->sum(cksum(ip)); - txIpChecksums++; - } - } - - txFifo.push(txPacket); - if (txFifo.avail() < regs.TxMaxCopy) { - devIntrPost(Regs::Intr_TxFull); - txFull = true; - } - txPacket = 0; - transmit(); - txList.pop_front(); - txState = txList.empty() ? txIdle : txFifoBlock; - devIntrPost(Regs::Intr_TxDMA); - break; - - default: - panic("Invalid txState!"); - } - - DPRINTF(EthernetSM, "entering next txState=%s\n", - TxStateStrings[txState]); - - goto next; - - exit: - /** - * @todo do we want to schedule a future kick? - */ - DPRINTF(EthernetSM, "tx state machine exited txState=%s\n", - TxStateStrings[txState]); -} - -void -Device::transferDone() -{ - if (txFifo.empty()) { - DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n"); - return; - } - - DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n"); - - if (txEvent.scheduled()) - txEvent.reschedule(curTick + cycles(1)); - else - txEvent.schedule(curTick + cycles(1)); -} - -bool -Device::rxFilter(const PacketPtr &packet) -{ - if (!Regs::get_Config_Filter(regs.Config)) - return false; - - panic("receive filter not implemented\n"); - bool drop = true; - -#if 0 - string type; - - EthHdr *eth = packet->eth(); - if (eth->unicast()) { - // If we're accepting all unicast addresses - if (acceptUnicast) - drop = false; - - // If we make a perfect match - if (acceptPerfect && params->eaddr == eth.dst()) - drop = false; - - if (acceptArp && eth->type() == ETH_TYPE_ARP) - drop = false; - - } else if (eth->broadcast()) { - // if we're accepting broadcasts - if (acceptBroadcast) - drop = false; - - } else if (eth->multicast()) { - // if we're accepting all multicasts - if (acceptMulticast) - drop = false; - - } - - if (drop) { - DPRINTF(Ethernet, "rxFilter drop\n"); - DDUMP(EthernetData, packet->data, packet->length); - } -#endif - return drop; -} - -bool -Device::recvPacket(PacketPtr packet) -{ - rxBytes += packet->length; - rxPackets++; - - DPRINTF(Ethernet, "Receiving packet from wire, rxFifo Available is %d\n", - rxFifo.avail()); - - if (!rxEnable) { - DPRINTF(Ethernet, "receive disabled...packet dropped\n"); - return true; - } - - if (rxFilter(packet)) { - DPRINTF(Ethernet, "packet filtered...dropped\n"); - return true; - } - - if (rxFifo.size() >= regs.RxFifoMark) - devIntrPost(Regs::Intr_RxHigh); - - if (!rxFifo.push(packet)) { - DPRINTF(Ethernet, - "packet will not fit in receive buffer...packet dropped\n"); - return false; - } - - // If we were at the last element, back up one ot go to the new - // last element of the list. - if (rxFifoPtr == rxFifo.end()) - --rxFifoPtr; - - devIntrPost(Regs::Intr_RxPacket); - rxKick(); - return true; -} - -//===================================================================== -// -// -void -Base::serialize(ostream &os) -{ - // Serialize the PciDev base class - PciDev::serialize(os); - - SERIALIZE_SCALAR(rxEnable); - SERIALIZE_SCALAR(txEnable); - SERIALIZE_SCALAR(cpuIntrEnable); - - /* - * Keep track of pending interrupt status. - */ - SERIALIZE_SCALAR(intrTick); - SERIALIZE_SCALAR(cpuPendingIntr); - Tick intrEventTick = 0; - if (intrEvent) - intrEventTick = intrEvent->when(); - SERIALIZE_SCALAR(intrEventTick); -} - -void -Base::unserialize(Checkpoint *cp, const std::string §ion) -{ - // Unserialize the PciDev base class - PciDev::unserialize(cp, section); - - UNSERIALIZE_SCALAR(rxEnable); - UNSERIALIZE_SCALAR(txEnable); - UNSERIALIZE_SCALAR(cpuIntrEnable); - - /* - * Keep track of pending interrupt status. - */ - UNSERIALIZE_SCALAR(intrTick); - UNSERIALIZE_SCALAR(cpuPendingIntr); - Tick intrEventTick; - UNSERIALIZE_SCALAR(intrEventTick); - if (intrEventTick) { - intrEvent = new IntrEvent(this, true); - intrEvent->schedule(intrEventTick); - } -} - -void -Device::serialize(ostream &os) -{ - int count; - - // Serialize the PciDev base class - Base::serialize(os); - - if (rxState == rxCopy) - panic("can't serialize with an in flight dma request rxState=%s", - RxStateStrings[rxState]); - - if (txState == txCopy) - panic("can't serialize with an in flight dma request txState=%s", - TxStateStrings[txState]); - - /* - * Serialize the device registers - */ - SERIALIZE_SCALAR(regs.Config); - SERIALIZE_SCALAR(regs.IntrStatus); - SERIALIZE_SCALAR(regs.IntrMask); - SERIALIZE_SCALAR(regs.RxMaxCopy); - SERIALIZE_SCALAR(regs.TxMaxCopy); - SERIALIZE_SCALAR(regs.RxMaxIntr); - SERIALIZE_SCALAR(regs.VirtualCount); - SERIALIZE_SCALAR(regs.RxData); - SERIALIZE_SCALAR(regs.RxDone); - SERIALIZE_SCALAR(regs.TxData); - SERIALIZE_SCALAR(regs.TxDone); - - /* - * Serialize the virtual nic state - */ - int virtualRegsSize = virtualRegs.size(); - SERIALIZE_SCALAR(virtualRegsSize); - for (int i = 0; i < virtualRegsSize; ++i) { - VirtualReg *vnic = &virtualRegs[i]; - - string reg = csprintf("vnic%d", i); - paramOut(os, reg + ".RxData", vnic->RxData); - paramOut(os, reg + ".RxDone", vnic->RxDone); - paramOut(os, reg + ".TxData", vnic->TxData); - paramOut(os, reg + ".TxDone", vnic->TxDone); - - bool rxPacketExists = vnic->rxPacket != rxFifo.end(); - paramOut(os, reg + ".rxPacketExists", rxPacketExists); - if (rxPacketExists) { - int rxPacket = 0; - PacketFifo::iterator i = rxFifo.begin(); - while (i != vnic->rxPacket) { - assert(i != rxFifo.end()); - ++i; - ++rxPacket; - } - - paramOut(os, reg + ".rxPacket", rxPacket); - paramOut(os, reg + ".rxPacketOffset", vnic->rxPacketOffset); - paramOut(os, reg + ".rxPacketBytes", vnic->rxPacketBytes); - } - paramOut(os, reg + ".rxDoneData", vnic->rxDoneData); - } - - int rxFifoPtr = rxFifo.countPacketsBefore(this->rxFifoPtr); - SERIALIZE_SCALAR(rxFifoPtr); - - SERIALIZE_SCALAR(rxActive); - - VirtualList::iterator i, end; - for (count = 0, i = rxList.begin(), end = rxList.end(); i != end; ++i) - paramOut(os, csprintf("rxList%d", count++), *i); - int rxListSize = count; - SERIALIZE_SCALAR(rxListSize); - - for (count = 0, i = rxBusy.begin(), end = rxBusy.end(); i != end; ++i) - paramOut(os, csprintf("rxBusy%d", count++), *i); - int rxBusySize = count; - SERIALIZE_SCALAR(rxBusySize); - - for (count = 0, i = txList.begin(), end = txList.end(); i != end; ++i) - paramOut(os, csprintf("txList%d", count++), *i); - int txListSize = count; - SERIALIZE_SCALAR(txListSize); - - /* - * Serialize rx state machine - */ - int rxState = this->rxState; - SERIALIZE_SCALAR(rxState); - SERIALIZE_SCALAR(rxEmpty); - SERIALIZE_SCALAR(rxLow); - rxFifo.serialize("rxFifo", os); - - /* - * Serialize tx state machine - */ - int txState = this->txState; - SERIALIZE_SCALAR(txState); - SERIALIZE_SCALAR(txFull); - txFifo.serialize("txFifo", os); - bool txPacketExists = txPacket; - SERIALIZE_SCALAR(txPacketExists); - if (txPacketExists) { - txPacket->serialize("txPacket", os); - SERIALIZE_SCALAR(txPacketOffset); - SERIALIZE_SCALAR(txPacketBytes); - } - - /* - * If there's a pending transmit, store the time so we can - * reschedule it later - */ - Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0; - SERIALIZE_SCALAR(transmitTick); -} - -void -Device::unserialize(Checkpoint *cp, const std::string §ion) -{ - // Unserialize the PciDev base class - Base::unserialize(cp, section); - - /* - * Unserialize the device registers - */ - UNSERIALIZE_SCALAR(regs.Config); - UNSERIALIZE_SCALAR(regs.IntrStatus); - UNSERIALIZE_SCALAR(regs.IntrMask); - UNSERIALIZE_SCALAR(regs.RxMaxCopy); - UNSERIALIZE_SCALAR(regs.TxMaxCopy); - UNSERIALIZE_SCALAR(regs.RxMaxIntr); - UNSERIALIZE_SCALAR(regs.VirtualCount); - UNSERIALIZE_SCALAR(regs.RxData); - UNSERIALIZE_SCALAR(regs.RxDone); - UNSERIALIZE_SCALAR(regs.TxData); - UNSERIALIZE_SCALAR(regs.TxDone); - - UNSERIALIZE_SCALAR(rxActive); - - int rxListSize; - UNSERIALIZE_SCALAR(rxListSize); - rxList.clear(); - for (int i = 0; i < rxListSize; ++i) { - int value; - paramIn(cp, section, csprintf("rxList%d", i), value); - rxList.push_back(value); - } - - int rxBusySize; - UNSERIALIZE_SCALAR(rxBusySize); - rxBusy.clear(); - for (int i = 0; i < rxBusySize; ++i) { - int value; - paramIn(cp, section, csprintf("rxBusy%d", i), value); - rxBusy.push_back(value); - } - - int txListSize; - UNSERIALIZE_SCALAR(txListSize); - txList.clear(); - for (int i = 0; i < txListSize; ++i) { - int value; - paramIn(cp, section, csprintf("txList%d", i), value); - txList.push_back(value); - } - - /* - * Unserialize rx state machine - */ - int rxState; - UNSERIALIZE_SCALAR(rxState); - UNSERIALIZE_SCALAR(rxEmpty); - UNSERIALIZE_SCALAR(rxLow); - this->rxState = (RxState) rxState; - rxFifo.unserialize("rxFifo", cp, section); - - int rxFifoPtr; - UNSERIALIZE_SCALAR(rxFifoPtr); - this->rxFifoPtr = rxFifo.begin(); - for (int i = 0; i < rxFifoPtr; ++i) - ++this->rxFifoPtr; - - /* - * Unserialize tx state machine - */ - int txState; - UNSERIALIZE_SCALAR(txState); - UNSERIALIZE_SCALAR(txFull); - this->txState = (TxState) txState; - txFifo.unserialize("txFifo", cp, section); - bool txPacketExists; - UNSERIALIZE_SCALAR(txPacketExists); - txPacket = 0; - if (txPacketExists) { - txPacket = new PacketData(16384); - txPacket->unserialize("txPacket", cp, section); - UNSERIALIZE_SCALAR(txPacketOffset); - UNSERIALIZE_SCALAR(txPacketBytes); - } - - /* - * unserialize the virtual nic registers/state - * - * this must be done after the unserialization of the rxFifo - * because the packet iterators depend on the fifo being populated - */ - int virtualRegsSize; - UNSERIALIZE_SCALAR(virtualRegsSize); - virtualRegs.clear(); - virtualRegs.resize(virtualRegsSize); - for (int i = 0; i < virtualRegsSize; ++i) { - VirtualReg *vnic = &virtualRegs[i]; - string reg = csprintf("vnic%d", i); - - paramIn(cp, section, reg + ".RxData", vnic->RxData); - paramIn(cp, section, reg + ".RxDone", vnic->RxDone); - paramIn(cp, section, reg + ".TxData", vnic->TxData); - paramIn(cp, section, reg + ".TxDone", vnic->TxDone); - - vnic->rxUnique = rxUnique++; - vnic->txUnique = txUnique++; - - bool rxPacketExists; - paramIn(cp, section, reg + ".rxPacketExists", rxPacketExists); - if (rxPacketExists) { - int rxPacket; - paramIn(cp, section, reg + ".rxPacket", rxPacket); - vnic->rxPacket = rxFifo.begin(); - while (rxPacket--) - ++vnic->rxPacket; - - paramIn(cp, section, reg + ".rxPacketOffset", - vnic->rxPacketOffset); - paramIn(cp, section, reg + ".rxPacketBytes", vnic->rxPacketBytes); - } else { - vnic->rxPacket = rxFifo.end(); - } - paramIn(cp, section, reg + ".rxDoneData", vnic->rxDoneData); - } - - /* - * If there's a pending transmit, reschedule it now - */ - Tick transmitTick; - UNSERIALIZE_SCALAR(transmitTick); - if (transmitTick) - txEvent.schedule(curTick + transmitTick); - - /* - * re-add addrRanges to bus bridges - */ - if (pioInterface) - pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0])); -} - -Tick -Device::cacheAccess(MemReqPtr &req) -{ - Addr daddr; - int bar; - if (!getBAR(req->paddr, daddr, bar)) - panic("address does not map to a BAR pa=%#x va=%#x size=%d", - req->paddr, req->vaddr, req->size); - - DPRINTF(EthernetPIO, "timing %s to paddr=%#x bar=%d daddr=%#x\n", - req->cmd.toString(), req->paddr, bar, daddr); - - return curTick + pioLatency; -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(Interface) - - SimObjectParam<EtherInt *> peer; - SimObjectParam<Device *> device; - -END_DECLARE_SIM_OBJECT_PARAMS(Interface) - -BEGIN_INIT_SIM_OBJECT_PARAMS(Interface) - - INIT_PARAM_DFLT(peer, "peer interface", NULL), - INIT_PARAM(device, "Ethernet device of this interface") - -END_INIT_SIM_OBJECT_PARAMS(Interface) - -CREATE_SIM_OBJECT(Interface) -{ - Interface *dev_int = new Interface(getInstanceName(), device); - - EtherInt *p = (EtherInt *)peer; - if (p) { - dev_int->setPeer(p); - p->setPeer(dev_int); - } - - return dev_int; -} - -REGISTER_SIM_OBJECT("SinicInt", Interface) - - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(Device) - - Param<Tick> clock; - - Param<Addr> addr; - SimObjectParam<MemoryController *> mmu; - SimObjectParam<PhysicalMemory *> physmem; - SimObjectParam<PciConfigAll *> configspace; - SimObjectParam<PciConfigData *> configdata; - SimObjectParam<Platform *> platform; - Param<uint32_t> pci_bus; - Param<uint32_t> pci_dev; - Param<uint32_t> pci_func; - - SimObjectParam<HierParams *> hier; - SimObjectParam<Bus*> pio_bus; - SimObjectParam<Bus*> dma_bus; - SimObjectParam<Bus*> payload_bus; - Param<Tick> dma_read_delay; - Param<Tick> dma_read_factor; - Param<Tick> dma_write_delay; - Param<Tick> dma_write_factor; - Param<bool> dma_no_allocate; - Param<Tick> pio_latency; - Param<Tick> intr_delay; - - Param<Tick> rx_delay; - Param<Tick> tx_delay; - Param<uint32_t> rx_max_copy; - Param<uint32_t> tx_max_copy; - Param<uint32_t> rx_max_intr; - Param<uint32_t> rx_fifo_size; - Param<uint32_t> tx_fifo_size; - Param<uint32_t> rx_fifo_threshold; - Param<uint32_t> rx_fifo_low_mark; - Param<uint32_t> tx_fifo_high_mark; - Param<uint32_t> tx_fifo_threshold; - - Param<bool> rx_filter; - Param<string> hardware_address; - Param<bool> rx_thread; - Param<bool> tx_thread; - Param<bool> rss; - Param<uint32_t> virtual_count; - Param<bool> zero_copy; - Param<bool> delay_copy; - Param<bool> virtual_addr; - -END_DECLARE_SIM_OBJECT_PARAMS(Device) - -BEGIN_INIT_SIM_OBJECT_PARAMS(Device) - - INIT_PARAM(clock, "State machine cycle time"), - - INIT_PARAM(addr, "Device Address"), - INIT_PARAM(mmu, "Memory Controller"), - INIT_PARAM(physmem, "Physical Memory"), - INIT_PARAM(configspace, "PCI Configspace"), - INIT_PARAM(configdata, "PCI Config data"), - INIT_PARAM(platform, "Platform"), - INIT_PARAM(pci_bus, "PCI bus"), - INIT_PARAM(pci_dev, "PCI device number"), - INIT_PARAM(pci_func, "PCI function code"), - - INIT_PARAM(hier, "Hierarchy global variables"), - INIT_PARAM(pio_bus, ""), - INIT_PARAM(dma_bus, ""), - INIT_PARAM(payload_bus, "The IO Bus to attach to for payload"), - INIT_PARAM(dma_read_delay, "fixed delay for dma reads"), - INIT_PARAM(dma_read_factor, "multiplier for dma reads"), - INIT_PARAM(dma_write_delay, "fixed delay for dma writes"), - INIT_PARAM(dma_write_factor, "multiplier for dma writes"), - INIT_PARAM(dma_no_allocate, "Should we allocat on read in cache"), - INIT_PARAM(pio_latency, "Programmed IO latency in bus cycles"), - INIT_PARAM(intr_delay, "Interrupt Delay"), - - INIT_PARAM(rx_delay, "Receive Delay"), - INIT_PARAM(tx_delay, "Transmit Delay"), - INIT_PARAM(rx_max_copy, "rx max copy"), - INIT_PARAM(tx_max_copy, "rx max copy"), - INIT_PARAM(rx_max_intr, "rx max intr"), - INIT_PARAM(rx_fifo_size, "max size in bytes of rxFifo"), - INIT_PARAM(tx_fifo_size, "max size in bytes of txFifo"), - INIT_PARAM(rx_fifo_threshold, "max size in bytes of rxFifo"), - INIT_PARAM(rx_fifo_low_mark, "max size in bytes of rxFifo"), - INIT_PARAM(tx_fifo_high_mark, "max size in bytes of txFifo"), - INIT_PARAM(tx_fifo_threshold, "max size in bytes of txFifo"), - - INIT_PARAM(rx_filter, "Enable Receive Filter"), - INIT_PARAM(hardware_address, "Ethernet Hardware Address"), - INIT_PARAM(rx_thread, ""), - INIT_PARAM(tx_thread, ""), - INIT_PARAM(rss, ""), - INIT_PARAM(virtual_count, ""), - INIT_PARAM(zero_copy, ""), - INIT_PARAM(delay_copy, ""), - INIT_PARAM(virtual_addr, "") - -END_INIT_SIM_OBJECT_PARAMS(Device) - - -CREATE_SIM_OBJECT(Device) -{ - Device::Params *params = new Device::Params; - - params->name = getInstanceName(); - - params->clock = clock; - - params->mmu = mmu; - params->physmem = physmem; - params->configSpace = configspace; - params->configData = configdata; - params->plat = platform; - params->busNum = pci_bus; - params->deviceNum = pci_dev; - params->functionNum = pci_func; - - params->hier = hier; - params->pio_bus = pio_bus; - params->header_bus = dma_bus; - params->payload_bus = payload_bus; - params->dma_read_delay = dma_read_delay; - params->dma_read_factor = dma_read_factor; - params->dma_write_delay = dma_write_delay; - params->dma_write_factor = dma_write_factor; - params->dma_no_allocate = dma_no_allocate; - params->pio_latency = pio_latency; - params->intr_delay = intr_delay; - - params->tx_delay = tx_delay; - params->rx_delay = rx_delay; - params->rx_max_copy = rx_max_copy; - params->tx_max_copy = tx_max_copy; - params->rx_max_intr = rx_max_intr; - params->rx_fifo_size = rx_fifo_size; - params->tx_fifo_size = tx_fifo_size; - params->rx_fifo_threshold = rx_fifo_threshold; - params->rx_fifo_low_mark = rx_fifo_low_mark; - params->tx_fifo_high_mark = tx_fifo_high_mark; - params->tx_fifo_threshold = tx_fifo_threshold; - - params->rx_filter = rx_filter; - params->eaddr = hardware_address; - params->rx_thread = rx_thread; - params->tx_thread = tx_thread; - params->rss = rss; - params->virtual_count = virtual_count; - params->zero_copy = zero_copy; - params->delay_copy = delay_copy; - params->virtual_addr = virtual_addr; - - return new Device(params); -} - -REGISTER_SIM_OBJECT("Sinic", Device) - -/* namespace Sinic */ } diff --git a/dev/sinic.hh b/dev/sinic.hh deleted file mode 100644 index 892b3ab69..000000000 --- a/dev/sinic.hh +++ /dev/null @@ -1,401 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __DEV_SINIC_HH__ -#define __DEV_SINIC_HH__ - -#include "base/inet.hh" -#include "base/statistics.hh" -#include "dev/etherint.hh" -#include "dev/etherpkt.hh" -#include "dev/io_device.hh" -#include "dev/pcidev.hh" -#include "dev/pktfifo.hh" -#include "dev/sinicreg.hh" -#include "mem/bus/bus.hh" -#include "sim/eventq.hh" - -namespace Sinic { - -class Interface; -class Base : public PciDev -{ - protected: - bool rxEnable; - bool txEnable; - Tick clock; - inline Tick cycles(int numCycles) const { return numCycles * clock; } - - protected: - Tick intrDelay; - Tick intrTick; - bool cpuIntrEnable; - bool cpuPendingIntr; - void cpuIntrPost(Tick when); - void cpuInterrupt(); - void cpuIntrClear(); - - typedef EventWrapper<Base, &Base::cpuInterrupt> IntrEvent; - friend void IntrEvent::process(); - IntrEvent *intrEvent; - Interface *interface; - - bool cpuIntrPending() const; - void cpuIntrAck() { cpuIntrClear(); } - -/** - * Serialization stuff - */ - public: - virtual void serialize(std::ostream &os); - virtual void unserialize(Checkpoint *cp, const std::string §ion); - -/** - * Construction/Destruction/Parameters - */ - public: - struct Params : public PciDev::Params - { - Tick clock; - Tick intr_delay; - }; - - Base(Params *p); -}; - -class Device : public Base -{ - protected: - Platform *plat; - PhysicalMemory *physmem; - - protected: - /** Receive State Machine States */ - enum RxState { - rxIdle, - rxFifoBlock, - rxBeginCopy, - rxCopy, - rxCopyDone - }; - - /** Transmit State Machine states */ - enum TxState { - txIdle, - txFifoBlock, - txBeginCopy, - txCopy, - txCopyDone - }; - - /** device register file */ - struct { - uint32_t Config; // 0x00 - uint32_t Command; // 0x04 - uint32_t IntrStatus; // 0x08 - uint32_t IntrMask; // 0x0c - uint32_t RxMaxCopy; // 0x10 - uint32_t TxMaxCopy; // 0x14 - uint32_t RxMaxIntr; // 0x18 - uint32_t VirtualCount; // 0x1c - uint32_t RxFifoSize; // 0x20 - uint32_t TxFifoSize; // 0x24 - uint32_t RxFifoMark; // 0x28 - uint32_t TxFifoMark; // 0x2c - uint64_t RxData; // 0x30 - uint64_t RxDone; // 0x38 - uint64_t RxWait; // 0x40 - uint64_t TxData; // 0x48 - uint64_t TxDone; // 0x50 - uint64_t TxWait; // 0x58 - uint64_t HwAddr; // 0x60 - } regs; - - struct VirtualReg { - uint64_t RxData; - uint64_t RxDone; - uint64_t TxData; - uint64_t TxDone; - - PacketFifo::iterator rxPacket; - int rxPacketOffset; - int rxPacketBytes; - uint64_t rxDoneData; - - Counter rxUnique; - Counter txUnique; - - VirtualReg() - : RxData(0), RxDone(0), TxData(0), TxDone(0), - rxPacketOffset(0), rxPacketBytes(0), rxDoneData(0) - { } - }; - typedef std::vector<VirtualReg> VirtualRegs; - typedef std::list<int> VirtualList; - Counter rxUnique; - Counter txUnique; - VirtualRegs virtualRegs; - VirtualList rxList; - VirtualList rxBusy; - int rxActive; - VirtualList txList; - - uint8_t ®Data8(Addr daddr) { return *((uint8_t *)®s + daddr); } - uint32_t ®Data32(Addr daddr) { return *(uint32_t *)®Data8(daddr); } - uint64_t ®Data64(Addr daddr) { return *(uint64_t *)®Data8(daddr); } - - private: - Addr addr; - static const Addr size = Regs::Size; - - protected: - RxState rxState; - PacketFifo rxFifo; - PacketFifo::iterator rxFifoPtr; - bool rxEmpty; - bool rxLow; - Addr rxDmaAddr; - uint8_t *rxDmaData; - int rxDmaLen; - - TxState txState; - PacketFifo txFifo; - bool txFull; - PacketPtr txPacket; - int txPacketOffset; - int txPacketBytes; - Addr txDmaAddr; - uint8_t *txDmaData; - int txDmaLen; - - protected: - void reset(); - - void rxKick(); - Tick rxKickTick; - typedef EventWrapper<Device, &Device::rxKick> RxKickEvent; - friend void RxKickEvent::process(); - - void txKick(); - Tick txKickTick; - typedef EventWrapper<Device, &Device::txKick> TxKickEvent; - friend void TxKickEvent::process(); - - /** - * Retransmit event - */ - void transmit(); - void txEventTransmit() - { - transmit(); - if (txState == txFifoBlock) - txKick(); - } - typedef EventWrapper<Device, &Device::txEventTransmit> TxEvent; - friend void TxEvent::process(); - TxEvent txEvent; - - void txDump() const; - void rxDump() const; - - /** - * receive address filter - */ - bool rxFilter(const PacketPtr &packet); - -/** - * device configuration - */ - void changeConfig(uint32_t newconfig); - void command(uint32_t command); - -/** - * device ethernet interface - */ - public: - bool recvPacket(PacketPtr packet); - void transferDone(); - void setInterface(Interface *i) { assert(!interface); interface = i; } - -/** - * DMA parameters - */ - protected: - void rxDmaCopy(); - void rxDmaDone(); - friend class EventWrapper<Device, &Device::rxDmaDone>; - EventWrapper<Device, &Device::rxDmaDone> rxDmaEvent; - - void txDmaCopy(); - void txDmaDone(); - friend class EventWrapper<Device, &Device::txDmaDone>; - EventWrapper<Device, &Device::txDmaDone> txDmaEvent; - - Tick dmaReadDelay; - Tick dmaReadFactor; - Tick dmaWriteDelay; - Tick dmaWriteFactor; - -/** - * Interrupt management - */ - protected: - void devIntrPost(uint32_t interrupts); - void devIntrClear(uint32_t interrupts = Regs::Intr_All); - void devIntrChangeMask(uint32_t newmask); - -/** - * PCI Configuration interface - */ - public: - virtual void writeConfig(int offset, int size, const uint8_t *data); - -/** - * Memory Interface - */ - public: - virtual Fault read(MemReqPtr &req, uint8_t *data); - virtual Fault write(MemReqPtr &req, const uint8_t *data); - - void prepareIO(int cpu, int index); - void prepareRead(int cpu, int index); - void prepareWrite(int cpu, int index); - Fault iprRead(Addr daddr, int cpu, uint64_t &result); - Fault readBar0(MemReqPtr &req, Addr daddr, uint8_t *data); - Fault writeBar0(MemReqPtr &req, Addr daddr, const uint8_t *data); - Tick cacheAccess(MemReqPtr &req); - -/** - * Statistics - */ - private: - Stats::Scalar<> rxBytes; - Stats::Formula rxBandwidth; - Stats::Scalar<> rxPackets; - Stats::Formula rxPacketRate; - Stats::Scalar<> rxIpPackets; - Stats::Scalar<> rxTcpPackets; - Stats::Scalar<> rxUdpPackets; - Stats::Scalar<> rxIpChecksums; - Stats::Scalar<> rxTcpChecksums; - Stats::Scalar<> rxUdpChecksums; - - Stats::Scalar<> txBytes; - Stats::Formula txBandwidth; - Stats::Formula totBandwidth; - Stats::Formula totPackets; - Stats::Formula totBytes; - Stats::Formula totPacketRate; - Stats::Scalar<> txPackets; - Stats::Formula txPacketRate; - Stats::Scalar<> txIpPackets; - Stats::Scalar<> txTcpPackets; - Stats::Scalar<> txUdpPackets; - Stats::Scalar<> txIpChecksums; - Stats::Scalar<> txTcpChecksums; - Stats::Scalar<> txUdpChecksums; - - public: - virtual void regStats(); - -/** - * Serialization stuff - */ - public: - virtual void serialize(std::ostream &os); - virtual void unserialize(Checkpoint *cp, const std::string §ion); - -/** - * Construction/Destruction/Parameters - */ - public: - struct Params : public Base::Params - { - IntrControl *i; - PhysicalMemory *pmem; - Tick tx_delay; - Tick rx_delay; - HierParams *hier; - Bus *pio_bus; - Bus *header_bus; - Bus *payload_bus; - Tick pio_latency; - PhysicalMemory *physmem; - IntrControl *intctrl; - bool rx_filter; - Net::EthAddr eaddr; - uint32_t rx_max_copy; - uint32_t tx_max_copy; - uint32_t rx_max_intr; - uint32_t rx_fifo_size; - uint32_t tx_fifo_size; - uint32_t rx_fifo_threshold; - uint32_t rx_fifo_low_mark; - uint32_t tx_fifo_high_mark; - uint32_t tx_fifo_threshold; - Tick dma_read_delay; - Tick dma_read_factor; - Tick dma_write_delay; - Tick dma_write_factor; - bool dma_no_allocate; - bool rx_thread; - bool tx_thread; - bool rss; - uint32_t virtual_count; - bool zero_copy; - bool delay_copy; - bool virtual_addr; - }; - - protected: - const Params *params() const { return (const Params *)_params; } - - public: - Device(Params *params); - ~Device(); -}; - -/* - * Ethernet Interface for an Ethernet Device - */ -class Interface : public EtherInt -{ - private: - Device *dev; - - public: - Interface(const std::string &name, Device *d) - : EtherInt(name), dev(d) { dev->setInterface(this); } - - virtual bool recvPacket(PacketPtr pkt) { return dev->recvPacket(pkt); } - virtual void sendDone() { dev->transferDone(); } -}; - -/* namespace Sinic */ } - -#endif // __DEV_SINIC_HH__ diff --git a/dev/tsunami.cc b/dev/tsunami.cc deleted file mode 100644 index 58fc7434e..000000000 --- a/dev/tsunami.cc +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** @file - * Implementation of Tsunami platform. - */ - -#include <deque> -#include <string> -#include <vector> - -#include "cpu/intr_control.hh" -#include "dev/simconsole.hh" -#include "dev/ide_ctrl.hh" -#include "dev/tsunami_cchip.hh" -#include "dev/tsunami_pchip.hh" -#include "dev/tsunami_io.hh" -#include "dev/tsunami.hh" -#include "dev/pciconfigall.hh" -#include "sim/builder.hh" -#include "sim/system.hh" - -using namespace std; -//Should this be AlphaISA? -using namespace TheISA; - -Tsunami::Tsunami(const string &name, System *s, IntrControl *ic, - PciConfigAll *pci) - : Platform(name, ic, pci), system(s) -{ - // set the back pointer from the system to myself - system->platform = this; - - for (int i = 0; i < Tsunami::Max_CPUs; i++) - intr_sum_type[i] = 0; -} - -Tick -Tsunami::intrFrequency() -{ - return io->frequency(); -} - -void -Tsunami::postConsoleInt() -{ - io->postPIC(0x10); -} - -void -Tsunami::clearConsoleInt() -{ - io->clearPIC(0x10); -} - -void -Tsunami::postPciInt(int line) -{ - cchip->postDRIR(line); -} - -void -Tsunami::clearPciInt(int line) -{ - cchip->clearDRIR(line); -} - -Addr -Tsunami::pciToDma(Addr pciAddr) const -{ - return pchip->translatePciToDma(pciAddr); -} - -void -Tsunami::serialize(std::ostream &os) -{ - SERIALIZE_ARRAY(intr_sum_type, Tsunami::Max_CPUs); -} - -void -Tsunami::unserialize(Checkpoint *cp, const std::string §ion) -{ - UNSERIALIZE_ARRAY(intr_sum_type, Tsunami::Max_CPUs); -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(Tsunami) - - SimObjectParam<System *> system; - SimObjectParam<IntrControl *> intrctrl; - SimObjectParam<PciConfigAll *> pciconfig; - -END_DECLARE_SIM_OBJECT_PARAMS(Tsunami) - -BEGIN_INIT_SIM_OBJECT_PARAMS(Tsunami) - - INIT_PARAM(system, "system"), - INIT_PARAM(intrctrl, "interrupt controller"), - INIT_PARAM(pciconfig, "PCI configuration") - -END_INIT_SIM_OBJECT_PARAMS(Tsunami) - -CREATE_SIM_OBJECT(Tsunami) -{ - return new Tsunami(getInstanceName(), system, intrctrl, pciconfig); -} - -REGISTER_SIM_OBJECT("Tsunami", Tsunami) diff --git a/dev/tsunami.hh b/dev/tsunami.hh deleted file mode 100644 index 7fd91d5b2..000000000 --- a/dev/tsunami.hh +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * Declaration of top level class for the Tsunami chipset. This class just - * retains pointers to all its children so the children can communicate. - */ - -#ifndef __DEV_TSUNAMI_HH__ -#define __DEV_TSUNAMI_HH__ - -#include "dev/platform.hh" - -class IdeController; -class TlaserClock; -class NSGigE; -class TsunamiCChip; -class TsunamiPChip; -class TsunamiIO; -class PciConfigAll; -class System; - -/** - * Top level class for Tsunami Chipset emulation. - * This structure just contains pointers to all the - * children so the children can commnicate to do the - * read work - */ - -class Tsunami : public Platform -{ - public: - /** Max number of CPUs in a Tsunami */ - static const int Max_CPUs = 64; - - /** Pointer to the system */ - System *system; - - /** Pointer to the TsunamiIO device which has the RTC */ - TsunamiIO *io; - - /** Pointer to the Tsunami CChip. - * The chip contains some configuration information and - * all the interrupt mask and status registers - */ - TsunamiCChip *cchip; - - /** Pointer to the Tsunami PChip. - * The pchip is the interface to the PCI bus, in our case - * it does not have to do much. - */ - TsunamiPChip *pchip; - - int intr_sum_type[Tsunami::Max_CPUs]; - int ipi_pending[Tsunami::Max_CPUs]; - - public: - /** - * Constructor for the Tsunami Class. - * @param name name of the object - * @param intrctrl pointer to the interrupt controller - */ - Tsunami(const std::string &name, System *s, IntrControl *intctrl, - PciConfigAll *pci); - - /** - * Return the interrupting frequency to AlphaAccess - * @return frequency of RTC interrupts - */ - virtual Tick intrFrequency(); - - /** - * Cause the cpu to post a serial interrupt to the CPU. - */ - virtual void postConsoleInt(); - - /** - * Clear a posted CPU interrupt (id=55) - */ - virtual void clearConsoleInt(); - - /** - * Cause the chipset to post a cpi interrupt to the CPU. - */ - virtual void postPciInt(int line); - - /** - * Clear a posted PCI->CPU interrupt - */ - virtual void clearPciInt(int line); - - virtual Addr pciToDma(Addr pciAddr) const; - - /** - * Serialize this object to the given output stream. - * @param os The stream to serialize to. - */ - virtual void serialize(std::ostream &os); - - /** - * Reconstruct the state of this object from a checkpoint. - * @param cp The checkpoint use. - * @param section The section name of this object - */ - virtual void unserialize(Checkpoint *cp, const std::string §ion); -}; - -#endif // __DEV_TSUNAMI_HH__ diff --git a/dev/tsunami_cchip.cc b/dev/tsunami_cchip.cc deleted file mode 100644 index 2649fe27a..000000000 --- a/dev/tsunami_cchip.cc +++ /dev/null @@ -1,580 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** @file - * Emulation of the Tsunami CChip CSRs - */ - -#include <deque> -#include <string> -#include <vector> - -#include "base/trace.hh" -#include "dev/tsunami_cchip.hh" -#include "dev/tsunamireg.h" -#include "dev/tsunami.hh" -#include "mem/bus/bus.hh" -#include "mem/bus/pio_interface.hh" -#include "mem/bus/pio_interface_impl.hh" -#include "mem/functional/memory_control.hh" -#include "cpu/exec_context.hh" -#include "cpu/intr_control.hh" -#include "sim/builder.hh" -#include "sim/system.hh" - -using namespace std; -//Should this be AlphaISA? -using namespace TheISA; - -TsunamiCChip::TsunamiCChip(const string &name, Tsunami *t, Addr a, - MemoryController *mmu, HierParams *hier, - Bus* pio_bus, Tick pio_latency) - : PioDevice(name, t), addr(a), tsunami(t) -{ - mmu->add_child(this, RangeSize(addr, size)); - - if (pio_bus) { - pioInterface = newPioInterface(name + ".pio", hier, pio_bus, this, - &TsunamiCChip::cacheAccess); - pioInterface->addAddrRange(RangeSize(addr, size)); - pioLatency = pio_latency * pio_bus->clockRate; - } - - drir = 0; - ipint = 0; - itint = 0; - - for (int x = 0; x < Tsunami::Max_CPUs; x++) - { - dim[x] = 0; - dir[x] = 0; - } - - //Put back pointer in tsunami - tsunami->cchip = this; -} - -Fault -TsunamiCChip::read(MemReqPtr &req, uint8_t *data) -{ - DPRINTF(Tsunami, "read va=%#x size=%d\n", req->vaddr, req->size); - - Addr regnum = (req->paddr - (addr & EV5::PAddrImplMask)) >> 6; - Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)); - - ExecContext *xc = req->xc; - - switch (req->size) { - - case sizeof(uint64_t): - if (daddr & TSDEV_CC_BDIMS) - { - *(uint64_t*)data = dim[(daddr >> 4) & 0x3F]; - return NoFault; - } - - if (daddr & TSDEV_CC_BDIRS) - { - *(uint64_t*)data = dir[(daddr >> 4) & 0x3F]; - return NoFault; - } - - switch(regnum) { - case TSDEV_CC_CSR: - *(uint64_t*)data = 0x0; - return NoFault; - case TSDEV_CC_MTR: - panic("TSDEV_CC_MTR not implemeted\n"); - return NoFault; - case TSDEV_CC_MISC: - *(uint64_t*)data = (ipint << 8) & 0xF | - (itint << 4) & 0xF | - (xc->readCpuId() & 0x3); - return NoFault; - case TSDEV_CC_AAR0: - case TSDEV_CC_AAR1: - case TSDEV_CC_AAR2: - case TSDEV_CC_AAR3: - *(uint64_t*)data = 0; - return NoFault; - case TSDEV_CC_DIM0: - *(uint64_t*)data = dim[0]; - return NoFault; - case TSDEV_CC_DIM1: - *(uint64_t*)data = dim[1]; - return NoFault; - case TSDEV_CC_DIM2: - *(uint64_t*)data = dim[2]; - return NoFault; - case TSDEV_CC_DIM3: - *(uint64_t*)data = dim[3]; - return NoFault; - case TSDEV_CC_DIR0: - *(uint64_t*)data = dir[0]; - return NoFault; - case TSDEV_CC_DIR1: - *(uint64_t*)data = dir[1]; - return NoFault; - case TSDEV_CC_DIR2: - *(uint64_t*)data = dir[2]; - return NoFault; - case TSDEV_CC_DIR3: - *(uint64_t*)data = dir[3]; - return NoFault; - case TSDEV_CC_DRIR: - *(uint64_t*)data = drir; - return NoFault; - case TSDEV_CC_PRBEN: - panic("TSDEV_CC_PRBEN not implemented\n"); - return NoFault; - case TSDEV_CC_IIC0: - case TSDEV_CC_IIC1: - case TSDEV_CC_IIC2: - case TSDEV_CC_IIC3: - panic("TSDEV_CC_IICx not implemented\n"); - return NoFault; - case TSDEV_CC_MPR0: - case TSDEV_CC_MPR1: - case TSDEV_CC_MPR2: - case TSDEV_CC_MPR3: - panic("TSDEV_CC_MPRx not implemented\n"); - return NoFault; - case TSDEV_CC_IPIR: - *(uint64_t*)data = ipint; - return NoFault; - case TSDEV_CC_ITIR: - *(uint64_t*)data = itint; - return NoFault; - default: - panic("default in cchip read reached, accessing 0x%x\n"); - } // uint64_t - - break; - case sizeof(uint32_t): - if (regnum == TSDEV_CC_DRIR) { - warn("accessing DRIR with 32 bit read, " - "hopefully your just reading this for timing"); - *(uint32_t*)data = drir; - } else - panic("invalid access size(?) for tsunami register!\n"); - return NoFault; - case sizeof(uint16_t): - case sizeof(uint8_t): - default: - panic("invalid access size(?) for tsunami register!\n"); - } - DPRINTFN("Tsunami CChip ERROR: read regnum=%#x size=%d\n", regnum, req->size); - - return NoFault; -} - -Fault -TsunamiCChip::write(MemReqPtr &req, const uint8_t *data) -{ - DPRINTF(Tsunami, "write - va=%#x value=%#x size=%d \n", - req->vaddr, *(uint64_t*)data, req->size); - - Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)); - Addr regnum = (req->paddr - (addr & EV5::PAddrImplMask)) >> 6; - - bool supportedWrite = false; - - switch (req->size) { - - case sizeof(uint64_t): - if (daddr & TSDEV_CC_BDIMS) - { - int number = (daddr >> 4) & 0x3F; - - uint64_t bitvector; - uint64_t olddim; - uint64_t olddir; - - olddim = dim[number]; - olddir = dir[number]; - dim[number] = *(uint64_t*)data; - dir[number] = dim[number] & drir; - for(int x = 0; x < Tsunami::Max_CPUs; x++) - { - bitvector = ULL(1) << x; - // Figure out which bits have changed - if ((dim[number] & bitvector) != (olddim & bitvector)) - { - // The bit is now set and it wasn't before (set) - if((dim[number] & bitvector) && (dir[number] & bitvector)) - { - tsunami->intrctrl->post(number, TheISA::INTLEVEL_IRQ1, x); - DPRINTF(Tsunami, "dim write resulting in posting dir" - " interrupt to cpu %d\n", number); - } - else if ((olddir & bitvector) && - !(dir[number] & bitvector)) - { - // The bit was set and now its now clear and - // we were interrupting on that bit before - tsunami->intrctrl->clear(number, TheISA::INTLEVEL_IRQ1, x); - DPRINTF(Tsunami, "dim write resulting in clear" - " dir interrupt to cpu %d\n", number); - - } - - - } - } - return NoFault; - } - - switch(regnum) { - case TSDEV_CC_CSR: - panic("TSDEV_CC_CSR write\n"); - return NoFault; - case TSDEV_CC_MTR: - panic("TSDEV_CC_MTR write not implemented\n"); - return NoFault; - case TSDEV_CC_MISC: - uint64_t ipreq; - ipreq = (*(uint64_t*)data >> 12) & 0xF; - //If it is bit 12-15, this is an IPI post - if (ipreq) { - reqIPI(ipreq); - supportedWrite = true; - } - - //If it is bit 8-11, this is an IPI clear - uint64_t ipintr; - ipintr = (*(uint64_t*)data >> 8) & 0xF; - if (ipintr) { - clearIPI(ipintr); - supportedWrite = true; - } - - //If it is the 4-7th bit, clear the RTC interrupt - uint64_t itintr; - itintr = (*(uint64_t*)data >> 4) & 0xF; - if (itintr) { - clearITI(itintr); - supportedWrite = true; - } - - // ignore NXMs - if (*(uint64_t*)data & 0x10000000) - supportedWrite = true; - - if(!supportedWrite) - panic("TSDEV_CC_MISC write not implemented\n"); - - return NoFault; - case TSDEV_CC_AAR0: - case TSDEV_CC_AAR1: - case TSDEV_CC_AAR2: - case TSDEV_CC_AAR3: - panic("TSDEV_CC_AARx write not implemeted\n"); - return NoFault; - case TSDEV_CC_DIM0: - case TSDEV_CC_DIM1: - case TSDEV_CC_DIM2: - case TSDEV_CC_DIM3: - int number; - if(regnum == TSDEV_CC_DIM0) - number = 0; - else if(regnum == TSDEV_CC_DIM1) - number = 1; - else if(regnum == TSDEV_CC_DIM2) - number = 2; - else - number = 3; - - uint64_t bitvector; - uint64_t olddim; - uint64_t olddir; - - olddim = dim[number]; - olddir = dir[number]; - dim[number] = *(uint64_t*)data; - dir[number] = dim[number] & drir; - for(int x = 0; x < 64; x++) - { - bitvector = ULL(1) << x; - // Figure out which bits have changed - if ((dim[number] & bitvector) != (olddim & bitvector)) - { - // The bit is now set and it wasn't before (set) - if((dim[number] & bitvector) && (dir[number] & bitvector)) - { - tsunami->intrctrl->post(number, TheISA::INTLEVEL_IRQ1, x); - DPRINTF(Tsunami, "posting dir interrupt to cpu 0\n"); - } - else if ((olddir & bitvector) && - !(dir[number] & bitvector)) - { - // The bit was set and now its now clear and - // we were interrupting on that bit before - tsunami->intrctrl->clear(number, TheISA::INTLEVEL_IRQ1, x); - DPRINTF(Tsunami, "dim write resulting in clear" - " dir interrupt to cpu %d\n", - x); - - } - - - } - } - return NoFault; - case TSDEV_CC_DIR0: - case TSDEV_CC_DIR1: - case TSDEV_CC_DIR2: - case TSDEV_CC_DIR3: - panic("TSDEV_CC_DIR write not implemented\n"); - case TSDEV_CC_DRIR: - panic("TSDEV_CC_DRIR write not implemented\n"); - case TSDEV_CC_PRBEN: - panic("TSDEV_CC_PRBEN write not implemented\n"); - case TSDEV_CC_IIC0: - case TSDEV_CC_IIC1: - case TSDEV_CC_IIC2: - case TSDEV_CC_IIC3: - panic("TSDEV_CC_IICx write not implemented\n"); - case TSDEV_CC_MPR0: - case TSDEV_CC_MPR1: - case TSDEV_CC_MPR2: - case TSDEV_CC_MPR3: - panic("TSDEV_CC_MPRx write not implemented\n"); - case TSDEV_CC_IPIR: - clearIPI(*(uint64_t*)data); - return NoFault; - case TSDEV_CC_ITIR: - clearITI(*(uint64_t*)data); - return NoFault; - case TSDEV_CC_IPIQ: - reqIPI(*(uint64_t*)data); - return NoFault; - default: - panic("default in cchip read reached, accessing 0x%x\n"); - } - - break; - case sizeof(uint32_t): - case sizeof(uint16_t): - case sizeof(uint8_t): - default: - panic("invalid access size(?) for tsunami register!\n"); - } - - DPRINTFN("Tsunami ERROR: write daddr=%#x size=%d\n", daddr, req->size); - - return NoFault; -} - -void -TsunamiCChip::clearIPI(uint64_t ipintr) -{ - int numcpus = tsunami->intrctrl->cpu->system->execContexts.size(); - assert(numcpus <= Tsunami::Max_CPUs); - - if (ipintr) { - for (int cpunum=0; cpunum < numcpus; cpunum++) { - // Check each cpu bit - uint64_t cpumask = ULL(1) << cpunum; - if (ipintr & cpumask) { - // Check if there is a pending ipi - if (ipint & cpumask) { - ipint &= ~cpumask; - tsunami->intrctrl->clear(cpunum, TheISA::INTLEVEL_IRQ3, 0); - DPRINTF(IPI, "clear IPI IPI cpu=%d\n", cpunum); - } - else - warn("clear IPI for CPU=%d, but NO IPI\n", cpunum); - } - } - } - else - panic("Big IPI Clear, but not processors indicated\n"); -} - -void -TsunamiCChip::clearITI(uint64_t itintr) -{ - int numcpus = tsunami->intrctrl->cpu->system->execContexts.size(); - assert(numcpus <= Tsunami::Max_CPUs); - - if (itintr) { - for (int i=0; i < numcpus; i++) { - uint64_t cpumask = ULL(1) << i; - if (itintr & cpumask & itint) { - tsunami->intrctrl->clear(i, TheISA::INTLEVEL_IRQ2, 0); - itint &= ~cpumask; - DPRINTF(Tsunami, "clearing rtc interrupt to cpu=%d\n", i); - } - } - } - else - panic("Big ITI Clear, but not processors indicated\n"); -} - -void -TsunamiCChip::reqIPI(uint64_t ipreq) -{ - int numcpus = tsunami->intrctrl->cpu->system->execContexts.size(); - assert(numcpus <= Tsunami::Max_CPUs); - - if (ipreq) { - for (int cpunum=0; cpunum < numcpus; cpunum++) { - // Check each cpu bit - uint64_t cpumask = ULL(1) << cpunum; - if (ipreq & cpumask) { - // Check if there is already an ipi (bits 8:11) - if (!(ipint & cpumask)) { - ipint |= cpumask; - tsunami->intrctrl->post(cpunum, TheISA::INTLEVEL_IRQ3, 0); - DPRINTF(IPI, "send IPI cpu=%d\n", cpunum); - } - else - warn("post IPI for CPU=%d, but IPI already\n", cpunum); - } - } - } - else - panic("Big IPI Request, but not processors indicated\n"); -} - - -void -TsunamiCChip::postRTC() -{ - int size = tsunami->intrctrl->cpu->system->execContexts.size(); - assert(size <= Tsunami::Max_CPUs); - - for (int i = 0; i < size; i++) { - uint64_t cpumask = ULL(1) << i; - if (!(cpumask & itint)) { - itint |= cpumask; - tsunami->intrctrl->post(i, TheISA::INTLEVEL_IRQ2, 0); - DPRINTF(Tsunami, "Posting RTC interrupt to cpu=%d", i); - } - } - -} - -void -TsunamiCChip::postDRIR(uint32_t interrupt) -{ - uint64_t bitvector = ULL(1) << interrupt; - uint64_t size = tsunami->intrctrl->cpu->system->execContexts.size(); - assert(size <= Tsunami::Max_CPUs); - drir |= bitvector; - - for(int i=0; i < size; i++) { - dir[i] = dim[i] & drir; - if (dim[i] & bitvector) { - tsunami->intrctrl->post(i, TheISA::INTLEVEL_IRQ1, interrupt); - DPRINTF(Tsunami, "posting dir interrupt to cpu %d," - "interrupt %d\n",i, interrupt); - } - } -} - -void -TsunamiCChip::clearDRIR(uint32_t interrupt) -{ - uint64_t bitvector = ULL(1) << interrupt; - uint64_t size = tsunami->intrctrl->cpu->system->execContexts.size(); - assert(size <= Tsunami::Max_CPUs); - - if (drir & bitvector) - { - drir &= ~bitvector; - for(int i=0; i < size; i++) { - if (dir[i] & bitvector) { - tsunami->intrctrl->clear(i, TheISA::INTLEVEL_IRQ1, interrupt); - DPRINTF(Tsunami, "clearing dir interrupt to cpu %d," - "interrupt %d\n",i, interrupt); - - } - dir[i] = dim[i] & drir; - } - } - else - DPRINTF(Tsunami, "Spurrious clear? interrupt %d\n", interrupt); -} - -Tick -TsunamiCChip::cacheAccess(MemReqPtr &req) -{ - return curTick + pioLatency; -} - - -void -TsunamiCChip::serialize(std::ostream &os) -{ - SERIALIZE_ARRAY(dim, Tsunami::Max_CPUs); - SERIALIZE_ARRAY(dir, Tsunami::Max_CPUs); - SERIALIZE_SCALAR(ipint); - SERIALIZE_SCALAR(itint); - SERIALIZE_SCALAR(drir); -} - -void -TsunamiCChip::unserialize(Checkpoint *cp, const std::string §ion) -{ - UNSERIALIZE_ARRAY(dim, Tsunami::Max_CPUs); - UNSERIALIZE_ARRAY(dir, Tsunami::Max_CPUs); - UNSERIALIZE_SCALAR(ipint); - UNSERIALIZE_SCALAR(itint); - UNSERIALIZE_SCALAR(drir); -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiCChip) - - SimObjectParam<Tsunami *> tsunami; - SimObjectParam<MemoryController *> mmu; - Param<Addr> addr; - SimObjectParam<Bus*> pio_bus; - Param<Tick> pio_latency; - SimObjectParam<HierParams *> hier; - -END_DECLARE_SIM_OBJECT_PARAMS(TsunamiCChip) - -BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiCChip) - - INIT_PARAM(tsunami, "Tsunami"), - INIT_PARAM(mmu, "Memory Controller"), - INIT_PARAM(addr, "Device Address"), - INIT_PARAM_DFLT(pio_bus, "The IO Bus to attach to", NULL), - INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1), - INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams) - -END_INIT_SIM_OBJECT_PARAMS(TsunamiCChip) - -CREATE_SIM_OBJECT(TsunamiCChip) -{ - return new TsunamiCChip(getInstanceName(), tsunami, addr, mmu, hier, - pio_bus, pio_latency); -} - -REGISTER_SIM_OBJECT("TsunamiCChip", TsunamiCChip) diff --git a/dev/tsunami_cchip.hh b/dev/tsunami_cchip.hh deleted file mode 100644 index d88ad375f..000000000 --- a/dev/tsunami_cchip.hh +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** @file - * Emulation of the Tsunami CChip CSRs - */ - -#ifndef __TSUNAMI_CCHIP_HH__ -#define __TSUNAMI_CCHIP_HH__ - -#include "dev/tsunami.hh" -#include "base/range.hh" -#include "dev/io_device.hh" - -class MemoryController; - -/** - * Tsunami CChip CSR Emulation. This device includes all the interrupt - * handling code for the chipset. - */ -class TsunamiCChip : public PioDevice -{ - private: - /** The base address of this device */ - Addr addr; - - /** The size of mappad from the above address */ - static const Addr size = 0xfffffff; - - protected: - /** - * pointer to the tsunami object. - * This is our access to all the other tsunami - * devices. - */ - Tsunami *tsunami; - - /** - * The dims are device interrupt mask registers. - * One exists for each CPU, the DRIR X DIM = DIR - */ - uint64_t dim[Tsunami::Max_CPUs]; - - /** - * The dirs are device interrupt registers. - * One exists for each CPU, the DRIR X DIM = DIR - */ - uint64_t dir[Tsunami::Max_CPUs]; - - /** - * This register contains bits for each PCI interrupt - * that can occur. - */ - uint64_t drir; - - /** Indicator of which CPUs have an IPI interrupt */ - uint64_t ipint; - - /** Indicator of which CPUs have an RTC interrupt */ - uint64_t itint; - - public: - /** - * Initialize the Tsunami CChip by setting all of the - * device register to 0. - * @param name name of this device. - * @param t pointer back to the Tsunami object that we belong to. - * @param a address we are mapped at. - * @param mmu pointer to the memory controller that sends us events. - * @param hier object to store parameters universal the device hierarchy - * @param bus The bus that this device is attached to - */ - TsunamiCChip(const std::string &name, Tsunami *t, Addr a, - MemoryController *mmu, HierParams *hier, Bus *pio_bus, - Tick pio_latency); - - /** - * Process a read to the CChip. - * @param req Contains the address to read from. - * @param data A pointer to write the read data to. - * @return The fault condition of the access. - */ - virtual Fault read(MemReqPtr &req, uint8_t *data); - - - /** - * Process a write to the CChip. - * @param req Contains the address to write to. - * @param data The data to write. - * @return The fault condition of the access. - */ - virtual Fault write(MemReqPtr &req, const uint8_t *data); - - /** - * post an RTC interrupt to the CPU - */ - void postRTC(); - - /** - * post an interrupt to the CPU. - * @param interrupt the interrupt number to post (0-64) - */ - void postDRIR(uint32_t interrupt); - - /** - * clear an interrupt previously posted to the CPU. - * @param interrupt the interrupt number to post (0-64) - */ - void clearDRIR(uint32_t interrupt); - - /** - * post an ipi interrupt to the CPU. - * @param ipintr the cpu number to clear(bitvector) - */ - void clearIPI(uint64_t ipintr); - - /** - * clear a timer interrupt previously posted to the CPU. - * @param itintr the cpu number to clear(bitvector) - */ - void clearITI(uint64_t itintr); - - /** - * request an interrupt be posted to the CPU. - * @param ipreq the cpu number to interrupt(bitvector) - */ - void reqIPI(uint64_t ipreq); - - - /** - * Serialize this object to the given output stream. - * @param os The stream to serialize to. - */ - virtual void serialize(std::ostream &os); - - /** - * Reconstruct the state of this object from a checkpoint. - * @param cp The checkpoint use. - * @param section The section name of this object - */ - virtual void unserialize(Checkpoint *cp, const std::string §ion); - - /** - * Return how long this access will take. - * @param req the memory request to calcuate - * @return Tick when the request is done - */ - Tick cacheAccess(MemReqPtr &req); -}; - -#endif // __TSUNAMI_CCHIP_HH__ diff --git a/dev/tsunami_io.cc b/dev/tsunami_io.cc deleted file mode 100644 index e66d6653b..000000000 --- a/dev/tsunami_io.cc +++ /dev/null @@ -1,719 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** @file - * Tsunami I/O including PIC, PIT, RTC, DMA - */ - -#include <sys/time.h> - -#include <deque> -#include <string> -#include <vector> - -#include "base/trace.hh" -#include "dev/tsunami_io.hh" -#include "dev/tsunami.hh" -#include "dev/pitreg.h" -#include "mem/bus/bus.hh" -#include "mem/bus/pio_interface.hh" -#include "mem/bus/pio_interface_impl.hh" -#include "sim/builder.hh" -#include "dev/tsunami_cchip.hh" -#include "dev/tsunamireg.h" -#include "dev/rtcreg.h" -#include "mem/functional/memory_control.hh" - -using namespace std; -//Should this be AlphaISA? -using namespace TheISA; - -TsunamiIO::RTC::RTC(const string &name, Tsunami* t, Tick i) - : _name(name), event(t, i), addr(0) -{ - memset(clock_data, 0, sizeof(clock_data)); - stat_regA = RTCA_32768HZ | RTCA_1024HZ; - stat_regB = RTCB_PRDC_IE |RTCB_BIN | RTCB_24HR; -} - -void -TsunamiIO::RTC::set_time(time_t t) -{ - struct tm tm; - gmtime_r(&t, &tm); - - sec = tm.tm_sec; - min = tm.tm_min; - hour = tm.tm_hour; - wday = tm.tm_wday + 1; - mday = tm.tm_mday; - mon = tm.tm_mon + 1; - year = tm.tm_year; - - DPRINTFN("Real-time clock set to %s", asctime(&tm)); -} - -void -TsunamiIO::RTC::writeAddr(const uint8_t *data) -{ - if (*data <= RTC_STAT_REGD) - addr = *data; - else - panic("RTC addresses over 0xD are not implemented.\n"); -} - -void -TsunamiIO::RTC::writeData(const uint8_t *data) -{ - if (addr < RTC_STAT_REGA) - clock_data[addr] = *data; - else { - switch (addr) { - case RTC_STAT_REGA: - if (*data != (RTCA_32768HZ | RTCA_1024HZ)) - panic("Unimplemented RTC register A value write!\n"); - stat_regA = *data; - break; - case RTC_STAT_REGB: - if ((*data & ~(RTCB_PRDC_IE | RTCB_SQWE)) != (RTCB_BIN | RTCB_24HR)) - panic("Write to RTC reg B bits that are not implemented!\n"); - - if (*data & RTCB_PRDC_IE) { - if (!event.scheduled()) - event.scheduleIntr(); - } else { - if (event.scheduled()) - event.deschedule(); - } - stat_regB = *data; - break; - case RTC_STAT_REGC: - case RTC_STAT_REGD: - panic("RTC status registers C and D are not implemented.\n"); - break; - } - } -} - -void -TsunamiIO::RTC::readData(uint8_t *data) -{ - if (addr < RTC_STAT_REGA) - *data = clock_data[addr]; - else { - switch (addr) { - case RTC_STAT_REGA: - // toggle UIP bit for linux - stat_regA ^= RTCA_UIP; - *data = stat_regA; - break; - case RTC_STAT_REGB: - *data = stat_regB; - break; - case RTC_STAT_REGC: - case RTC_STAT_REGD: - *data = 0x00; - break; - } - } -} - -void -TsunamiIO::RTC::serialize(const string &base, ostream &os) -{ - paramOut(os, base + ".addr", addr); - arrayParamOut(os, base + ".clock_data", clock_data, sizeof(clock_data)); - paramOut(os, base + ".stat_regA", stat_regA); - paramOut(os, base + ".stat_regB", stat_regB); -} - -void -TsunamiIO::RTC::unserialize(const string &base, Checkpoint *cp, - const string §ion) -{ - paramIn(cp, section, base + ".addr", addr); - arrayParamIn(cp, section, base + ".clock_data", clock_data, - sizeof(clock_data)); - paramIn(cp, section, base + ".stat_regA", stat_regA); - paramIn(cp, section, base + ".stat_regB", stat_regB); - - // We're not unserializing the event here, but we need to - // rescehedule the event since curTick was moved forward by the - // checkpoint - event.reschedule(curTick + event.interval); -} - -TsunamiIO::RTC::RTCEvent::RTCEvent(Tsunami*t, Tick i) - : Event(&mainEventQueue), tsunami(t), interval(i) -{ - DPRINTF(MC146818, "RTC Event Initilizing\n"); - schedule(curTick + interval); -} - -void -TsunamiIO::RTC::RTCEvent::scheduleIntr() -{ - schedule(curTick + interval); -} - -void -TsunamiIO::RTC::RTCEvent::process() -{ - DPRINTF(MC146818, "RTC Timer Interrupt\n"); - schedule(curTick + interval); - //Actually interrupt the processor here - tsunami->cchip->postRTC(); -} - -const char * -TsunamiIO::RTC::RTCEvent::description() -{ - return "tsunami RTC interrupt"; -} - -TsunamiIO::PITimer::PITimer(const string &name) - : _name(name), counter0(name + ".counter0"), counter1(name + ".counter1"), - counter2(name + ".counter2") -{ - counter[0] = &counter0; - counter[1] = &counter0; - counter[2] = &counter0; -} - -void -TsunamiIO::PITimer::writeControl(const uint8_t *data) -{ - int rw; - int sel; - - sel = GET_CTRL_SEL(*data); - - if (sel == PIT_READ_BACK) - panic("PITimer Read-Back Command is not implemented.\n"); - - rw = GET_CTRL_RW(*data); - - if (rw == PIT_RW_LATCH_COMMAND) - counter[sel]->latchCount(); - else { - counter[sel]->setRW(rw); - counter[sel]->setMode(GET_CTRL_MODE(*data)); - counter[sel]->setBCD(GET_CTRL_BCD(*data)); - } -} - -void -TsunamiIO::PITimer::serialize(const string &base, ostream &os) -{ - // serialize the counters - counter0.serialize(base + ".counter0", os); - counter1.serialize(base + ".counter1", os); - counter2.serialize(base + ".counter2", os); -} - -void -TsunamiIO::PITimer::unserialize(const string &base, Checkpoint *cp, - const string §ion) -{ - // unserialze the counters - counter0.unserialize(base + ".counter0", cp, section); - counter1.unserialize(base + ".counter1", cp, section); - counter2.unserialize(base + ".counter2", cp, section); -} - -TsunamiIO::PITimer::Counter::Counter(const string &name) - : _name(name), event(this), count(0), latched_count(0), period(0), - mode(0), output_high(false), latch_on(false), read_byte(LSB), - write_byte(LSB) -{ - -} - -void -TsunamiIO::PITimer::Counter::latchCount() -{ - // behave like a real latch - if(!latch_on) { - latch_on = true; - read_byte = LSB; - latched_count = count; - } -} - -void -TsunamiIO::PITimer::Counter::read(uint8_t *data) -{ - if (latch_on) { - switch (read_byte) { - case LSB: - read_byte = MSB; - *data = (uint8_t)latched_count; - break; - case MSB: - read_byte = LSB; - latch_on = false; - *data = latched_count >> 8; - break; - } - } else { - switch (read_byte) { - case LSB: - read_byte = MSB; - *data = (uint8_t)count; - break; - case MSB: - read_byte = LSB; - *data = count >> 8; - break; - } - } -} - -void -TsunamiIO::PITimer::Counter::write(const uint8_t *data) -{ - switch (write_byte) { - case LSB: - count = (count & 0xFF00) | *data; - - if (event.scheduled()) - event.deschedule(); - output_high = false; - write_byte = MSB; - break; - - case MSB: - count = (count & 0x00FF) | (*data << 8); - period = count; - - if (period > 0) { - DPRINTF(Tsunami, "Timer set to curTick + %d\n", - count * event.interval); - event.schedule(curTick + count * event.interval); - } - write_byte = LSB; - break; - } -} - -void -TsunamiIO::PITimer::Counter::setRW(int rw_val) -{ - if (rw_val != PIT_RW_16BIT) - panic("Only LSB/MSB read/write is implemented.\n"); -} - -void -TsunamiIO::PITimer::Counter::setMode(int mode_val) -{ - if(mode_val != PIT_MODE_INTTC && mode_val != PIT_MODE_RATEGEN && - mode_val != PIT_MODE_SQWAVE) - panic("PIT mode %#x is not implemented: \n", mode_val); - - mode = mode_val; -} - -void -TsunamiIO::PITimer::Counter::setBCD(int bcd_val) -{ - if (bcd_val != PIT_BCD_FALSE) - panic("PITimer does not implement BCD counts.\n"); -} - -bool -TsunamiIO::PITimer::Counter::outputHigh() -{ - return output_high; -} - -void -TsunamiIO::PITimer::Counter::serialize(const string &base, ostream &os) -{ - paramOut(os, base + ".count", count); - paramOut(os, base + ".latched_count", latched_count); - paramOut(os, base + ".period", period); - paramOut(os, base + ".mode", mode); - paramOut(os, base + ".output_high", output_high); - paramOut(os, base + ".latch_on", latch_on); - paramOut(os, base + ".read_byte", read_byte); - paramOut(os, base + ".write_byte", write_byte); - - Tick event_tick = 0; - if (event.scheduled()) - event_tick = event.when(); - paramOut(os, base + ".event_tick", event_tick); -} - -void -TsunamiIO::PITimer::Counter::unserialize(const string &base, Checkpoint *cp, - const string §ion) -{ - paramIn(cp, section, base + ".count", count); - paramIn(cp, section, base + ".latched_count", latched_count); - paramIn(cp, section, base + ".period", period); - paramIn(cp, section, base + ".mode", mode); - paramIn(cp, section, base + ".output_high", output_high); - paramIn(cp, section, base + ".latch_on", latch_on); - paramIn(cp, section, base + ".read_byte", read_byte); - paramIn(cp, section, base + ".write_byte", write_byte); - - Tick event_tick; - paramIn(cp, section, base + ".event_tick", event_tick); - if (event_tick) - event.schedule(event_tick); -} - -TsunamiIO::PITimer::Counter::CounterEvent::CounterEvent(Counter* c_ptr) - : Event(&mainEventQueue) -{ - interval = (Tick)(Clock::Float::s / 1193180.0); - counter = c_ptr; -} - -void -TsunamiIO::PITimer::Counter::CounterEvent::process() -{ - DPRINTF(Tsunami, "Timer Interrupt\n"); - switch (counter->mode) { - case PIT_MODE_INTTC: - counter->output_high = true; - case PIT_MODE_RATEGEN: - case PIT_MODE_SQWAVE: - break; - default: - panic("Unimplemented PITimer mode.\n"); - } -} - -const char * -TsunamiIO::PITimer::Counter::CounterEvent::description() -{ - return "tsunami 8254 Interval timer"; -} - -TsunamiIO::TsunamiIO(const string &name, Tsunami *t, time_t init_time, - Addr a, MemoryController *mmu, HierParams *hier, - Bus *pio_bus, Tick pio_latency, Tick ci) - : PioDevice(name, t), addr(a), clockInterval(ci), tsunami(t), - pitimer(name + "pitimer"), rtc(name + ".rtc", t, ci) -{ - mmu->add_child(this, RangeSize(addr, size)); - - if (pio_bus) { - pioInterface = newPioInterface(name + ".pio", hier, pio_bus, this, - &TsunamiIO::cacheAccess); - pioInterface->addAddrRange(RangeSize(addr, size)); - pioLatency = pio_latency * pio_bus->clockRate; - } - - // set the back pointer from tsunami to myself - tsunami->io = this; - - timerData = 0; - rtc.set_time(init_time == 0 ? time(NULL) : init_time); - picr = 0; - picInterrupting = false; -} - -Tick -TsunamiIO::frequency() const -{ - return Clock::Frequency / clockInterval; -} - -Fault -TsunamiIO::read(MemReqPtr &req, uint8_t *data) -{ - DPRINTF(Tsunami, "io read va=%#x size=%d IOPorrt=%#x\n", - req->vaddr, req->size, req->vaddr & 0xfff); - - Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)); - - - switch(req->size) { - case sizeof(uint8_t): - switch(daddr) { - // PIC1 mask read - case TSDEV_PIC1_MASK: - *(uint8_t*)data = ~mask1; - return NoFault; - case TSDEV_PIC2_MASK: - *(uint8_t*)data = ~mask2; - return NoFault; - case TSDEV_PIC1_ISR: - // !!! If this is modified 64bit case needs to be too - // Pal code has to do a 64 bit physical read because there is - // no load physical byte instruction - *(uint8_t*)data = picr; - return NoFault; - case TSDEV_PIC2_ISR: - // PIC2 not implemnted... just return 0 - *(uint8_t*)data = 0x00; - return NoFault; - case TSDEV_TMR0_DATA: - pitimer.counter0.read(data); - return NoFault; - case TSDEV_TMR1_DATA: - pitimer.counter1.read(data); - return NoFault; - case TSDEV_TMR2_DATA: - pitimer.counter2.read(data); - return NoFault; - case TSDEV_RTC_DATA: - rtc.readData(data); - return NoFault; - case TSDEV_CTRL_PORTB: - if (pitimer.counter2.outputHigh()) - *data = PORTB_SPKR_HIGH; - else - *data = 0x00; - return NoFault; - default: - panic("I/O Read - va%#x size %d\n", req->vaddr, req->size); - } - case sizeof(uint16_t): - case sizeof(uint32_t): - panic("I/O Read - invalid size - va %#x size %d\n", - req->vaddr, req->size); - - case sizeof(uint64_t): - switch(daddr) { - case TSDEV_PIC1_ISR: - // !!! If this is modified 8bit case needs to be too - // Pal code has to do a 64 bit physical read because there is - // no load physical byte instruction - *(uint64_t*)data = (uint64_t)picr; - return NoFault; - default: - panic("I/O Read - invalid size - va %#x size %d\n", - req->vaddr, req->size); - } - - default: - panic("I/O Read - invalid size - va %#x size %d\n", - req->vaddr, req->size); - } - panic("I/O Read - va%#x size %d\n", req->vaddr, req->size); - - return NoFault; -} - -Fault -TsunamiIO::write(MemReqPtr &req, const uint8_t *data) -{ - -#if TRACING_ON - uint8_t dt = *(uint8_t*)data; - uint64_t dt64 = dt; -#endif - - DPRINTF(Tsunami, "io write - va=%#x size=%d IOPort=%#x Data=%#x\n", - req->vaddr, req->size, req->vaddr & 0xfff, dt64); - - Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)); - - switch(req->size) { - case sizeof(uint8_t): - switch(daddr) { - case TSDEV_PIC1_MASK: - mask1 = ~(*(uint8_t*)data); - if ((picr & mask1) && !picInterrupting) { - picInterrupting = true; - tsunami->cchip->postDRIR(55); - DPRINTF(Tsunami, "posting pic interrupt to cchip\n"); - } - if ((!(picr & mask1)) && picInterrupting) { - picInterrupting = false; - tsunami->cchip->clearDRIR(55); - DPRINTF(Tsunami, "clearing pic interrupt\n"); - } - return NoFault; - case TSDEV_PIC2_MASK: - mask2 = *(uint8_t*)data; - //PIC2 Not implemented to interrupt - return NoFault; - case TSDEV_PIC1_ACK: - // clear the interrupt on the PIC - picr &= ~(1 << (*(uint8_t*)data & 0xF)); - if (!(picr & mask1)) - tsunami->cchip->clearDRIR(55); - return NoFault; - case TSDEV_DMA1_CMND: - return NoFault; - case TSDEV_DMA2_CMND: - return NoFault; - case TSDEV_DMA1_MMASK: - return NoFault; - case TSDEV_DMA2_MMASK: - return NoFault; - case TSDEV_PIC2_ACK: - return NoFault; - case TSDEV_DMA1_RESET: - return NoFault; - case TSDEV_DMA2_RESET: - return NoFault; - case TSDEV_DMA1_MODE: - mode1 = *(uint8_t*)data; - return NoFault; - case TSDEV_DMA2_MODE: - mode2 = *(uint8_t*)data; - return NoFault; - case TSDEV_DMA1_MASK: - case TSDEV_DMA2_MASK: - return NoFault; - case TSDEV_TMR0_DATA: - pitimer.counter0.write(data); - return NoFault; - case TSDEV_TMR1_DATA: - pitimer.counter1.write(data); - return NoFault; - case TSDEV_TMR2_DATA: - pitimer.counter2.write(data); - return NoFault; - case TSDEV_TMR_CTRL: - pitimer.writeControl(data); - return NoFault; - case TSDEV_RTC_ADDR: - rtc.writeAddr(data); - return NoFault; - case TSDEV_KBD: - return NoFault; - case TSDEV_RTC_DATA: - rtc.writeData(data); - return NoFault; - case TSDEV_CTRL_PORTB: - // System Control Port B not implemented - return NoFault; - default: - panic("I/O Write - va%#x size %d data %#x\n", req->vaddr, req->size, (int)*data); - } - case sizeof(uint16_t): - case sizeof(uint32_t): - case sizeof(uint64_t): - default: - panic("I/O Write - invalid size - va %#x size %d\n", - req->vaddr, req->size); - } - - - return NoFault; -} - -void -TsunamiIO::postPIC(uint8_t bitvector) -{ - //PIC2 Is not implemented, because nothing of interest there - picr |= bitvector; - if (picr & mask1) { - tsunami->cchip->postDRIR(55); - DPRINTF(Tsunami, "posting pic interrupt to cchip\n"); - } -} - -void -TsunamiIO::clearPIC(uint8_t bitvector) -{ - //PIC2 Is not implemented, because nothing of interest there - picr &= ~bitvector; - if (!(picr & mask1)) { - tsunami->cchip->clearDRIR(55); - DPRINTF(Tsunami, "clearing pic interrupt to cchip\n"); - } -} - -Tick -TsunamiIO::cacheAccess(MemReqPtr &req) -{ - return curTick + pioLatency; -} - -void -TsunamiIO::serialize(ostream &os) -{ - SERIALIZE_SCALAR(timerData); - SERIALIZE_SCALAR(mask1); - SERIALIZE_SCALAR(mask2); - SERIALIZE_SCALAR(mode1); - SERIALIZE_SCALAR(mode2); - SERIALIZE_SCALAR(picr); - SERIALIZE_SCALAR(picInterrupting); - - // Serialize the timers - pitimer.serialize("pitimer", os); - rtc.serialize("rtc", os); -} - -void -TsunamiIO::unserialize(Checkpoint *cp, const string §ion) -{ - UNSERIALIZE_SCALAR(timerData); - UNSERIALIZE_SCALAR(mask1); - UNSERIALIZE_SCALAR(mask2); - UNSERIALIZE_SCALAR(mode1); - UNSERIALIZE_SCALAR(mode2); - UNSERIALIZE_SCALAR(picr); - UNSERIALIZE_SCALAR(picInterrupting); - - // Unserialize the timers - pitimer.unserialize("pitimer", cp, section); - rtc.unserialize("rtc", cp, section); -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO) - - SimObjectParam<Tsunami *> tsunami; - Param<time_t> time; - SimObjectParam<MemoryController *> mmu; - Param<Addr> addr; - SimObjectParam<Bus*> pio_bus; - Param<Tick> pio_latency; - SimObjectParam<HierParams *> hier; - Param<Tick> frequency; - -END_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO) - -BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiIO) - - INIT_PARAM(tsunami, "Tsunami"), - INIT_PARAM(time, "System time to use (0 for actual time"), - INIT_PARAM(mmu, "Memory Controller"), - INIT_PARAM(addr, "Device Address"), - INIT_PARAM(pio_bus, "The IO Bus to attach to"), - INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1), - INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams), - INIT_PARAM(frequency, "clock interrupt frequency") - -END_INIT_SIM_OBJECT_PARAMS(TsunamiIO) - -CREATE_SIM_OBJECT(TsunamiIO) -{ - return new TsunamiIO(getInstanceName(), tsunami, time, addr, mmu, hier, - pio_bus, pio_latency, frequency); -} - -REGISTER_SIM_OBJECT("TsunamiIO", TsunamiIO) diff --git a/dev/tsunami_io.hh b/dev/tsunami_io.hh deleted file mode 100644 index b024ecd14..000000000 --- a/dev/tsunami_io.hh +++ /dev/null @@ -1,371 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** @file - * Tsunami I/O Space mapping including RTC/timer interrupts - */ - -#ifndef __DEV_TSUNAMI_IO_HH__ -#define __DEV_TSUNAMI_IO_HH__ - -#include "dev/io_device.hh" -#include "base/range.hh" -#include "dev/tsunami.hh" -#include "sim/eventq.hh" - -class MemoryController; - -/** - * Tsunami I/O device is a catch all for all the south bridge stuff we care - * to implement. - */ -class TsunamiIO : public PioDevice -{ - private: - /** The base address of this device */ - Addr addr; - - /** The size of mappad from the above address */ - static const Addr size = 0xff; - - struct tm tm; - - protected: - /** Real-Time Clock (MC146818) */ - class RTC - { - private: - /** Event for RTC periodic interrupt */ - struct RTCEvent : public Event - { - /** A pointer back to tsunami to create interrupt the processor. */ - Tsunami* tsunami; - Tick interval; - - RTCEvent(Tsunami* t, Tick i); - - /** Schedule the RTC periodic interrupt */ - void scheduleIntr(); - - /** Event process to occur at interrupt*/ - virtual void process(); - - /** Event description */ - virtual const char *description(); - }; - - private: - std::string _name; - const std::string &name() const { return _name; } - - /** RTC periodic interrupt event */ - RTCEvent event; - - /** Current RTC register address/index */ - int addr; - - /** Data for real-time clock function */ - union { - uint8_t clock_data[10]; - - struct { - uint8_t sec; - uint8_t sec_alrm; - uint8_t min; - uint8_t min_alrm; - uint8_t hour; - uint8_t hour_alrm; - uint8_t wday; - uint8_t mday; - uint8_t mon; - uint8_t year; - }; - }; - - /** RTC status register A */ - uint8_t stat_regA; - - /** RTC status register B */ - uint8_t stat_regB; - - public: - RTC(const std::string &name, Tsunami* t, Tick i); - - /** Set the initial RTC time/date */ - void set_time(time_t t); - - /** RTC address port: write address of RTC RAM data to access */ - void writeAddr(const uint8_t *data); - - /** RTC write data */ - void writeData(const uint8_t *data); - - /** RTC read data */ - void readData(uint8_t *data); - - /** - * Serialize this object to the given output stream. - * @param os The stream to serialize to. - */ - void serialize(const std::string &base, std::ostream &os); - - /** - * Reconstruct the state of this object from a checkpoint. - * @param cp The checkpoint use. - * @param section The section name of this object - */ - void unserialize(const std::string &base, Checkpoint *cp, - const std::string §ion); - }; - - /** Programmable Interval Timer (Intel 8254) */ - class PITimer - { - /** Counter element for PIT */ - class Counter - { - /** Event for counter interrupt */ - class CounterEvent : public Event - { - private: - /** Pointer back to Counter */ - Counter* counter; - Tick interval; - - public: - CounterEvent(Counter*); - - /** Event process */ - virtual void process(); - - /** Event description */ - virtual const char *description(); - - friend class Counter; - }; - - private: - std::string _name; - const std::string &name() const { return _name; } - - CounterEvent event; - - /** Current count value */ - uint16_t count; - - /** Latched count */ - uint16_t latched_count; - - /** Interrupt period */ - uint16_t period; - - /** Current mode of operation */ - uint8_t mode; - - /** Output goes high when the counter reaches zero */ - bool output_high; - - /** State of the count latch */ - bool latch_on; - - /** Set of values for read_byte and write_byte */ - enum {LSB, MSB}; - - /** Determine which byte of a 16-bit count value to read/write */ - uint8_t read_byte, write_byte; - - public: - Counter(const std::string &name); - - /** Latch the current count (if one is not already latched) */ - void latchCount(); - - /** Set the read/write mode */ - void setRW(int rw_val); - - /** Set operational mode */ - void setMode(int mode_val); - - /** Set count encoding */ - void setBCD(int bcd_val); - - /** Read a count byte */ - void read(uint8_t *data); - - /** Write a count byte */ - void write(const uint8_t *data); - - /** Is the output high? */ - bool outputHigh(); - - /** - * Serialize this object to the given output stream. - * @param os The stream to serialize to. - */ - void serialize(const std::string &base, std::ostream &os); - - /** - * Reconstruct the state of this object from a checkpoint. - * @param cp The checkpoint use. - * @param section The section name of this object - */ - void unserialize(const std::string &base, Checkpoint *cp, - const std::string §ion); - }; - - private: - std::string _name; - const std::string &name() const { return _name; } - - /** PIT has three seperate counters */ - Counter *counter[3]; - - public: - /** Public way to access individual counters (avoid array accesses) */ - Counter counter0; - Counter counter1; - Counter counter2; - - PITimer(const std::string &name); - - /** Write control word */ - void writeControl(const uint8_t* data); - - /** - * Serialize this object to the given output stream. - * @param os The stream to serialize to. - */ - void serialize(const std::string &base, std::ostream &os); - - /** - * Reconstruct the state of this object from a checkpoint. - * @param cp The checkpoint use. - * @param section The section name of this object - */ - void unserialize(const std::string &base, Checkpoint *cp, - const std::string §ion); - }; - - /** Mask of the PIC1 */ - uint8_t mask1; - - /** Mask of the PIC2 */ - uint8_t mask2; - - /** Mode of PIC1. Not used for anything */ - uint8_t mode1; - - /** Mode of PIC2. Not used for anything */ - uint8_t mode2; - - /** Raw PIC interrupt register before masking */ - uint8_t picr; //Raw PIC interrput register - - /** Is the pic interrupting right now or not. */ - bool picInterrupting; - - Tick clockInterval; - - /** A pointer to the Tsunami device which be belong to */ - Tsunami *tsunami; - - /** Intel 8253 Periodic Interval Timer */ - PITimer pitimer; - - RTC rtc; - - /** The interval is set via two writes to the PIT. - * This variable contains a flag as to how many writes have happened, and - * the time so far. - */ - uint16_t timerData; - - public: - /** - * Return the freqency of the RTC - * @return interrupt rate of the RTC - */ - Tick frequency() const; - - /** - * Initialize all the data for devices supported by Tsunami I/O. - * @param name name of this device. - * @param t pointer back to the Tsunami object that we belong to. - * @param init_time Time (as in seconds since 1970) to set RTC to. - * @param a address we are mapped at. - * @param mmu pointer to the memory controller that sends us events. - */ - TsunamiIO(const std::string &name, Tsunami *t, time_t init_time, - Addr a, MemoryController *mmu, HierParams *hier, Bus *pio_bus, - Tick pio_latency, Tick ci); - - /** - * Process a read to one of the devices we are emulating. - * @param req Contains the address to read from. - * @param data A pointer to write the read data to. - * @return The fault condition of the access. - */ - virtual Fault read(MemReqPtr &req, uint8_t *data); - - /** - * Process a write to one of the devices we emulate. - * @param req Contains the address to write to. - * @param data The data to write. - * @return The fault condition of the access. - */ - virtual Fault write(MemReqPtr &req, const uint8_t *data); - - /** - * Post an PIC interrupt to the CPU via the CChip - * @param bitvector interrupt to post. - */ - void postPIC(uint8_t bitvector); - - /** - * Clear a posted interrupt - * @param bitvector interrupt to clear - */ - void clearPIC(uint8_t bitvector); - - /** - * Serialize this object to the given output stream. - * @param os The stream to serialize to. - */ - virtual void serialize(std::ostream &os); - - /** - * Reconstruct the state of this object from a checkpoint. - * @param cp The checkpoint use. - * @param section The section name of this object - */ - virtual void unserialize(Checkpoint *cp, const std::string §ion); - - Tick cacheAccess(MemReqPtr &req); -}; - -#endif // __DEV_TSUNAMI_IO_HH__ diff --git a/dev/tsunami_pchip.cc b/dev/tsunami_pchip.cc deleted file mode 100644 index 46efc3dfe..000000000 --- a/dev/tsunami_pchip.cc +++ /dev/null @@ -1,388 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** @file - * Tsunami PChip (pci) - */ - -#include <deque> -#include <string> -#include <vector> - -#include "base/trace.hh" -#include "dev/tsunami_pchip.hh" -#include "dev/tsunamireg.h" -#include "dev/tsunami.hh" -#include "mem/bus/bus.hh" -#include "mem/bus/pio_interface.hh" -#include "mem/bus/pio_interface_impl.hh" -#include "mem/functional/memory_control.hh" -#include "mem/functional/physical.hh" -#include "sim/builder.hh" -#include "sim/system.hh" - -using namespace std; -//Should this be AlphaISA? -using namespace TheISA; - -TsunamiPChip::TsunamiPChip(const string &name, Tsunami *t, Addr a, - MemoryController *mmu, HierParams *hier, - Bus *pio_bus, Tick pio_latency) - : PioDevice(name, t), addr(a), tsunami(t) -{ - mmu->add_child(this, RangeSize(addr, size)); - - for (int i = 0; i < 4; i++) { - wsba[i] = 0; - wsm[i] = 0; - tba[i] = 0; - } - - if (pio_bus) { - pioInterface = newPioInterface(name + ".pio", hier, pio_bus, this, - &TsunamiPChip::cacheAccess); - pioInterface->addAddrRange(RangeSize(addr, size)); - pioLatency = pio_latency * pio_bus->clockRate; - } - - - // initialize pchip control register - pctl = (ULL(0x1) << 20) | (ULL(0x1) << 32) | (ULL(0x2) << 36); - - //Set back pointer in tsunami - tsunami->pchip = this; -} - -Fault -TsunamiPChip::read(MemReqPtr &req, uint8_t *data) -{ - DPRINTF(Tsunami, "read va=%#x size=%d\n", - req->vaddr, req->size); - - Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)) >> 6; - - switch (req->size) { - - case sizeof(uint64_t): - switch(daddr) { - case TSDEV_PC_WSBA0: - *(uint64_t*)data = wsba[0]; - return NoFault; - case TSDEV_PC_WSBA1: - *(uint64_t*)data = wsba[1]; - return NoFault; - case TSDEV_PC_WSBA2: - *(uint64_t*)data = wsba[2]; - return NoFault; - case TSDEV_PC_WSBA3: - *(uint64_t*)data = wsba[3]; - return NoFault; - case TSDEV_PC_WSM0: - *(uint64_t*)data = wsm[0]; - return NoFault; - case TSDEV_PC_WSM1: - *(uint64_t*)data = wsm[1]; - return NoFault; - case TSDEV_PC_WSM2: - *(uint64_t*)data = wsm[2]; - return NoFault; - case TSDEV_PC_WSM3: - *(uint64_t*)data = wsm[3]; - return NoFault; - case TSDEV_PC_TBA0: - *(uint64_t*)data = tba[0]; - return NoFault; - case TSDEV_PC_TBA1: - *(uint64_t*)data = tba[1]; - return NoFault; - case TSDEV_PC_TBA2: - *(uint64_t*)data = tba[2]; - return NoFault; - case TSDEV_PC_TBA3: - *(uint64_t*)data = tba[3]; - return NoFault; - case TSDEV_PC_PCTL: - *(uint64_t*)data = pctl; - return NoFault; - case TSDEV_PC_PLAT: - panic("PC_PLAT not implemented\n"); - case TSDEV_PC_RES: - panic("PC_RES not implemented\n"); - case TSDEV_PC_PERROR: - *(uint64_t*)data = 0x00; - return NoFault; - case TSDEV_PC_PERRMASK: - *(uint64_t*)data = 0x00; - return NoFault; - case TSDEV_PC_PERRSET: - panic("PC_PERRSET not implemented\n"); - case TSDEV_PC_TLBIV: - panic("PC_TLBIV not implemented\n"); - case TSDEV_PC_TLBIA: - *(uint64_t*)data = 0x00; // shouldn't be readable, but linux - return NoFault; - case TSDEV_PC_PMONCTL: - panic("PC_PMONCTL not implemented\n"); - case TSDEV_PC_PMONCNT: - panic("PC_PMONCTN not implemented\n"); - default: - panic("Default in PChip Read reached reading 0x%x\n", daddr); - - } // uint64_t - - break; - case sizeof(uint32_t): - case sizeof(uint16_t): - case sizeof(uint8_t): - default: - panic("invalid access size(?) for tsunami register!\n\n"); - } - DPRINTFN("Tsunami PChip ERROR: read daddr=%#x size=%d\n", daddr, req->size); - - return NoFault; -} - -Fault -TsunamiPChip::write(MemReqPtr &req, const uint8_t *data) -{ - DPRINTF(Tsunami, "write - va=%#x size=%d \n", - req->vaddr, req->size); - - Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)) >> 6; - - switch (req->size) { - - case sizeof(uint64_t): - switch(daddr) { - case TSDEV_PC_WSBA0: - wsba[0] = *(uint64_t*)data; - return NoFault; - case TSDEV_PC_WSBA1: - wsba[1] = *(uint64_t*)data; - return NoFault; - case TSDEV_PC_WSBA2: - wsba[2] = *(uint64_t*)data; - return NoFault; - case TSDEV_PC_WSBA3: - wsba[3] = *(uint64_t*)data; - return NoFault; - case TSDEV_PC_WSM0: - wsm[0] = *(uint64_t*)data; - return NoFault; - case TSDEV_PC_WSM1: - wsm[1] = *(uint64_t*)data; - return NoFault; - case TSDEV_PC_WSM2: - wsm[2] = *(uint64_t*)data; - return NoFault; - case TSDEV_PC_WSM3: - wsm[3] = *(uint64_t*)data; - return NoFault; - case TSDEV_PC_TBA0: - tba[0] = *(uint64_t*)data; - return NoFault; - case TSDEV_PC_TBA1: - tba[1] = *(uint64_t*)data; - return NoFault; - case TSDEV_PC_TBA2: - tba[2] = *(uint64_t*)data; - return NoFault; - case TSDEV_PC_TBA3: - tba[3] = *(uint64_t*)data; - return NoFault; - case TSDEV_PC_PCTL: - pctl = *(uint64_t*)data; - return NoFault; - case TSDEV_PC_PLAT: - panic("PC_PLAT not implemented\n"); - case TSDEV_PC_RES: - panic("PC_RES not implemented\n"); - case TSDEV_PC_PERROR: - return NoFault; - case TSDEV_PC_PERRMASK: - panic("PC_PERRMASK not implemented\n"); - case TSDEV_PC_PERRSET: - panic("PC_PERRSET not implemented\n"); - case TSDEV_PC_TLBIV: - panic("PC_TLBIV not implemented\n"); - case TSDEV_PC_TLBIA: - return NoFault; // value ignored, supposted to invalidate SG TLB - case TSDEV_PC_PMONCTL: - panic("PC_PMONCTL not implemented\n"); - case TSDEV_PC_PMONCNT: - panic("PC_PMONCTN not implemented\n"); - default: - panic("Default in PChip Read reached reading 0x%x\n", daddr); - - } // uint64_t - - break; - case sizeof(uint32_t): - case sizeof(uint16_t): - case sizeof(uint8_t): - default: - panic("invalid access size(?) for tsunami register!\n\n"); - } - - DPRINTFN("Tsunami ERROR: write daddr=%#x size=%d\n", daddr, req->size); - - return NoFault; -} - -#define DMA_ADDR_MASK ULL(0x3ffffffff) - -Addr -TsunamiPChip::translatePciToDma(Addr busAddr) -{ - // compare the address to the window base registers - uint64_t tbaMask = 0; - uint64_t baMask = 0; - - uint64_t windowMask = 0; - uint64_t windowBase = 0; - - uint64_t pteEntry = 0; - - Addr pteAddr; - Addr dmaAddr; - -#if 0 - DPRINTF(IdeDisk, "Translation for bus address: %#x\n", busAddr); - for (int i = 0; i < 4; i++) { - DPRINTF(IdeDisk, "(%d) base:%#x mask:%#x\n", - i, wsba[i], wsm[i]); - - windowBase = wsba[i]; - windowMask = ~wsm[i] & (ULL(0xfff) << 20); - - if ((busAddr & windowMask) == (windowBase & windowMask)) { - DPRINTF(IdeDisk, "Would have matched %d (wb:%#x wm:%#x --> ba&wm:%#x wb&wm:%#x)\n", - i, windowBase, windowMask, (busAddr & windowMask), - (windowBase & windowMask)); - } - } -#endif - - for (int i = 0; i < 4; i++) { - - windowBase = wsba[i]; - windowMask = ~wsm[i] & (ULL(0xfff) << 20); - - if ((busAddr & windowMask) == (windowBase & windowMask)) { - - if (wsba[i] & 0x1) { // see if enabled - if (wsba[i] & 0x2) { // see if SG bit is set - /** @todo - This currently is faked by just doing a direct - read from memory, however, to be realistic, this - needs to actually do a bus transaction. The process - is explained in the tsunami documentation on page - 10-12 and basically munges the address to look up a - PTE from a table in memory and then uses that mapping - to create an address for the SG page - */ - - tbaMask = ~(((wsm[i] & (ULL(0xfff) << 20)) >> 10) | ULL(0x3ff)); - baMask = (wsm[i] & (ULL(0xfff) << 20)) | (ULL(0x7f) << 13); - pteAddr = (tba[i] & tbaMask) | ((busAddr & baMask) >> 10); - - memcpy((void *)&pteEntry, - tsunami->system-> - physmem->dma_addr(pteAddr, sizeof(uint64_t)), - sizeof(uint64_t)); - - dmaAddr = ((pteEntry & ~ULL(0x1)) << 12) | (busAddr & ULL(0x1fff)); - - } else { - baMask = (wsm[i] & (ULL(0xfff) << 20)) | ULL(0xfffff); - tbaMask = ~baMask; - dmaAddr = (tba[i] & tbaMask) | (busAddr & baMask); - } - - return (dmaAddr & DMA_ADDR_MASK); - } - } - } - - // if no match was found, then return the original address - return busAddr; -} - -void -TsunamiPChip::serialize(std::ostream &os) -{ - SERIALIZE_SCALAR(pctl); - SERIALIZE_ARRAY(wsba, 4); - SERIALIZE_ARRAY(wsm, 4); - SERIALIZE_ARRAY(tba, 4); -} - -void -TsunamiPChip::unserialize(Checkpoint *cp, const std::string §ion) -{ - UNSERIALIZE_SCALAR(pctl); - UNSERIALIZE_ARRAY(wsba, 4); - UNSERIALIZE_ARRAY(wsm, 4); - UNSERIALIZE_ARRAY(tba, 4); -} - -Tick -TsunamiPChip::cacheAccess(MemReqPtr &req) -{ - return curTick + pioLatency; -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiPChip) - - SimObjectParam<Tsunami *> tsunami; - SimObjectParam<MemoryController *> mmu; - Param<Addr> addr; - SimObjectParam<Bus*> pio_bus; - Param<Tick> pio_latency; - SimObjectParam<HierParams *> hier; - -END_DECLARE_SIM_OBJECT_PARAMS(TsunamiPChip) - -BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiPChip) - - INIT_PARAM(tsunami, "Tsunami"), - INIT_PARAM(mmu, "Memory Controller"), - INIT_PARAM(addr, "Device Address"), - INIT_PARAM_DFLT(pio_bus, "The IO Bus to attach to", NULL), - INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1), - INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams) - -END_INIT_SIM_OBJECT_PARAMS(TsunamiPChip) - -CREATE_SIM_OBJECT(TsunamiPChip) -{ - return new TsunamiPChip(getInstanceName(), tsunami, addr, mmu, hier, - pio_bus, pio_latency); -} - -REGISTER_SIM_OBJECT("TsunamiPChip", TsunamiPChip) diff --git a/dev/tsunami_pchip.hh b/dev/tsunami_pchip.hh deleted file mode 100644 index c1d95431b..000000000 --- a/dev/tsunami_pchip.hh +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** @file - * Tsunami PCI interface CSRs - */ - -#ifndef __TSUNAMI_PCHIP_HH__ -#define __TSUNAMI_PCHIP_HH__ - -#include "dev/tsunami.hh" -#include "base/range.hh" -#include "dev/io_device.hh" - -class MemoryController; - -/** - * A very simple implementation of the Tsunami PCI interface chips. - */ -class TsunamiPChip : public PioDevice -{ - private: - /** The base address of this device */ - Addr addr; - - /** The size of mappad from the above address */ - static const Addr size = 0xfff; - - protected: - /** - * pointer to the tsunami object. - * This is our access to all the other tsunami - * devices. - */ - Tsunami *tsunami; - - /** Pchip control register */ - uint64_t pctl; - - /** Window Base addresses */ - uint64_t wsba[4]; - - /** Window masks */ - uint64_t wsm[4]; - - /** Translated Base Addresses */ - uint64_t tba[4]; - - public: - /** - * Register the PChip with the mmu and init all wsba, wsm, and tba to 0 - * @param name the name of thes device - * @param t a pointer to the tsunami device - * @param a the address which we respond to - * @param mmu the mmu we are to register with - * @param hier object to store parameters universal the device hierarchy - * @param bus The bus that this device is attached to - */ - TsunamiPChip(const std::string &name, Tsunami *t, Addr a, - MemoryController *mmu, HierParams *hier, Bus *pio_bus, - Tick pio_latency); - - /** - * Translate a PCI bus address to a memory address for DMA. - * @todo Andrew says this needs to be fixed. What's wrong with it? - * @param busAddr PCI address to translate. - * @return memory system address - */ - Addr translatePciToDma(Addr busAddr); - - /** - * Process a read to the PChip. - * @param req Contains the address to read from. - * @param data A pointer to write the read data to. - * @return The fault condition of the access. - */ - virtual Fault read(MemReqPtr &req, uint8_t *data); - - /** - * Process a write to the PChip. - * @param req Contains the address to write to. - * @param data The data to write. - * @return The fault condition of the access. - */ - virtual Fault write(MemReqPtr &req, const uint8_t *data); - - /** - * Serialize this object to the given output stream. - * @param os The stream to serialize to. - */ - virtual void serialize(std::ostream &os); - - /** - * Reconstruct the state of this object from a checkpoint. - * @param cp The checkpoint use. - * @param section The section name of this object - */ - virtual void unserialize(Checkpoint *cp, const std::string §ion); - - /** - * Return how long this access will take. - * @param req the memory request to calcuate - * @return Tick when the request is done - */ - Tick cacheAccess(MemReqPtr &req); -}; - -#endif // __TSUNAMI_PCHIP_HH__ diff --git a/dev/uart.cc b/dev/uart.cc deleted file mode 100644 index b2eeb8e9f..000000000 --- a/dev/uart.cc +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** @file - * Implements a 8250 UART - */ - -#include <string> -#include <vector> - -#include "base/inifile.hh" -#include "base/str.hh" // for to_number -#include "base/trace.hh" -#include "dev/simconsole.hh" -#include "dev/uart.hh" -#include "dev/platform.hh" -#include "mem/bus/bus.hh" -#include "mem/bus/pio_interface.hh" -#include "mem/bus/pio_interface_impl.hh" -#include "mem/functional/memory_control.hh" -#include "sim/builder.hh" - -using namespace std; - -Uart::Uart(const string &name, SimConsole *c, MemoryController *mmu, Addr a, - Addr s, HierParams *hier, Bus *bus, Tick pio_latency, Platform *p) - : PioDevice(name, p), addr(a), size(s), cons(c) -{ - mmu->add_child(this, RangeSize(addr, size)); - - - if (bus) { - pioInterface = newPioInterface(name, hier, bus, this, - &Uart::cacheAccess); - pioInterface->addAddrRange(RangeSize(addr, size)); - pioLatency = pio_latency * bus->clockRate; - } - - status = 0; - - // set back pointers - cons->uart = this; - platform->uart = this; -} - -Tick -Uart::cacheAccess(MemReqPtr &req) -{ - return curTick + pioLatency; -} - -DEFINE_SIM_OBJECT_CLASS_NAME("Uart", Uart) - diff --git a/dev/uart.hh b/dev/uart.hh deleted file mode 100644 index 78b1dc68e..000000000 --- a/dev/uart.hh +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** @file - * Base class for UART - */ - -#ifndef __UART_HH__ -#define __UART_HH__ - -#include "base/range.hh" -#include "dev/io_device.hh" - -class SimConsole; -class MemoryController; -class Platform; - -const int RX_INT = 0x1; -const int TX_INT = 0x2; - - -class Uart : public PioDevice -{ - - protected: - int status; - Addr addr; - Addr size; - SimConsole *cons; - - public: - Uart(const std::string &name, SimConsole *c, MemoryController *mmu, - Addr a, Addr s, HierParams *hier, Bus *bus, Tick pio_latency, - Platform *p); - - virtual Fault read(MemReqPtr &req, uint8_t *data) = 0; - virtual Fault write(MemReqPtr &req, const uint8_t *data) = 0; - - - /** - * Inform the uart that there is data available. - */ - virtual void dataAvailable() = 0; - - - /** - * Return if we have an interrupt pending - * @return interrupt status - */ - bool intStatus() { return status ? true : false; } - - /** - * Return how long this access will take. - * @param req the memory request to calcuate - * @return Tick when the request is done - */ - Tick cacheAccess(MemReqPtr &req); -}; - -#endif // __UART_HH__ diff --git a/dev/uart8250.cc b/dev/uart8250.cc deleted file mode 100644 index 65bccee86..000000000 --- a/dev/uart8250.cc +++ /dev/null @@ -1,349 +0,0 @@ -/* - * Copyright (c) 2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** @file - * Implements a 8250 UART - */ - -#include <string> -#include <vector> - -#include "base/inifile.hh" -#include "base/str.hh" // for to_number -#include "base/trace.hh" -#include "dev/simconsole.hh" -#include "dev/uart8250.hh" -#include "dev/platform.hh" -#include "mem/bus/bus.hh" -#include "mem/bus/pio_interface.hh" -#include "mem/bus/pio_interface_impl.hh" -#include "mem/functional/memory_control.hh" -#include "sim/builder.hh" - -using namespace std; -using namespace TheISA; - -Uart8250::IntrEvent::IntrEvent(Uart8250 *u, int bit) - : Event(&mainEventQueue), uart(u) -{ - DPRINTF(Uart, "UART Interrupt Event Initilizing\n"); - intrBit = bit; -} - -const char * -Uart8250::IntrEvent::description() -{ - return "uart interrupt delay event"; -} - -void -Uart8250::IntrEvent::process() -{ - if (intrBit & uart->IER) { - DPRINTF(Uart, "UART InterEvent, interrupting\n"); - uart->platform->postConsoleInt(); - uart->status |= intrBit; - } - else - DPRINTF(Uart, "UART InterEvent, not interrupting\n"); - -} - -/* The linux serial driver (8250.c about line 1182) loops reading from - * the device until the device reports it has no more data to - * read. After a maximum of 255 iterations the code prints "serial8250 - * too much work for irq X," and breaks out of the loop. Since the - * simulated system is so much slower than the actual system, if a - * user is typing on the keyboard it is very easy for them to provide - * input at a fast enough rate to not allow the loop to exit and thus - * the error to be printed. This magic number provides a delay between - * the time the UART receives a character to send to the simulated - * system and the time it actually notifies the system it has a - * character to send to alleviate this problem. --Ali - */ -void -Uart8250::IntrEvent::scheduleIntr() -{ - static const Tick interval = (Tick)((Clock::Float::s / 2e9) * 450); - DPRINTF(Uart, "Scheduling IER interrupt for %#x, at cycle %lld\n", intrBit, - curTick + interval); - if (!scheduled()) - schedule(curTick + interval); - else - reschedule(curTick + interval); -} - - -Uart8250::Uart8250(const string &name, SimConsole *c, MemoryController *mmu, - Addr a, Addr s, HierParams *hier, Bus *pio_bus, - Tick pio_latency, Platform *p) - : Uart(name, c, mmu, a, s, hier, pio_bus, pio_latency, p), - txIntrEvent(this, TX_INT), rxIntrEvent(this, RX_INT) -{ - IER = 0; - DLAB = 0; - LCR = 0; - MCR = 0; - -} - -Fault -Uart8250::read(MemReqPtr &req, uint8_t *data) -{ - Addr daddr = req->paddr - (addr & EV5::PAddrImplMask); - DPRINTF(Uart, " read register %#x\n", daddr); - - assert(req->size == 1); - - switch (daddr) { - case 0x0: - if (!(LCR & 0x80)) { // read byte - if (cons->dataAvailable()) - cons->in(*data); - else { - *(uint8_t*)data = 0; - // A limited amount of these are ok. - DPRINTF(Uart, "empty read of RX register\n"); - } - status &= ~RX_INT; - platform->clearConsoleInt(); - - if (cons->dataAvailable() && (IER & UART_IER_RDI)) - rxIntrEvent.scheduleIntr(); - } else { // dll divisor latch - ; - } - break; - case 0x1: - if (!(LCR & 0x80)) { // Intr Enable Register(IER) - *(uint8_t*)data = IER; - } else { // DLM divisor latch MSB - ; - } - break; - case 0x2: // Intr Identification Register (IIR) - DPRINTF(Uart, "IIR Read, status = %#x\n", (uint32_t)status); - - if (status & RX_INT) /* Rx data interrupt has a higher priority */ - *(uint8_t*)data = IIR_RXID; - else if (status & TX_INT) - *(uint8_t*)data = IIR_TXID; - else - *(uint8_t*)data = IIR_NOPEND; - - //Tx interrupts are cleared on IIR reads - status &= ~TX_INT; - break; - case 0x3: // Line Control Register (LCR) - *(uint8_t*)data = LCR; - break; - case 0x4: // Modem Control Register (MCR) - break; - case 0x5: // Line Status Register (LSR) - uint8_t lsr; - lsr = 0; - // check if there are any bytes to be read - if (cons->dataAvailable()) - lsr = UART_LSR_DR; - lsr |= UART_LSR_TEMT | UART_LSR_THRE; - *(uint8_t*)data = lsr; - break; - case 0x6: // Modem Status Register (MSR) - *(uint8_t*)data = 0; - break; - case 0x7: // Scratch Register (SCR) - *(uint8_t*)data = 0; // doesn't exist with at 8250. - break; - default: - panic("Tried to access a UART port that doesn't exist\n"); - break; - } - - return NoFault; - -} - -Fault -Uart8250::write(MemReqPtr &req, const uint8_t *data) -{ - Addr daddr = req->paddr - (addr & EV5::PAddrImplMask); - - DPRINTF(Uart, " write register %#x value %#x\n", daddr, *(uint8_t*)data); - - switch (daddr) { - case 0x0: - if (!(LCR & 0x80)) { // write byte - cons->out(*(uint8_t *)data); - platform->clearConsoleInt(); - status &= ~TX_INT; - if (UART_IER_THRI & IER) - txIntrEvent.scheduleIntr(); - } else { // dll divisor latch - ; - } - break; - case 0x1: - if (!(LCR & 0x80)) { // Intr Enable Register(IER) - IER = *(uint8_t*)data; - if (UART_IER_THRI & IER) - { - DPRINTF(Uart, "IER: IER_THRI set, scheduling TX intrrupt\n"); - txIntrEvent.scheduleIntr(); - } - else - { - DPRINTF(Uart, "IER: IER_THRI cleared, descheduling TX intrrupt\n"); - if (txIntrEvent.scheduled()) - txIntrEvent.deschedule(); - if (status & TX_INT) - platform->clearConsoleInt(); - status &= ~TX_INT; - } - - if ((UART_IER_RDI & IER) && cons->dataAvailable()) { - DPRINTF(Uart, "IER: IER_RDI set, scheduling RX intrrupt\n"); - rxIntrEvent.scheduleIntr(); - } else { - DPRINTF(Uart, "IER: IER_RDI cleared, descheduling RX intrrupt\n"); - if (rxIntrEvent.scheduled()) - rxIntrEvent.deschedule(); - if (status & RX_INT) - platform->clearConsoleInt(); - status &= ~RX_INT; - } - } else { // DLM divisor latch MSB - ; - } - break; - case 0x2: // FIFO Control Register (FCR) - break; - case 0x3: // Line Control Register (LCR) - LCR = *(uint8_t*)data; - break; - case 0x4: // Modem Control Register (MCR) - if (*(uint8_t*)data == (UART_MCR_LOOP | 0x0A)) - MCR = 0x9A; - break; - case 0x7: // Scratch Register (SCR) - // We are emulating a 8250 so we don't have a scratch reg - break; - default: - panic("Tried to access a UART port that doesn't exist\n"); - break; - } - return NoFault; -} - -void -Uart8250::dataAvailable() -{ - // if the kernel wants an interrupt when we have data - if (IER & UART_IER_RDI) - { - platform->postConsoleInt(); - status |= RX_INT; - } - -} - - - -void -Uart8250::serialize(ostream &os) -{ - SERIALIZE_SCALAR(status); - SERIALIZE_SCALAR(IER); - SERIALIZE_SCALAR(DLAB); - SERIALIZE_SCALAR(LCR); - SERIALIZE_SCALAR(MCR); - Tick rxintrwhen; - if (rxIntrEvent.scheduled()) - rxintrwhen = rxIntrEvent.when(); - else - rxintrwhen = 0; - Tick txintrwhen; - if (txIntrEvent.scheduled()) - txintrwhen = txIntrEvent.when(); - else - txintrwhen = 0; - SERIALIZE_SCALAR(rxintrwhen); - SERIALIZE_SCALAR(txintrwhen); -} - -void -Uart8250::unserialize(Checkpoint *cp, const std::string §ion) -{ - UNSERIALIZE_SCALAR(status); - UNSERIALIZE_SCALAR(IER); - UNSERIALIZE_SCALAR(DLAB); - UNSERIALIZE_SCALAR(LCR); - UNSERIALIZE_SCALAR(MCR); - Tick rxintrwhen; - Tick txintrwhen; - UNSERIALIZE_SCALAR(rxintrwhen); - UNSERIALIZE_SCALAR(txintrwhen); - if (rxintrwhen != 0) - rxIntrEvent.schedule(rxintrwhen); - if (txintrwhen != 0) - txIntrEvent.schedule(txintrwhen); -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(Uart8250) - - SimObjectParam<SimConsole *> console; - SimObjectParam<MemoryController *> mmu; - SimObjectParam<Platform *> platform; - Param<Addr> addr; - Param<Addr> size; - SimObjectParam<Bus*> pio_bus; - Param<Tick> pio_latency; - SimObjectParam<HierParams *> hier; - - -END_DECLARE_SIM_OBJECT_PARAMS(Uart8250) - -BEGIN_INIT_SIM_OBJECT_PARAMS(Uart8250) - - INIT_PARAM(console, "The console"), - INIT_PARAM(mmu, "Memory Controller"), - INIT_PARAM(platform, "Pointer to platfrom"), - INIT_PARAM(addr, "Device Address"), - INIT_PARAM_DFLT(size, "Device size", 0x8), - INIT_PARAM(pio_bus, ""), - INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1), - INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams) - -END_INIT_SIM_OBJECT_PARAMS(Uart8250) - -CREATE_SIM_OBJECT(Uart8250) -{ - return new Uart8250(getInstanceName(), console, mmu, addr, size, hier, - pio_bus, pio_latency, platform); -} - -REGISTER_SIM_OBJECT("Uart8250", Uart8250) diff --git a/dev/uart8250.hh b/dev/uart8250.hh deleted file mode 100644 index 63d1da3cf..000000000 --- a/dev/uart8250.hh +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** @file - * Defines a 8250 UART - */ - -#ifndef __TSUNAMI_UART_HH__ -#define __TSUNAMI_UART_HH__ - -#include "dev/tsunamireg.h" -#include "base/range.hh" -#include "dev/io_device.hh" -#include "dev/uart.hh" - - -/* UART8250 Interrupt ID Register - * bit 0 Interrupt Pending 0 = true, 1 = false - * bit 2:1 ID of highest priority interrupt - * bit 7:3 zeroes - */ -#define IIR_NOPEND 0x1 - -// Interrupt IDs -#define IIR_MODEM 0x00 /* Modem Status (lowest priority) */ -#define IIR_TXID 0x02 /* Tx Data */ -#define IIR_RXID 0x04 /* Rx Data */ -#define IIR_LINE 0x06 /* Rx Line Status (highest priority)*/ - -class SimConsole; -class MemoryController; -class Platform; - -class Uart8250 : public Uart -{ - - - protected: - uint8_t IER, DLAB, LCR, MCR; - - class IntrEvent : public Event - { - protected: - Uart8250 *uart; - int intrBit; - public: - IntrEvent(Uart8250 *u, int bit); - virtual void process(); - virtual const char *description(); - void scheduleIntr(); - }; - - IntrEvent txIntrEvent; - IntrEvent rxIntrEvent; - - public: - Uart8250(const std::string &name, SimConsole *c, MemoryController *mmu, - Addr a, Addr s, HierParams *hier, Bus *pio_bus, Tick pio_latency, - Platform *p); - - virtual Fault read(MemReqPtr &req, uint8_t *data); - virtual Fault write(MemReqPtr &req, const uint8_t *data); - - - /** - * Inform the uart that there is data available. - */ - virtual void dataAvailable(); - - - /** - * Return if we have an interrupt pending - * @return interrupt status - */ - virtual bool intStatus() { return status ? true : false; } - - virtual void serialize(std::ostream &os); - virtual void unserialize(Checkpoint *cp, const std::string §ion); - -}; - -#endif // __TSUNAMI_UART_HH__ diff --git a/encumbered/cpu/full/op_class.hh b/encumbered/cpu/full/op_class.hh deleted file mode 100644 index ff53b58d2..000000000 --- a/encumbered/cpu/full/op_class.hh +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __ENCUMBERED_CPU_FULL_OP_CLASS_HH__ -#define __ENCUMBERED_CPU_FULL_OP_CLASS_HH__ - -/** - * @file - * Definition of operation classes. - */ - -/** - * Instruction operation classes. These classes are used for - * assigning instructions to functional units. - */ -enum OpClass { - No_OpClass = 0, /* inst does not use a functional unit */ - IntAluOp, /* integer ALU */ - IntMultOp, /* integer multiplier */ - IntDivOp, /* integer divider */ - FloatAddOp, /* floating point adder/subtractor */ - FloatCmpOp, /* floating point comparator */ - FloatCvtOp, /* floating point<->integer converter */ - FloatMultOp, /* floating point multiplier */ - FloatDivOp, /* floating point divider */ - FloatSqrtOp, /* floating point square root */ - MemReadOp, /* memory read port */ - MemWriteOp, /* memory write port */ - IprAccessOp, /* Internal Processor Register read/write port */ - InstPrefetchOp, /* instruction prefetch port (on I-cache) */ - Num_OpClasses /* total functional unit classes */ -}; - -/** - * Array mapping OpClass enum values to strings. Defined in fu_pool.cc. - */ -extern const char *opClassStrings[]; - -#endif // __ENCUMBERED_CPU_FULL_OP_CLASS_HH__ diff --git a/ext/dnet/LICENSE b/ext/dnet/LICENSE new file mode 100644 index 000000000..95ecd51e6 --- /dev/null +++ b/ext/dnet/LICENSE @@ -0,0 +1,28 @@ + + Copyright (c) 2000-2004 Dug Song <dugsong@monkey.org> + All rights reserved, all wrongs reversed. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The names of the authors and copyright holders may not be used to + endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/ext/dnet/dnet/addr.h b/ext/dnet/dnet/addr.h new file mode 100644 index 000000000..584e3aba3 --- /dev/null +++ b/ext/dnet/dnet/addr.h @@ -0,0 +1,67 @@ +/* + * addr.h + * + * Network address operations. + * + * Copyright (c) 2000 Dug Song <dugsong@monkey.org> + * + * $Id: addr.h,v 1.12 2003/02/27 03:44:55 dugsong Exp $ + */ + +#ifndef DNET_ADDR_H +#define DNET_ADDR_H + +#define ADDR_TYPE_NONE 0 /* No address set */ +#define ADDR_TYPE_ETH 1 /* Ethernet */ +#define ADDR_TYPE_IP 2 /* Internet Protocol v4 */ +#define ADDR_TYPE_IP6 3 /* Internet Protocol v6 */ + +struct addr { + uint16_t addr_type; + uint16_t addr_bits; + union { + eth_addr_t __eth; + ip_addr_t __ip; + ip6_addr_t __ip6; + + uint8_t __data8[16]; + uint16_t __data16[8]; + uint32_t __data32[4]; + } __addr_u; +}; +#define addr_eth __addr_u.__eth +#define addr_ip __addr_u.__ip +#define addr_ip6 __addr_u.__ip6 +#define addr_data8 __addr_u.__data8 +#define addr_data16 __addr_u.__data16 +#define addr_data32 __addr_u.__data32 + +#define addr_pack(addr, type, bits, data, len) do { \ + (addr)->addr_type = type; \ + (addr)->addr_bits = bits; \ + memmove((addr)->addr_data8, (char *)data, len); \ +} while (0) + +__BEGIN_DECLS +int addr_cmp(const struct addr *a, const struct addr *b); + +int addr_bcast(const struct addr *a, struct addr *b); +int addr_net(const struct addr *a, struct addr *b); + +char *addr_ntop(const struct addr *src, char *dst, size_t size); +int addr_pton(const char *src, struct addr *dst); + +char *addr_ntoa(const struct addr *a); +#define addr_aton addr_pton + +int addr_ntos(const struct addr *a, struct sockaddr *sa); +int addr_ston(const struct sockaddr *sa, struct addr *a); + +int addr_btos(uint16_t bits, struct sockaddr *sa); +int addr_stob(const struct sockaddr *sa, uint16_t *bits); + +int addr_btom(uint16_t bits, void *mask, size_t size); +int addr_mtob(const void *mask, size_t size, uint16_t *bits); +__END_DECLS + +#endif /* DNET_ADDR_H */ diff --git a/ext/dnet/dnet/arp.h b/ext/dnet/dnet/arp.h new file mode 100644 index 000000000..d3c162410 --- /dev/null +++ b/ext/dnet/dnet/arp.h @@ -0,0 +1,103 @@ +/* + * arp.h + * + * Address Resolution Protocol. + * RFC 826 + * + * Copyright (c) 2000 Dug Song <dugsong@monkey.org> + * + * $Id: arp.h,v 1.12 2003/03/16 17:39:17 dugsong Exp $ + */ + +#ifndef DNET_ARP_H +#define DNET_ARP_H + +#define ARP_HDR_LEN 8 /* base ARP header length */ +#define ARP_ETHIP_LEN 20 /* base ARP message length */ + +#ifndef __GNUC__ +# define __attribute__(x) +# pragma pack(1) +#endif + +/* + * ARP header + */ +struct arp_hdr { + uint16_t ar_hrd; /* format of hardware address */ + uint16_t ar_pro; /* format of protocol address */ + uint8_t ar_hln; /* length of hardware address (ETH_ADDR_LEN) */ + uint8_t ar_pln; /* length of protocol address (IP_ADDR_LEN) */ + uint16_t ar_op; /* operation */ +}; + +/* + * Hardware address format + */ +#define ARP_HRD_ETH 0x0001 /* ethernet hardware */ +#define ARP_HRD_IEEE802 0x0006 /* IEEE 802 hardware */ + +/* + * Protocol address format + */ +#define ARP_PRO_IP 0x0800 /* IP protocol */ + +/* + * ARP operation + */ +#define ARP_OP_REQUEST 1 /* request to resolve ha given pa */ +#define ARP_OP_REPLY 2 /* response giving hardware address */ +#define ARP_OP_REVREQUEST 3 /* request to resolve pa given ha */ +#define ARP_OP_REVREPLY 4 /* response giving protocol address */ + +/* + * Ethernet/IP ARP message + */ +struct arp_ethip { + uint8_t ar_sha[ETH_ADDR_LEN]; /* sender hardware address */ + uint8_t ar_spa[IP_ADDR_LEN]; /* sender protocol address */ + uint8_t ar_tha[ETH_ADDR_LEN]; /* target hardware address */ + uint8_t ar_tpa[IP_ADDR_LEN]; /* target protocol address */ +}; + +/* + * ARP cache entry + */ +struct arp_entry { + struct addr arp_pa; /* protocol address */ + struct addr arp_ha; /* hardware address */ +}; + +#ifndef __GNUC__ +# pragma pack() +#endif + +#define arp_pack_hdr_ethip(hdr, op, sha, spa, tha, tpa) do { \ + struct arp_hdr *pack_arp_p = (struct arp_hdr *)(hdr); \ + struct arp_ethip *pack_ethip_p = (struct arp_ethip *) \ + ((uint8_t *)(hdr) + ARP_HDR_LEN); \ + pack_arp_p->ar_hrd = htons(ARP_HRD_ETH); \ + pack_arp_p->ar_pro = htons(ARP_PRO_IP); \ + pack_arp_p->ar_hln = ETH_ADDR_LEN; \ + pack_arp_p->ar_pln = IP_ADDR_LEN; \ + pack_arp_p->ar_op = htons(op); \ + memmove(pack_ethip_p->ar_sha, &(sha), ETH_ADDR_LEN); \ + memmove(pack_ethip_p->ar_spa, &(spa), IP_ADDR_LEN); \ + memmove(pack_ethip_p->ar_tha, &(tha), ETH_ADDR_LEN); \ + memmove(pack_ethip_p->ar_tpa, &(tpa), IP_ADDR_LEN); \ +} while (0) + +typedef struct arp_handle arp_t; + +typedef int (*arp_handler)(const struct arp_entry *entry, void *arg); + +__BEGIN_DECLS +arp_t *arp_open(void); +int arp_add(arp_t *arp, const struct arp_entry *entry); +int arp_delete(arp_t *arp, const struct arp_entry *entry); +int arp_get(arp_t *arp, struct arp_entry *entry); +int arp_loop(arp_t *arp, arp_handler callback, void *arg); +arp_t *arp_close(arp_t *arp); +__END_DECLS + +#endif /* DNET_ARP_H */ diff --git a/ext/dnet/dnet/blob.h b/ext/dnet/dnet/blob.h new file mode 100644 index 000000000..a3be7897d --- /dev/null +++ b/ext/dnet/dnet/blob.h @@ -0,0 +1,56 @@ +/* + * blob.h + * + * Binary blob handling. + * + * Copyright (c) 2002 Dug Song <dugsong@monkey.org> + * + * $Id: blob.h,v 1.2 2002/04/05 03:06:44 dugsong Exp $ + */ + +#ifndef DNET_BLOB_H +#define DNET_BLOB_H + +typedef struct blob { + u_char *base; /* start of data */ + int off; /* offset into data */ + int end; /* end of data */ + int size; /* size of allocation */ +} blob_t; + +__BEGIN_DECLS +blob_t *blob_new(void); + +int blob_read(blob_t *b, void *buf, int len); +int blob_write(blob_t *b, const void *buf, int len); + +int blob_seek(blob_t *b, int off, int whence); +#define blob_skip(b, l) blob_seek(b, l, SEEK_CUR) +#define blob_rewind(b) blob_seek(b, 0, SEEK_SET) + +#define blob_offset(b) ((b)->off) +#define blob_left(b) ((b)->end - (b)->off) + +int blob_index(blob_t *b, const void *buf, int len); +int blob_rindex(blob_t *b, const void *buf, int len); + +int blob_pack(blob_t *b, const char *fmt, ...); +int blob_unpack(blob_t *b, const char *fmt, ...); + +int blob_insert(blob_t *b, const void *buf, int len); +int blob_delete(blob_t *b, void *buf, int len); + +int blob_print(blob_t *b, char *style, int len); + +blob_t *blob_free(blob_t *b); + +int blob_register_alloc(size_t size, void *(*bmalloc)(size_t), + void (*bfree)(void *), void *(*brealloc)(void *, size_t)); +#ifdef va_start +typedef int (*blob_fmt_cb)(int pack, int len, blob_t *b, va_list *arg); + +int blob_register_pack(char c, blob_fmt_cb fmt_cb); +#endif +__END_DECLS + +#endif /* DNET_BLOB_H */ diff --git a/ext/dnet/dnet/eth.h b/ext/dnet/dnet/eth.h new file mode 100644 index 000000000..da3033066 --- /dev/null +++ b/ext/dnet/dnet/eth.h @@ -0,0 +1,77 @@ +/* + * eth.h + * + * Ethernet. + * + * Copyright (c) 2000 Dug Song <dugsong@monkey.org> + * + * $Id: eth.h,v 1.15 2004/01/03 08:47:23 dugsong Exp $ + */ + +#ifndef DNET_ETH_H +#define DNET_ETH_H + +#define ETH_ADDR_LEN 6 +#define ETH_ADDR_BITS 48 +#define ETH_TYPE_LEN 2 +#define ETH_CRC_LEN 4 +#define ETH_HDR_LEN 14 + +#define ETH_LEN_MIN 64 /* minimum frame length with CRC */ +#define ETH_LEN_MAX 1518 /* maximum frame length with CRC */ + +#define ETH_MTU (ETH_LEN_MAX - ETH_HDR_LEN - ETH_CRC_LEN) +#define ETH_MIN (ETH_LEN_MIN - ETH_HDR_LEN - ETH_CRC_LEN) + +typedef struct eth_addr { + uint8_t data[ETH_ADDR_LEN]; +} eth_addr_t; + +struct eth_hdr { + eth_addr_t eth_dst; /* destination address */ + eth_addr_t eth_src; /* source address */ + uint16_t eth_type; /* payload type */ +}; + +/* + * Ethernet payload types - http://standards.ieee.org/regauth/ethertype + */ +#define ETH_TYPE_PUP 0x0200 /* PUP protocol */ +#define ETH_TYPE_IP 0x0800 /* IP protocol */ +#define ETH_TYPE_ARP 0x0806 /* address resolution protocol */ +#define ETH_TYPE_REVARP 0x8035 /* reverse addr resolution protocol */ +#define ETH_TYPE_8021Q 0x8100 /* IEEE 802.1Q VLAN tagging */ +#define ETH_TYPE_IPV6 0x86DD /* IPv6 protocol */ +#define ETH_TYPE_MPLS 0x8847 /* MPLS */ +#define ETH_TYPE_MPLS_MCAST 0x8848 /* MPLS Multicast */ +#define ETH_TYPE_PPPOEDISC 0x8863 /* PPP Over Ethernet Discovery Stage */ +#define ETH_TYPE_PPPOE 0x8864 /* PPP Over Ethernet Session Stage */ +#define ETH_TYPE_LOOPBACK 0x9000 /* used to test interfaces */ + +#define ETH_IS_MULTICAST(ea) (*(ea) & 0x01) /* is address mcast/bcast? */ + +#define ETH_ADDR_BROADCAST "\xff\xff\xff\xff\xff\xff" + +#define eth_pack_hdr(h, dst, src, type) do { \ + struct eth_hdr *eth_pack_p = (struct eth_hdr *)(h); \ + memmove(ð_pack_p->eth_dst, &(dst), ETH_ADDR_LEN); \ + memmove(ð_pack_p->eth_src, &(src), ETH_ADDR_LEN); \ + eth_pack_p->eth_type = htons(type); \ +} while (0) + +typedef struct eth_handle eth_t; + +__BEGIN_DECLS +eth_t *eth_open(const char *device); +int eth_get(eth_t *e, eth_addr_t *ea); +int eth_set(eth_t *e, const eth_addr_t *ea); +size_t eth_send(eth_t *e, const void *buf, size_t len); +eth_t *eth_close(eth_t *e); + +char *eth_ntop(const eth_addr_t *eth, char *dst, size_t len); +int eth_pton(const char *src, eth_addr_t *dst); +char *eth_ntoa(const eth_addr_t *eth); +#define eth_aton eth_pton +__END_DECLS + +#endif /* DNET_ETH_H */ diff --git a/ext/dnet/dnet/fw.h b/ext/dnet/dnet/fw.h new file mode 100644 index 000000000..ebda8e7eb --- /dev/null +++ b/ext/dnet/dnet/fw.h @@ -0,0 +1,54 @@ +/* + * fw.h + * + * Network firewalling operations. + * + * Copyright (c) 2001 Dug Song <dugsong@monkey.org> + * + * $Id: fw.h,v 1.13 2002/12/14 04:02:36 dugsong Exp $ + */ + +#ifndef DNET_FW_H +#define DNET_FW_H + +struct fw_rule { + char fw_device[INTF_NAME_LEN]; /* interface name */ + uint8_t fw_op; /* operation */ + uint8_t fw_dir; /* direction */ + uint8_t fw_proto; /* IP protocol */ + struct addr fw_src; /* src address / net */ + struct addr fw_dst; /* dst address / net */ + uint16_t fw_sport[2]; /* range / ICMP type */ + uint16_t fw_dport[2]; /* range / ICMP code */ +}; + +#define FW_OP_ALLOW 1 +#define FW_OP_BLOCK 2 + +#define FW_DIR_IN 1 +#define FW_DIR_OUT 2 + +#define fw_pack_rule(rule, dev, op, dir, p, s, d, sp1, sp2, dp1, dp2) \ +do { \ + strlcpy((rule)->fw_device, dev, sizeof((rule)->fw_device)); \ + (rule)->fw_op = op; (rule)->fw_dir = dir; \ + (rule)->fw_proto = p; \ + memmove(&(rule)->fw_src, &(s), sizeof((rule)->fw_src)); \ + memmove(&(rule)->fw_dst, &(d), sizeof((rule)->fw_dst)); \ + (rule)->fw_sport[0] = sp1; (rule)->fw_sport[1] = sp2; \ + (rule)->fw_dport[0] = dp1; (rule)->fw_dport[1] = dp2; \ +} while (0) + +typedef struct fw_handle fw_t; + +typedef int (*fw_handler)(const struct fw_rule *rule, void *arg); + +__BEGIN_DECLS +fw_t *fw_open(void); +int fw_add(fw_t *f, const struct fw_rule *rule); +int fw_delete(fw_t *f, const struct fw_rule *rule); +int fw_loop(fw_t *f, fw_handler callback, void *arg); +fw_t *fw_close(fw_t *f); +__END_DECLS + +#endif /* DNET_FW_H */ diff --git a/ext/dnet/dnet/icmp.h b/ext/dnet/dnet/icmp.h new file mode 100644 index 000000000..e997d5887 --- /dev/null +++ b/ext/dnet/dnet/icmp.h @@ -0,0 +1,265 @@ +/* + * icmp.h + * + * Internet Control Message Protocol. + * RFC 792, 950, 1256, 1393, 1475, 2002, 2521 + * + * Copyright (c) 2000 Dug Song <dugsong@monkey.org> + * + * $Id: icmp.h,v 1.14 2003/03/16 17:39:17 dugsong Exp $ + */ + +#ifndef DNET_ICMP_H +#define DNET_ICMP_H + +#define ICMP_HDR_LEN 4 /* base ICMP header length */ +#define ICMP_LEN_MIN 8 /* minimum ICMP message size, with header */ + +#ifndef __GNUC__ +# define __attribute__(x) +# pragma pack(1) +#endif + +/* + * ICMP header + */ +struct icmp_hdr { + uint8_t icmp_type; /* type of message, see below */ + uint8_t icmp_code; /* type sub code */ + uint16_t icmp_cksum; /* ones complement cksum of struct */ +}; + +/* + * Types (icmp_type) and codes (icmp_code) - + * http://www.iana.org/assignments/icmp-parameters + */ +#define ICMP_CODE_NONE 0 /* for types without codes */ +#define ICMP_ECHOREPLY 0 /* echo reply */ +#define ICMP_UNREACH 3 /* dest unreachable, codes: */ +#define ICMP_UNREACH_NET 0 /* bad net */ +#define ICMP_UNREACH_HOST 1 /* bad host */ +#define ICMP_UNREACH_PROTO 2 /* bad protocol */ +#define ICMP_UNREACH_PORT 3 /* bad port */ +#define ICMP_UNREACH_NEEDFRAG 4 /* IP_DF caused drop */ +#define ICMP_UNREACH_SRCFAIL 5 /* src route failed */ +#define ICMP_UNREACH_NET_UNKNOWN 6 /* unknown net */ +#define ICMP_UNREACH_HOST_UNKNOWN 7 /* unknown host */ +#define ICMP_UNREACH_ISOLATED 8 /* src host isolated */ +#define ICMP_UNREACH_NET_PROHIB 9 /* for crypto devs */ +#define ICMP_UNREACH_HOST_PROHIB 10 /* ditto */ +#define ICMP_UNREACH_TOSNET 11 /* bad tos for net */ +#define ICMP_UNREACH_TOSHOST 12 /* bad tos for host */ +#define ICMP_UNREACH_FILTER_PROHIB 13 /* prohibited access */ +#define ICMP_UNREACH_HOST_PRECEDENCE 14 /* precedence error */ +#define ICMP_UNREACH_PRECEDENCE_CUTOFF 15 /* precedence cutoff */ +#define ICMP_SRCQUENCH 4 /* packet lost, slow down */ +#define ICMP_REDIRECT 5 /* shorter route, codes: */ +#define ICMP_REDIRECT_NET 0 /* for network */ +#define ICMP_REDIRECT_HOST 1 /* for host */ +#define ICMP_REDIRECT_TOSNET 2 /* for tos and net */ +#define ICMP_REDIRECT_TOSHOST 3 /* for tos and host */ +#define ICMP_ALTHOSTADDR 6 /* alternate host address */ +#define ICMP_ECHO 8 /* echo service */ +#define ICMP_RTRADVERT 9 /* router advertise, codes: */ +#define ICMP_RTRADVERT_NORMAL 0 /* normal */ +#define ICMP_RTRADVERT_NOROUTE_COMMON 16 /* selective routing */ +#define ICMP_RTRSOLICIT 10 /* router solicitation */ +#define ICMP_TIMEXCEED 11 /* time exceeded, code: */ +#define ICMP_TIMEXCEED_INTRANS 0 /* ttl==0 in transit */ +#define ICMP_TIMEXCEED_REASS 1 /* ttl==0 in reass */ +#define ICMP_PARAMPROB 12 /* ip header bad */ +#define ICMP_PARAMPROB_ERRATPTR 0 /* req. opt. absent */ +#define ICMP_PARAMPROB_OPTABSENT 1 /* req. opt. absent */ +#define ICMP_PARAMPROB_LENGTH 2 /* bad length */ +#define ICMP_TSTAMP 13 /* timestamp request */ +#define ICMP_TSTAMPREPLY 14 /* timestamp reply */ +#define ICMP_INFO 15 /* information request */ +#define ICMP_INFOREPLY 16 /* information reply */ +#define ICMP_MASK 17 /* address mask request */ +#define ICMP_MASKREPLY 18 /* address mask reply */ +#define ICMP_TRACEROUTE 30 /* traceroute */ +#define ICMP_DATACONVERR 31 /* data conversion error */ +#define ICMP_MOBILE_REDIRECT 32 /* mobile host redirect */ +#define ICMP_IPV6_WHEREAREYOU 33 /* IPv6 where-are-you */ +#define ICMP_IPV6_IAMHERE 34 /* IPv6 i-am-here */ +#define ICMP_MOBILE_REG 35 /* mobile registration req */ +#define ICMP_MOBILE_REGREPLY 36 /* mobile registration reply */ +#define ICMP_DNS 37 /* domain name request */ +#define ICMP_DNSREPLY 38 /* domain name reply */ +#define ICMP_SKIP 39 /* SKIP */ +#define ICMP_PHOTURIS 40 /* Photuris */ +#define ICMP_PHOTURIS_UNKNOWN_INDEX 0 /* unknown sec index */ +#define ICMP_PHOTURIS_AUTH_FAILED 1 /* auth failed */ +#define ICMP_PHOTURIS_DECOMPRESS_FAILED 2 /* decompress failed */ +#define ICMP_PHOTURIS_DECRYPT_FAILED 3 /* decrypt failed */ +#define ICMP_PHOTURIS_NEED_AUTHN 4 /* no authentication */ +#define ICMP_PHOTURIS_NEED_AUTHZ 5 /* no authorization */ +#define ICMP_TYPE_MAX 40 + +#define ICMP_INFOTYPE(type) \ + ((type) == ICMP_ECHOREPLY || (type) == ICMP_ECHO || \ + (type) == ICMP_RTRADVERT || (type) == ICMP_RTRSOLICIT || \ + (type) == ICMP_TSTAMP || (type) == ICMP_TSTAMPREPLY || \ + (type) == ICMP_INFO || (type) == ICMP_INFOREPLY || \ + (type) == ICMP_MASK || (type) == ICMP_MASKREPLY) + +/* + * Echo message data + */ +struct icmp_msg_echo { + uint16_t icmp_id; + uint16_t icmp_seq; + uint8_t icmp_data __flexarr; /* optional data */ +}; + +/* + * Fragmentation-needed (unreachable) message data + */ +struct icmp_msg_needfrag { + uint16_t icmp_void; /* must be zero */ + uint16_t icmp_mtu; /* MTU of next-hop network */ + uint8_t icmp_ip __flexarr; /* IP hdr + 8 bytes of pkt */ +}; + +/* + * Unreachable, source quench, redirect, time exceeded, + * parameter problem message data + */ +struct icmp_msg_quote { + uint32_t icmp_void; /* must be zero */ +#define icmp_gwaddr icmp_void /* router IP address to use */ +#define icmp_pptr icmp_void /* ptr to bad octet field */ + uint8_t icmp_ip __flexarr; /* IP hdr + 8 bytes of pkt */ +}; + +/* + * Router advertisement message data, RFC 1256 + */ +struct icmp_msg_rtradvert { + uint8_t icmp_num_addrs; /* # of address / pref pairs */ + uint8_t icmp_wpa; /* words / address == 2 */ + uint16_t icmp_lifetime; /* route lifetime in seconds */ + struct icmp_msg_rtr_data { + uint32_t icmp_void; +#define icmp_gwaddr icmp_void /* router IP address */ + uint32_t icmp_pref; /* router preference (usu 0) */ + } icmp_rtr __flexarr; /* variable # of routers */ +}; +#define ICMP_RTR_PREF_NODEFAULT 0x80000000 /* do not use as default gw */ + +/* + * Timestamp message data + */ +struct icmp_msg_tstamp { + uint32_t icmp_id; /* identifier */ + uint32_t icmp_seq; /* sequence number */ + uint32_t icmp_ts_orig; /* originate timestamp */ + uint32_t icmp_ts_rx; /* receive timestamp */ + uint32_t icmp_ts_tx; /* transmit timestamp */ +}; + +/* + * Address mask message data, RFC 950 + */ +struct icmp_msg_mask { + uint32_t icmp_id; /* identifier */ + uint32_t icmp_seq; /* sequence number */ + uint32_t icmp_mask; /* address mask */ +}; + +/* + * Traceroute message data, RFC 1393, RFC 1812 + */ +struct icmp_msg_traceroute { + uint16_t icmp_id; /* identifier */ + uint16_t icmp_void; /* unused */ + uint16_t icmp_ohc; /* outbound hop count */ + uint16_t icmp_rhc; /* return hop count */ + uint32_t icmp_speed; /* link speed, bytes/sec */ + uint32_t icmp_mtu; /* MTU in bytes */ +}; + +/* + * Domain name reply message data, RFC 1788 + */ +struct icmp_msg_dnsreply { + uint16_t icmp_id; /* identifier */ + uint16_t icmp_seq; /* sequence number */ + uint32_t icmp_ttl; /* time-to-live */ + uint8_t icmp_names __flexarr; /* variable number of names */ +}; + +/* + * Generic identifier, sequence number data + */ +struct icmp_msg_idseq { + uint16_t icmp_id; + uint16_t icmp_seq; +}; + +/* + * ICMP message union + */ +union icmp_msg { + struct icmp_msg_echo echo; /* ICMP_ECHO{REPLY} */ + struct icmp_msg_quote unreach; /* ICMP_UNREACH */ + struct icmp_msg_needfrag needfrag; /* ICMP_UNREACH_NEEDFRAG */ + struct icmp_msg_quote srcquench; /* ICMP_SRCQUENCH */ + struct icmp_msg_quote redirect; /* ICMP_REDIRECT (set to 0) */ + uint32_t rtrsolicit; /* ICMP_RTRSOLICIT */ + struct icmp_msg_rtradvert rtradvert; /* ICMP_RTRADVERT */ + struct icmp_msg_quote timexceed; /* ICMP_TIMEXCEED */ + struct icmp_msg_quote paramprob; /* ICMP_PARAMPROB */ + struct icmp_msg_tstamp tstamp; /* ICMP_TSTAMP{REPLY} */ + struct icmp_msg_idseq info; /* ICMP_INFO{REPLY} */ + struct icmp_msg_mask mask; /* ICMP_MASK{REPLY} */ + struct icmp_msg_traceroute traceroute; /* ICMP_TRACEROUTE */ + struct icmp_msg_idseq dns; /* ICMP_DNS */ + struct icmp_msg_dnsreply dnsreply; /* ICMP_DNSREPLY */ +}; + +#ifndef __GNUC__ +# pragma pack() +#endif + +#define icmp_pack_hdr(hdr, type, code) do { \ + struct icmp_hdr *icmp_pack_p = (struct icmp_hdr *)(hdr); \ + icmp_pack_p->icmp_type = type; icmp_pack_p->icmp_code = code; \ +} while (0) + +#define icmp_pack_hdr_echo(hdr, type, code, id, seq, data, len) do { \ + struct icmp_msg_echo *echo_pack_p = (struct icmp_msg_echo *) \ + ((uint8_t *)(hdr) + ICMP_HDR_LEN); \ + icmp_pack_hdr(hdr, type, code); \ + echo_pack_p->icmp_id = htons(id); \ + echo_pack_p->icmp_seq = htons(seq); \ + memmove(echo_pack_p->icmp_data, data, len); \ +} while (0) + +#define icmp_pack_hdr_quote(hdr, type, code, word, pkt, len) do { \ + struct icmp_msg_quote *quote_pack_p = (struct icmp_msg_quote *) \ + ((uint8_t *)(hdr) + ICMP_HDR_LEN); \ + icmp_pack_hdr(hdr, type, code); \ + quote_pack_p->icmp_void = htonl(word); \ + memmove(quote_pack_p->icmp_ip, pkt, len); \ +} while (0) + +#define icmp_pack_hdr_mask(hdr, type, code, id, seq, mask) do { \ + struct icmp_msg_mask *mask_pack_p = (struct icmp_msg_mask *) \ + ((uint8_t *)(hdr) + ICMP_HDR_LEN); \ + icmp_pack_hdr(hdr, type, code); \ + mask_pack_p->icmp_id = htons(id); \ + mask_pack_p->icmp_seq = htons(seq); \ + mask_pack_p->icmp_mask = htonl(mask); \ +} while (0) + +#define icmp_pack_hdr_needfrag(hdr, type, code, mtu, pkt, len) do { \ + struct icmp_msg_needfrag *frag_pack_p = \ + (struct icmp_msg_needfrag *)((uint8_t *)(hdr) + ICMP_HDR_LEN); \ + icmp_pack_hdr(hdr, type, code); \ + frag_pack_p->icmp_void = 0; \ + frag_pack_p->icmp_mtu = htons(mtu); \ + memmove(frag_pack_p->icmp_ip, pkt, len); \ +} while (0) + +#endif /* DNET_ICMP_H */ diff --git a/ext/dnet/dnet/intf.h b/ext/dnet/dnet/intf.h new file mode 100644 index 000000000..38acd4356 --- /dev/null +++ b/ext/dnet/dnet/intf.h @@ -0,0 +1,68 @@ +/* + * intf.c + * + * Network interface operations. + * + * Copyright (c) 2000 Dug Song <dugsong@monkey.org> + * + * $Id: intf.h,v 1.16 2004/01/13 07:41:09 dugsong Exp $ + */ + +#ifndef DNET_INTF_H +#define DNET_INTF_H + +/* + * Interface entry + */ +#define INTF_NAME_LEN 16 + +struct intf_entry { + u_int intf_len; /* length of entry */ + char intf_name[INTF_NAME_LEN]; /* interface name */ + u_short intf_type; /* interface type (r/o) */ + u_short intf_flags; /* interface flags */ + u_int intf_mtu; /* interface MTU */ + struct addr intf_addr; /* interface address */ + struct addr intf_dst_addr; /* point-to-point dst */ + struct addr intf_link_addr; /* link-layer address */ + u_int intf_alias_num; /* number of aliases */ + struct addr intf_alias_addrs __flexarr; /* array of aliases */ +}; + +/* + * MIB-II interface types - http://www.iana.org/assignments/ianaiftype-mib + */ +#define INTF_TYPE_OTHER 1 /* other */ +#define INTF_TYPE_ETH 6 /* Ethernet */ +#define INTF_TYPE_TOKENRING 9 /* Token Ring */ +#define INTF_TYPE_FDDI 15 /* FDDI */ +#define INTF_TYPE_PPP 23 /* Point-to-Point Protocol */ +#define INTF_TYPE_LOOPBACK 24 /* software loopback */ +#define INTF_TYPE_SLIP 28 /* Serial Line Interface Protocol */ +#define INTF_TYPE_TUN 53 /* proprietary virtual/internal */ + +/* + * Interface flags + */ +#define INTF_FLAG_UP 0x01 /* enable interface */ +#define INTF_FLAG_LOOPBACK 0x02 /* is a loopback net (r/o) */ +#define INTF_FLAG_POINTOPOINT 0x04 /* point-to-point link (r/o) */ +#define INTF_FLAG_NOARP 0x08 /* disable ARP */ +#define INTF_FLAG_BROADCAST 0x10 /* supports broadcast (r/o) */ +#define INTF_FLAG_MULTICAST 0x20 /* supports multicast (r/o) */ + +typedef struct intf_handle intf_t; + +typedef int (*intf_handler)(const struct intf_entry *entry, void *arg); + +__BEGIN_DECLS +intf_t *intf_open(void); +int intf_get(intf_t *i, struct intf_entry *entry); +int intf_get_src(intf_t *i, struct intf_entry *entry, struct addr *src); +int intf_get_dst(intf_t *i, struct intf_entry *entry, struct addr *dst); +int intf_set(intf_t *i, const struct intf_entry *entry); +int intf_loop(intf_t *i, intf_handler callback, void *arg); +intf_t *intf_close(intf_t *i); +__END_DECLS + +#endif /* DNET_INTF_H */ diff --git a/ext/dnet/dnet/ip.h b/ext/dnet/dnet/ip.h new file mode 100644 index 000000000..95b7718fb --- /dev/null +++ b/ext/dnet/dnet/ip.h @@ -0,0 +1,487 @@ +/* + * ip.h + * + * Internet Protocol (RFC 791). + * + * Copyright (c) 2000 Dug Song <dugsong@monkey.org> + * + * $Id: ip.h,v 1.23 2003/03/16 17:39:17 dugsong Exp $ + */ + +#ifndef DNET_IP_H +#define DNET_IP_H + +#define IP_ADDR_LEN 4 /* IP address length */ +#define IP_ADDR_BITS 32 /* IP address bits */ + +#define IP_HDR_LEN 20 /* base IP header length */ +#define IP_OPT_LEN 2 /* base IP option length */ +#define IP_OPT_LEN_MAX 40 +#define IP_HDR_LEN_MAX (IP_HDR_LEN + IP_OPT_LEN_MAX) + +#define IP_LEN_MAX 65535 +#define IP_LEN_MIN IP_HDR_LEN + +typedef uint32_t ip_addr_t; + +#ifndef __GNUC__ +# define __attribute__(x) +# pragma pack(1) +#endif + +/* + * IP header, without options + */ +struct ip_hdr { +#if DNET_BYTESEX == DNET_BIG_ENDIAN + uint8_t ip_v:4, /* version */ + ip_hl:4; /* header length (incl any options) */ +#elif DNET_BYTESEX == DNET_LIL_ENDIAN + uint8_t ip_hl:4, + ip_v:4; +#else +# error "need to include <dnet.h>" +#endif + uint8_t ip_tos; /* type of service */ + uint16_t ip_len; /* total length (incl header) */ + uint16_t ip_id; /* identification */ + uint16_t ip_off; /* fragment offset and flags */ + uint8_t ip_ttl; /* time to live */ + uint8_t ip_p; /* protocol */ + uint16_t ip_sum; /* checksum */ + ip_addr_t ip_src; /* source address */ + ip_addr_t ip_dst; /* destination address */ +}; + +/* + * Type of service (ip_tos), RFC 1349 ("obsoleted by RFC 2474") + */ +#define IP_TOS_DEFAULT 0x00 /* default */ +#define IP_TOS_LOWDELAY 0x10 /* low delay */ +#define IP_TOS_THROUGHPUT 0x08 /* high throughput */ +#define IP_TOS_RELIABILITY 0x04 /* high reliability */ +#define IP_TOS_LOWCOST 0x02 /* low monetary cost - XXX */ +#define IP_TOS_ECT 0x02 /* ECN-capable transport */ +#define IP_TOS_CE 0x01 /* congestion experienced */ + +/* + * IP precedence (high 3 bits of ip_tos), hopefully unused + */ +#define IP_TOS_PREC_ROUTINE 0x00 +#define IP_TOS_PREC_PRIORITY 0x20 +#define IP_TOS_PREC_IMMEDIATE 0x40 +#define IP_TOS_PREC_FLASH 0x60 +#define IP_TOS_PREC_FLASHOVERRIDE 0x80 +#define IP_TOS_PREC_CRITIC_ECP 0xa0 +#define IP_TOS_PREC_INTERNETCONTROL 0xc0 +#define IP_TOS_PREC_NETCONTROL 0xe0 + +/* + * Fragmentation flags (ip_off) + */ +#define IP_RF 0x8000 /* reserved */ +#define IP_DF 0x4000 /* don't fragment */ +#define IP_MF 0x2000 /* more fragments (not last frag) */ +#define IP_OFFMASK 0x1fff /* mask for fragment offset */ + +/* + * Time-to-live (ip_ttl), seconds + */ +#define IP_TTL_DEFAULT 64 /* default ttl, RFC 1122, RFC 1340 */ +#define IP_TTL_MAX 255 /* maximum ttl */ + +/* + * Protocol (ip_p) - http://www.iana.org/assignments/protocol-numbers + */ +#define IP_PROTO_IP 0 /* dummy for IP */ +#define IP_PROTO_HOPOPTS IP_PROTO_IP /* IPv6 hop-by-hop options */ +#define IP_PROTO_ICMP 1 /* ICMP */ +#define IP_PROTO_IGMP 2 /* IGMP */ +#define IP_PROTO_GGP 3 /* gateway-gateway protocol */ +#define IP_PROTO_IPIP 4 /* IP in IP */ +#define IP_PROTO_ST 5 /* ST datagram mode */ +#define IP_PROTO_TCP 6 /* TCP */ +#define IP_PROTO_CBT 7 /* CBT */ +#define IP_PROTO_EGP 8 /* exterior gateway protocol */ +#define IP_PROTO_IGP 9 /* interior gateway protocol */ +#define IP_PROTO_BBNRCC 10 /* BBN RCC monitoring */ +#define IP_PROTO_NVP 11 /* Network Voice Protocol */ +#define IP_PROTO_PUP 12 /* PARC universal packet */ +#define IP_PROTO_ARGUS 13 /* ARGUS */ +#define IP_PROTO_EMCON 14 /* EMCON */ +#define IP_PROTO_XNET 15 /* Cross Net Debugger */ +#define IP_PROTO_CHAOS 16 /* Chaos */ +#define IP_PROTO_UDP 17 /* UDP */ +#define IP_PROTO_MUX 18 /* multiplexing */ +#define IP_PROTO_DCNMEAS 19 /* DCN measurement */ +#define IP_PROTO_HMP 20 /* Host Monitoring Protocol */ +#define IP_PROTO_PRM 21 /* Packet Radio Measurement */ +#define IP_PROTO_IDP 22 /* Xerox NS IDP */ +#define IP_PROTO_TRUNK1 23 /* Trunk-1 */ +#define IP_PROTO_TRUNK2 24 /* Trunk-2 */ +#define IP_PROTO_LEAF1 25 /* Leaf-1 */ +#define IP_PROTO_LEAF2 26 /* Leaf-2 */ +#define IP_PROTO_RDP 27 /* "Reliable Datagram" proto */ +#define IP_PROTO_IRTP 28 /* Inet Reliable Transaction */ +#define IP_PROTO_TP 29 /* ISO TP class 4 */ +#define IP_PROTO_NETBLT 30 /* Bulk Data Transfer */ +#define IP_PROTO_MFPNSP 31 /* MFE Network Services */ +#define IP_PROTO_MERITINP 32 /* Merit Internodal Protocol */ +#define IP_PROTO_SEP 33 /* Sequential Exchange proto */ +#define IP_PROTO_3PC 34 /* Third Party Connect proto */ +#define IP_PROTO_IDPR 35 /* Interdomain Policy Route */ +#define IP_PROTO_XTP 36 /* Xpress Transfer Protocol */ +#define IP_PROTO_DDP 37 /* Datagram Delivery Proto */ +#define IP_PROTO_CMTP 38 /* IDPR Ctrl Message Trans */ +#define IP_PROTO_TPPP 39 /* TP++ Transport Protocol */ +#define IP_PROTO_IL 40 /* IL Transport Protocol */ +#define IP_PROTO_IPV6 41 /* IPv6 */ +#define IP_PROTO_SDRP 42 /* Source Demand Routing */ +#define IP_PROTO_ROUTING 43 /* IPv6 routing header */ +#define IP_PROTO_FRAGMENT 44 /* IPv6 fragmentation header */ +#define IP_PROTO_RSVP 46 /* Reservation protocol */ +#define IP_PROTO_GRE 47 /* General Routing Encap */ +#define IP_PROTO_MHRP 48 /* Mobile Host Routing */ +#define IP_PROTO_ENA 49 /* ENA */ +#define IP_PROTO_ESP 50 /* Encap Security Payload */ +#define IP_PROTO_AH 51 /* Authentication Header */ +#define IP_PROTO_INLSP 52 /* Integated Net Layer Sec */ +#define IP_PROTO_SWIPE 53 /* SWIPE */ +#define IP_PROTO_NARP 54 /* NBMA Address Resolution */ +#define IP_PROTO_MOBILE 55 /* Mobile IP, RFC 2004 */ +#define IP_PROTO_TLSP 56 /* Transport Layer Security */ +#define IP_PROTO_SKIP 57 /* SKIP */ +#define IP_PROTO_ICMPV6 58 /* ICMP for IPv6 */ +#define IP_PROTO_NONE 59 /* IPv6 no next header */ +#define IP_PROTO_DSTOPTS 60 /* IPv6 destination options */ +#define IP_PROTO_ANYHOST 61 /* any host internal proto */ +#define IP_PROTO_CFTP 62 /* CFTP */ +#define IP_PROTO_ANYNET 63 /* any local network */ +#define IP_PROTO_EXPAK 64 /* SATNET and Backroom EXPAK */ +#define IP_PROTO_KRYPTOLAN 65 /* Kryptolan */ +#define IP_PROTO_RVD 66 /* MIT Remote Virtual Disk */ +#define IP_PROTO_IPPC 67 /* Inet Pluribus Packet Core */ +#define IP_PROTO_DISTFS 68 /* any distributed fs */ +#define IP_PROTO_SATMON 69 /* SATNET Monitoring */ +#define IP_PROTO_VISA 70 /* VISA Protocol */ +#define IP_PROTO_IPCV 71 /* Inet Packet Core Utility */ +#define IP_PROTO_CPNX 72 /* Comp Proto Net Executive */ +#define IP_PROTO_CPHB 73 /* Comp Protocol Heart Beat */ +#define IP_PROTO_WSN 74 /* Wang Span Network */ +#define IP_PROTO_PVP 75 /* Packet Video Protocol */ +#define IP_PROTO_BRSATMON 76 /* Backroom SATNET Monitor */ +#define IP_PROTO_SUNND 77 /* SUN ND Protocol */ +#define IP_PROTO_WBMON 78 /* WIDEBAND Monitoring */ +#define IP_PROTO_WBEXPAK 79 /* WIDEBAND EXPAK */ +#define IP_PROTO_EON 80 /* ISO CNLP */ +#define IP_PROTO_VMTP 81 /* Versatile Msg Transport*/ +#define IP_PROTO_SVMTP 82 /* Secure VMTP */ +#define IP_PROTO_VINES 83 /* VINES */ +#define IP_PROTO_TTP 84 /* TTP */ +#define IP_PROTO_NSFIGP 85 /* NSFNET-IGP */ +#define IP_PROTO_DGP 86 /* Dissimilar Gateway Proto */ +#define IP_PROTO_TCF 87 /* TCF */ +#define IP_PROTO_EIGRP 88 /* EIGRP */ +#define IP_PROTO_OSPF 89 /* Open Shortest Path First */ +#define IP_PROTO_SPRITERPC 90 /* Sprite RPC Protocol */ +#define IP_PROTO_LARP 91 /* Locus Address Resolution */ +#define IP_PROTO_MTP 92 /* Multicast Transport Proto */ +#define IP_PROTO_AX25 93 /* AX.25 Frames */ +#define IP_PROTO_IPIPENCAP 94 /* yet-another IP encap */ +#define IP_PROTO_MICP 95 /* Mobile Internet Ctrl */ +#define IP_PROTO_SCCSP 96 /* Semaphore Comm Sec Proto */ +#define IP_PROTO_ETHERIP 97 /* Ethernet in IPv4 */ +#define IP_PROTO_ENCAP 98 /* encapsulation header */ +#define IP_PROTO_ANYENC 99 /* private encryption scheme */ +#define IP_PROTO_GMTP 100 /* GMTP */ +#define IP_PROTO_IFMP 101 /* Ipsilon Flow Mgmt Proto */ +#define IP_PROTO_PNNI 102 /* PNNI over IP */ +#define IP_PROTO_PIM 103 /* Protocol Indep Multicast */ +#define IP_PROTO_ARIS 104 /* ARIS */ +#define IP_PROTO_SCPS 105 /* SCPS */ +#define IP_PROTO_QNX 106 /* QNX */ +#define IP_PROTO_AN 107 /* Active Networks */ +#define IP_PROTO_IPCOMP 108 /* IP Payload Compression */ +#define IP_PROTO_SNP 109 /* Sitara Networks Protocol */ +#define IP_PROTO_COMPAQPEER 110 /* Compaq Peer Protocol */ +#define IP_PROTO_IPXIP 111 /* IPX in IP */ +#define IP_PROTO_VRRP 112 /* Virtual Router Redundancy */ +#define IP_PROTO_PGM 113 /* PGM Reliable Transport */ +#define IP_PROTO_ANY0HOP 114 /* 0-hop protocol */ +#define IP_PROTO_L2TP 115 /* Layer 2 Tunneling Proto */ +#define IP_PROTO_DDX 116 /* D-II Data Exchange (DDX) */ +#define IP_PROTO_IATP 117 /* Interactive Agent Xfer */ +#define IP_PROTO_STP 118 /* Schedule Transfer Proto */ +#define IP_PROTO_SRP 119 /* SpectraLink Radio Proto */ +#define IP_PROTO_UTI 120 /* UTI */ +#define IP_PROTO_SMP 121 /* Simple Message Protocol */ +#define IP_PROTO_SM 122 /* SM */ +#define IP_PROTO_PTP 123 /* Performance Transparency */ +#define IP_PROTO_ISIS 124 /* ISIS over IPv4 */ +#define IP_PROTO_FIRE 125 /* FIRE */ +#define IP_PROTO_CRTP 126 /* Combat Radio Transport */ +#define IP_PROTO_CRUDP 127 /* Combat Radio UDP */ +#define IP_PROTO_SSCOPMCE 128 /* SSCOPMCE */ +#define IP_PROTO_IPLT 129 /* IPLT */ +#define IP_PROTO_SPS 130 /* Secure Packet Shield */ +#define IP_PROTO_PIPE 131 /* Private IP Encap in IP */ +#define IP_PROTO_SCTP 132 /* Stream Ctrl Transmission */ +#define IP_PROTO_FC 133 /* Fibre Channel */ +#define IP_PROTO_RSVPIGN 134 /* RSVP-E2E-IGNORE */ +#define IP_PROTO_RAW 255 /* Raw IP packets */ +#define IP_PROTO_RESERVED IP_PROTO_RAW /* Reserved */ +#define IP_PROTO_MAX 255 + +/* + * Option types (opt_type) - http://www.iana.org/assignments/ip-parameters + */ +#define IP_OPT_CONTROL 0x00 /* control */ +#define IP_OPT_DEBMEAS 0x40 /* debugging & measurement */ +#define IP_OPT_COPY 0x80 /* copy into all fragments */ +#define IP_OPT_RESERVED1 0x20 +#define IP_OPT_RESERVED2 0x60 + +#define IP_OPT_EOL 0 /* end of option list */ +#define IP_OPT_NOP 1 /* no operation */ +#define IP_OPT_SEC (2|IP_OPT_COPY) /* DoD basic security */ +#define IP_OPT_LSRR (3|IP_OPT_COPY) /* loose source route */ +#define IP_OPT_TS (4|IP_OPT_DEBMEAS) /* timestamp */ +#define IP_OPT_ESEC (5|IP_OPT_COPY) /* DoD extended security */ +#define IP_OPT_CIPSO (6|IP_OPT_COPY) /* commercial security */ +#define IP_OPT_RR 7 /* record route */ +#define IP_OPT_SATID (8|IP_OPT_COPY) /* stream ID (obsolete) */ +#define IP_OPT_SSRR (9|IP_OPT_COPY) /* strict source route */ +#define IP_OPT_ZSU 10 /* experimental measurement */ +#define IP_OPT_MTUP 11 /* MTU probe */ +#define IP_OPT_MTUR 12 /* MTU reply */ +#define IP_OPT_FINN (13|IP_OPT_COPY|IP_OPT_DEBMEAS) /* exp flow control */ +#define IP_OPT_VISA (14|IP_OPT_COPY) /* exp access control */ +#define IP_OPT_ENCODE 15 /* ??? */ +#define IP_OPT_IMITD (16|IP_OPT_COPY) /* IMI traffic descriptor */ +#define IP_OPT_EIP (17|IP_OPT_COPY) /* extended IP, RFC 1385 */ +#define IP_OPT_TR (18|IP_OPT_DEBMEAS) /* traceroute */ +#define IP_OPT_ADDEXT (19|IP_OPT_COPY) /* IPv7 ext addr, RFC 1475 */ +#define IP_OPT_RTRALT (20|IP_OPT_COPY) /* router alert, RFC 2113 */ +#define IP_OPT_SDB (21|IP_OPT_COPY) /* directed bcast, RFC 1770 */ +#define IP_OPT_NSAPA (22|IP_OPT_COPY) /* NSAP addresses */ +#define IP_OPT_DPS (23|IP_OPT_COPY) /* dynamic packet state */ +#define IP_OPT_UMP (24|IP_OPT_COPY) /* upstream multicast */ +#define IP_OPT_MAX 25 + +#define IP_OPT_COPIED(o) ((o) & 0x80) +#define IP_OPT_CLASS(o) ((o) & 0x60) +#define IP_OPT_NUMBER(o) ((o) & 0x1f) +#define IP_OPT_TYPEONLY(o) ((o) == IP_OPT_EOL || (o) == IP_OPT_NOP) + +/* + * Security option data - RFC 791, 3.1 + */ +struct ip_opt_data_sec { + uint16_t s; /* security */ + uint16_t c; /* compartments */ + uint16_t h; /* handling restrictions */ + uint8_t tcc[3]; /* transmission control code */ +} __attribute__((__packed__)); + +#define IP_OPT_SEC_UNCLASS 0x0000 /* unclassified */ +#define IP_OPT_SEC_CONFID 0xf135 /* confidential */ +#define IP_OPT_SEC_EFTO 0x789a /* EFTO */ +#define IP_OPT_SEC_MMMM 0xbc4d /* MMMM */ +#define IP_OPT_SEC_PROG 0x5e26 /* PROG */ +#define IP_OPT_SEC_RESTR 0xaf13 /* restricted */ +#define IP_OPT_SEC_SECRET 0xd788 /* secret */ +#define IP_OPT_SEC_TOPSECRET 0x6bc5 /* top secret */ + +/* + * {Loose Source, Record, Strict Source} Route option data - RFC 791, 3.1 + */ +struct ip_opt_data_rr { + uint8_t ptr; /* from start of option, >= 4 */ + uint32_t iplist __flexarr; /* list of IP addresses */ +} __attribute__((__packed__)); + +/* + * Timestamp option data - RFC 791, 3.1 + */ +struct ip_opt_data_ts { + uint8_t ptr; /* from start of option, >= 5 */ +#if DNET_BYTESEX == DNET_BIG_ENDIAN + uint8_t oflw:4, /* number of IPs skipped */ + flg:4; /* address[ / timestamp] flag */ +#elif DNET_BYTESEX == DNET_LIL_ENDIAN + uint8_t flg:4, + oflw:4; +#endif + uint32_t ipts __flexarr; /* IP address [/ timestamp] pairs */ +} __attribute__((__packed__)); + +#define IP_OPT_TS_TSONLY 0 /* timestamps only */ +#define IP_OPT_TS_TSADDR 1 /* IP address / timestamp pairs */ +#define IP_OPT_TS_PRESPEC 3 /* IP address / zero timestamp pairs */ + +/* + * Traceroute option data - RFC 1393, 2.2 + */ +struct ip_opt_data_tr { + uint16_t id; /* ID number */ + uint16_t ohc; /* outbound hop count */ + uint16_t rhc; /* return hop count */ + uint32_t origip; /* originator IP address */ +} __attribute__((__packed__)); + +/* + * IP option (following IP header) + */ +struct ip_opt { + uint8_t opt_type; /* option type */ + uint8_t opt_len; /* option length >= IP_OPT_LEN */ + union ip_opt_data { + struct ip_opt_data_sec sec; /* IP_OPT_SEC */ + struct ip_opt_data_rr rr; /* IP_OPT_{L,S}RR */ + struct ip_opt_data_ts ts; /* IP_OPT_TS */ + uint16_t satid; /* IP_OPT_SATID */ + uint16_t mtu; /* IP_OPT_MTU{P,R} */ + struct ip_opt_data_tr tr; /* IP_OPT_TR */ + uint32_t addext[2]; /* IP_OPT_ADDEXT */ + uint16_t rtralt; /* IP_OPT_RTRALT */ + uint32_t sdb[9]; /* IP_OPT_SDB */ + uint8_t data8[IP_OPT_LEN_MAX - IP_OPT_LEN]; + } opt_data; +} __attribute__((__packed__)); + +#ifndef __GNUC__ +# pragma pack() +#endif + +/* + * Classful addressing + */ +#define IP_CLASSA(i) (((uint32_t)(i) & htonl(0x80000000)) == \ + htonl(0x00000000)) +#define IP_CLASSA_NET (htonl(0xff000000)) +#define IP_CLASSA_NSHIFT 24 +#define IP_CLASSA_HOST (htonl(0x00ffffff)) +#define IP_CLASSA_MAX 128 + +#define IP_CLASSB(i) (((uint32_t)(i) & htonl(0xc0000000)) == \ + htonl(0x80000000)) +#define IP_CLASSB_NET (htonl(0xffff0000)) +#define IP_CLASSB_NSHIFT 16 +#define IP_CLASSB_HOST (htonl(0x0000ffff)) +#define IP_CLASSB_MAX 65536 + +#define IP_CLASSC(i) (((uint32_t)(i) & htonl(0xe0000000)) == \ + htonl(0xc0000000)) +#define IP_CLASSC_NET (htonl(0xffffff00)) +#define IP_CLASSC_NSHIFT 8 +#define IP_CLASSC_HOST (htonl(0x000000ff)) + +#define IP_CLASSD(i) (((uint32_t)(i) & htonl(0xf0000000)) == \ + htonl(0xe0000000)) +/* These ones aren't really net and host fields, but routing needn't know. */ +#define IP_CLASSD_NET (htonl(0xf0000000)) +#define IP_CLASSD_NSHIFT 28 +#define IP_CLASSD_HOST (htonl(0x0fffffff)) +#define IP_MULTICAST(i) IP_CLASSD(i) + +#define IP_EXPERIMENTAL(i) (((uint32_t)(i) & htonl(0xf0000000)) == \ + htonl(0xf0000000)) +#define IP_BADCLASS(i) (((uint32_t)(i) & htonl(0xf0000000)) == \ + htonl(0xf0000000)) +#define IP_LOCAL_GROUP(i) (((uint32_t)(i) & htonl(0xffffff00)) == \ + htonl(0xe0000000)) +/* + * Reserved addresses + */ +#define IP_ADDR_ANY (htonl(0x00000000)) /* 0.0.0.0 */ +#define IP_ADDR_BROADCAST (htonl(0xffffffff)) /* 255.255.255.255 */ +#define IP_ADDR_LOOPBACK (htonl(0x7f000001)) /* 127.0.0.1 */ +#define IP_ADDR_MCAST_ALL (htonl(0xe0000001)) /* 224.0.0.1 */ +#define IP_ADDR_MCAST_LOCAL (htonl(0xe00000ff)) /* 224.0.0.225 */ + +#define ip_pack_hdr(hdr, tos, len, id, off, ttl, p, src, dst) do { \ + struct ip_hdr *ip_pack_p = (struct ip_hdr *)(hdr); \ + ip_pack_p->ip_v = 4; ip_pack_p->ip_hl = 5; \ + ip_pack_p->ip_tos = tos; ip_pack_p->ip_len = htons(len); \ + ip_pack_p->ip_id = htons(id); ip_pack_p->ip_off = htons(off); \ + ip_pack_p->ip_ttl = ttl; ip_pack_p->ip_p = p; \ + ip_pack_p->ip_src = src; ip_pack_p->ip_dst = dst; \ +} while (0) + +typedef struct ip_handle ip_t; + +__BEGIN_DECLS +ip_t *ip_open(void); +size_t ip_send(ip_t *i, const void *buf, size_t len); +ip_t *ip_close(ip_t *i); + +char *ip_ntop(const ip_addr_t *ip, char *dst, size_t len); +int ip_pton(const char *src, ip_addr_t *dst); +char *ip_ntoa(const ip_addr_t *ip); +#define ip_aton ip_pton + +size_t ip_add_option(void *buf, size_t len, + int proto, const void *optbuf, size_t optlen); +void ip_checksum(void *buf, size_t len); + +inline int +ip_cksum_add(const void *buf, size_t len, int cksum) +{ + uint16_t *sp = (uint16_t *)buf; + int n, sn; + + sn = len / 2; + n = (sn + 15) / 16; + + /* XXX - unroll loop using Duff's device. */ + switch (sn % 16) { + case 0: do { + cksum += *sp++; + case 15: + cksum += *sp++; + case 14: + cksum += *sp++; + case 13: + cksum += *sp++; + case 12: + cksum += *sp++; + case 11: + cksum += *sp++; + case 10: + cksum += *sp++; + case 9: + cksum += *sp++; + case 8: + cksum += *sp++; + case 7: + cksum += *sp++; + case 6: + cksum += *sp++; + case 5: + cksum += *sp++; + case 4: + cksum += *sp++; + case 3: + cksum += *sp++; + case 2: + cksum += *sp++; + case 1: + cksum += *sp++; + } while (--n > 0); + } + if (len & 1) + cksum += htons(*(u_char *)sp << 8); + + return (cksum); +} + +inline uint16_t +ip_cksum_carry(int x) +{ + x = (x >> 16) + (x & 0xffff); + return ~(x + (x >> 16)) & 0xffff; +} + +__END_DECLS + +#endif /* DNET_IP_H */ diff --git a/ext/dnet/dnet/ip6.h b/ext/dnet/dnet/ip6.h new file mode 100644 index 000000000..7fae29b47 --- /dev/null +++ b/ext/dnet/dnet/ip6.h @@ -0,0 +1,183 @@ +/* + * ip6.h + * + * Internet Protocol, Version 6 (RFC 2460). + * + * Copyright (c) 2002 Dug Song <dugsong@monkey.org> + * + * $Id: ip6.h,v 1.6 2004/02/23 10:01:15 dugsong Exp $ + */ + +#ifndef DNET_IP6_H +#define DNET_IP6_H + +#define IP6_ADDR_LEN 16 +#define IP6_ADDR_BITS 128 + +#define IP6_HDR_LEN 40 /* IPv6 header length */ +#define IP6_LEN_MIN IP6_HDR_LEN +#define IP6_LEN_MAX 65535 /* non-jumbo payload */ + +#define IP6_MTU_MIN 1280 /* minimum MTU (1024 + 256) */ + +typedef struct ip6_addr { + uint8_t data[IP6_ADDR_LEN]; +} ip6_addr_t; + +#ifndef __GNUC__ +# define __attribute__(x) +# pragma pack(1) +#endif + +/* + * IPv6 header + */ +struct ip6_hdr { + union { + struct ip6_hdr_ctl { + uint32_t ip6_un1_flow; /* 20 bits of flow ID */ + uint16_t ip6_un1_plen; /* payload length */ + uint8_t ip6_un1_nxt; /* next header */ + uint8_t ip6_un1_hlim; /* hop limit */ + } ip6_un1; + uint8_t ip6_un2_vfc; /* 4 bits version, top 4 bits class */ + } ip6_ctlun; + ip6_addr_t ip6_src; + ip6_addr_t ip6_dst; +} __attribute__((__packed__)); + +#define ip6_vfc ip6_ctlun.ip6_un2_vfc +#define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow +#define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen +#define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt /* IP_PROTO_* */ +#define ip6_hlim ip6_ctlun.ip6_un1.ip6_un1_hlim + +#define IP6_VERSION 0x60 +#define IP6_VERSION_MASK 0xf0 /* ip6_vfc version */ + +#if DNET_BYTESEX == DNET_BIG_ENDIAN +#define IP6_FLOWINFO_MASK 0x0fffffff /* ip6_flow info (28 bits) */ +#define IP6_FLOWLABEL_MASK 0x000fffff /* ip6_flow label (20 bits) */ +#elif DNET_BYTESEX == DNET_LIL_ENDIAN +#define IP6_FLOWINFO_MASK 0xffffff0f /* ip6_flow info (28 bits) */ +#define IP6_FLOWLABEL_MASK 0xffff0f00 /* ip6_flow label (20 bits) */ +#endif + +/* + * Hop limit (ip6_hlim) + */ +#define IP6_HLIM_DEFAULT 64 +#define IP6_HLIM_MAX 255 + +/* + * Preferred extension header order from RFC 2460, 4.1: + * + * IP_PROTO_IPV6, IP_PROTO_HOPOPTS, IP_PROTO_DSTOPTS, IP_PROTO_ROUTING, + * IP_PROTO_FRAGMENT, IP_PROTO_AH, IP_PROTO_ESP, IP_PROTO_DSTOPTS, IP_PROTO_* + */ + +/* + * Routing header data (IP_PROTO_ROUTING) + */ +struct ip6_ext_data_routing { + uint8_t type; /* routing type */ + uint8_t segleft; /* segments left */ + /* followed by routing type specific data */ +} __attribute__((__packed__)); + +struct ip6_ext_data_routing0 { + uint8_t type; /* always zero */ + uint8_t segleft; /* segments left */ + uint8_t reserved; /* reserved field */ + uint8_t slmap[3]; /* strict/loose bit map */ + ip6_addr_t addr[1]; /* up to 23 addresses */ +} __attribute__((__packed__)); + +/* + * Fragment header data (IP_PROTO_FRAGMENT) + */ +struct ip6_ext_data_fragment { + uint16_t offlg; /* offset, reserved, and flag */ + uint32_t ident; /* identification */ +} __attribute__((__packed__)); + +/* + * Fragmentation offset, reserved, and flags (offlg) + */ +#if DNET_BYTESEX == DNET_BIG_ENDIAN +#define IP6_OFF_MASK 0xfff8 /* mask out offset from offlg */ +#define IP6_RESERVED_MASK 0x0006 /* reserved bits in offlg */ +#define IP6_MORE_FRAG 0x0001 /* more-fragments flag */ +#elif DNET_BYTESEX == DNET_LIL_ENDIAN +#define IP6_OFF_MASK 0xf8ff /* mask out offset from offlg */ +#define IP6_RESERVED_MASK 0x0600 /* reserved bits in offlg */ +#define IP6_MORE_FRAG 0x0100 /* more-fragments flag */ +#endif + +/* + * Option types, for IP_PROTO_HOPOPTS, IP_PROTO_DSTOPTS headers + */ +#define IP6_OPT_PAD1 0x00 /* 00 0 00000 */ +#define IP6_OPT_PADN 0x01 /* 00 0 00001 */ +#define IP6_OPT_JUMBO 0xC2 /* 11 0 00010 = 194 */ +#define IP6_OPT_JUMBO_LEN 6 +#define IP6_OPT_RTALERT 0x05 /* 00 0 00101 */ +#define IP6_OPT_RTALERT_LEN 4 +#define IP6_OPT_RTALERT_MLD 0 /* Datagram contains an MLD message */ +#define IP6_OPT_RTALERT_RSVP 1 /* Datagram contains an RSVP message */ +#define IP6_OPT_RTALERT_ACTNET 2 /* contains an Active Networks msg */ +#define IP6_OPT_LEN_MIN 2 + +#define IP6_OPT_TYPE(o) ((o) & 0xC0) /* high 2 bits of opt_type */ +#define IP6_OPT_TYPE_SKIP 0x00 /* continue processing on failure */ +#define IP6_OPT_TYPE_DISCARD 0x40 /* discard packet on failure */ +#define IP6_OPT_TYPE_FORCEICMP 0x80 /* discard and send ICMP on failure */ +#define IP6_OPT_TYPE_ICMP 0xC0 /* ...only if non-multicast dst */ + +#define IP6_OPT_MUTABLE 0x20 /* option data may change en route */ + +/* + * Extension header (chained via {ip6,ext}_nxt, following IPv6 header) + */ +struct ip6_ext_hdr { + uint8_t ext_nxt; /* next header */ + uint8_t ext_len; /* following length in units of 8 octets */ + union { + struct ip6_ext_data_routing routing; + struct ip6_ext_data_fragment fragment; + } ext_data; +} __attribute__((__packed__)); + +#ifndef __GNUC__ +# pragma pack() +#endif + +/* + * Reserved addresses + */ +#define IP6_ADDR_UNSPEC \ + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +#define IP6_ADDR_LOOPBACK \ + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01" + +#define ip6_pack_hdr(hdr, fc, fl, plen, nxt, hlim, src, dst) do { \ + struct ip6_hdr *ip6 = (struct ip6_hdr *)(hdr); \ + ip6->ip6_flow = htonl(((uint32_t)(fc) << 28) & \ + (IP6_FLOWLABEL_MASK | (fl))); \ + ip6->ip6_vfc = (IP6_VERSION | ((fc) >> 4)); \ + ip6->ip6_plen = htons((plen)); \ + ip6->ip6_nxt = (nxt); ip6->ip6_hlim = (hlim); \ + memmove(&ip6->ip6_src, &(src), IP6_ADDR_LEN); \ + memmove(&ip6->ip6_dst, &(dst), IP6_ADDR_LEN); \ +} while (0); + +__BEGIN_DECLS +char *ip6_ntop(const ip6_addr_t *ip6, char *dst, size_t size); +int ip6_pton(const char *src, ip6_addr_t *dst); +char *ip6_ntoa(const ip6_addr_t *ip6); +#define ip6_aton ip6_pton + +void ip6_checksum(void *buf, size_t len); +__END_DECLS + +#endif /* DNET_IP6_H */ diff --git a/ext/dnet/dnet/os.h b/ext/dnet/dnet/os.h new file mode 100644 index 000000000..cae244781 --- /dev/null +++ b/ext/dnet/dnet/os.h @@ -0,0 +1,117 @@ +/* + * os.h + * + * Sleazy OS-specific defines. + * + * Copyright (c) 2000 Dug Song <dugsong@monkey.org> + * + * $Id: os.h,v 1.10 2004/05/04 03:19:42 dugsong Exp $ + */ + +#ifndef DNET_OS_H +#define DNET_OS_H + +#ifdef _WIN32 +# include <windows.h> +# include <winsock2.h> +# include <stdint.h> +/* XXX */ +# undef IP_OPT_LSRR +# undef IP_OPT_TS +# undef IP_OPT_RR +# undef IP_OPT_SSRR +#else +# include <sys/param.h> +# include <sys/types.h> +# include <sys/socket.h> +# include <netinet/in.h> +# include <arpa/inet.h> +# include <netdb.h> +# ifdef __bsdi__ +# include <machine/types.h> + typedef u_int8_t uint8_t; + typedef u_int16_t uint16_t; + typedef u_int32_t uint32_t; + typedef u_int64_t uint64_t; +# else +# include <inttypes.h> +# endif +#endif + +#define DNET_LIL_ENDIAN 1234 +#define DNET_BIG_ENDIAN 4321 + +/* BSD and IRIX */ +#ifdef BYTE_ORDER +#if BYTE_ORDER == LITTLE_ENDIAN +# define DNET_BYTESEX DNET_LIL_ENDIAN +#elif BYTE_ORDER == BIG_ENDIAN +# define DNET_BYTESEX DNET_BIG_ENDIAN +#endif +#endif + +/* Linux */ +#ifdef __BYTE_ORDER +#if __BYTE_ORDER == __LITTLE_ENDIAN +# define DNET_BYTESEX DNET_LIL_ENDIAN +#elif __BYTE_ORDER == __BIG_ENDIAN +# define DNET_BYTESEX DNET_BIG_ENDIAN +#endif +#endif + +/* Solaris */ +#if defined(_BIT_FIELDS_LTOH) +# define DNET_BYTESEX DNET_LIL_ENDIAN +#elif defined (_BIT_FIELDS_HTOL) +# define DNET_BYTESEX DNET_BIG_ENDIAN +#endif + +/* Nastiness from old BIND code. */ +#ifndef DNET_BYTESEX +# if defined(vax) || defined(ns32000) || defined(sun386) || defined(i386) || \ + defined(MIPSEL) || defined(_MIPSEL) || defined(BIT_ZERO_ON_RIGHT) || \ + defined(__alpha__) || defined(__alpha) +# define DNET_BYTESEX DNET_LIL_ENDIAN +# elif defined(sel) || defined(pyr) || defined(mc68000) || defined(sparc) || \ + defined(is68k) || defined(tahoe) || defined(ibm032) || defined(ibm370) || \ + defined(MIPSEB) || defined(_MIPSEB) || defined(_IBMR2) || defined(DGUX) ||\ + defined(apollo) || defined(__convex__) || defined(_CRAY) || \ + defined(__hppa) || defined(__hp9000) || \ + defined(__hp9000s300) || defined(__hp9000s700) || defined(__ia64) || \ + defined (BIT_ZERO_ON_LEFT) || defined(m68k) +# define DNET_BYTESEX DNET_BIG_ENDIAN +# else +# error "bytesex unknown" +# endif +#endif + +/* C++ support. */ +#undef __BEGIN_DECLS +#undef __END_DECLS +#ifdef __cplusplus +# define __BEGIN_DECLS extern "C" { +# define __END_DECLS } /* extern "C" */ +#else +# define __BEGIN_DECLS +# define __END_DECLS +#endif + +/* Support for flexible arrays. */ +#undef __flexarr +#if defined(__GNUC__) && ((__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)) +/* GCC 2.97 supports C99 flexible array members. */ +# define __flexarr [] +#else +# ifdef __GNUC__ +# define __flexarr [0] +# else +# if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L +# define __flexarr [] +# else +/* Some other non-C99 compiler. Approximate with [1]. */ +# define __flexarr [1] +# endif +# endif +#endif + +#endif /* DNET_OS_H */ diff --git a/ext/dnet/dnet/rand.h b/ext/dnet/dnet/rand.h new file mode 100644 index 000000000..49121930c --- /dev/null +++ b/ext/dnet/dnet/rand.h @@ -0,0 +1,33 @@ +/* + * rand.h + * + * Pseudo-random number generation, based on OpenBSD arc4random(). + * + * Copyright (c) 2000 Dug Song <dugsong@monkey.org> + * Copyright (c) 1996 David Mazieres <dm@lcs.mit.edu> + * + * $Id: rand.h,v 1.4 2002/04/07 19:01:25 dugsong Exp $ + */ + +#ifndef DNET_RAND_H +#define DNET_RAND_H + +typedef struct rand_handle rand_t; + +__BEGIN_DECLS +rand_t *rand_open(void); + +int rand_get(rand_t *r, void *buf, size_t len); +int rand_set(rand_t *r, const void *seed, size_t len); +int rand_add(rand_t *r, const void *buf, size_t len); + +uint8_t rand_uint8(rand_t *r); +uint16_t rand_uint16(rand_t *r); +uint32_t rand_uint32(rand_t *r); + +int rand_shuffle(rand_t *r, void *base, size_t nmemb, size_t size); + +rand_t *rand_close(rand_t *r); +__END_DECLS + +#endif /* DNET_RAND_H */ diff --git a/ext/dnet/dnet/route.h b/ext/dnet/dnet/route.h new file mode 100644 index 000000000..74c21419c --- /dev/null +++ b/ext/dnet/dnet/route.h @@ -0,0 +1,35 @@ +/* + * route.c + * + * Kernel route table operations. + * + * Copyright (c) 2000 Dug Song <dugsong@monkey.org> + * + * $Id: route.h,v 1.6 2002/02/04 04:02:22 dugsong Exp $ + */ + +#ifndef DNET_ROUTE_H +#define DNET_ROUTE_H + +/* + * Routing table entry + */ +struct route_entry { + struct addr route_dst; /* destination address */ + struct addr route_gw; /* gateway address */ +}; + +typedef struct route_handle route_t; + +typedef int (*route_handler)(const struct route_entry *entry, void *arg); + +__BEGIN_DECLS +route_t *route_open(void); +int route_add(route_t *r, const struct route_entry *entry); +int route_delete(route_t *r, const struct route_entry *entry); +int route_get(route_t *r, struct route_entry *entry); +int route_loop(route_t *r, route_handler callback, void *arg); +route_t *route_close(route_t *r); +__END_DECLS + +#endif /* DNET_ROUTE_H */ diff --git a/ext/dnet/dnet/tcp.h b/ext/dnet/dnet/tcp.h new file mode 100644 index 000000000..008946384 --- /dev/null +++ b/ext/dnet/dnet/tcp.h @@ -0,0 +1,158 @@ +/* + * tcp.h + * + * Transmission Control Protocol (RFC 793). + * + * Copyright (c) 2000 Dug Song <dugsong@monkey.org> + * + * $Id: tcp.h,v 1.17 2004/02/23 10:02:11 dugsong Exp $ + */ + +#ifndef DNET_TCP_H +#define DNET_TCP_H + +#define TCP_HDR_LEN 20 /* base TCP header length */ +#define TCP_OPT_LEN 2 /* base TCP option length */ +#define TCP_OPT_LEN_MAX 40 +#define TCP_HDR_LEN_MAX (TCP_HDR_LEN + TCP_OPT_LEN_MAX) + +#ifndef __GNUC__ +# define __attribute__(x) +# pragma pack(1) +#endif + +/* + * TCP header, without options + */ +struct tcp_hdr { + uint16_t th_sport; /* source port */ + uint16_t th_dport; /* destination port */ + uint32_t th_seq; /* sequence number */ + uint32_t th_ack; /* acknowledgment number */ +#if DNET_BYTESEX == DNET_BIG_ENDIAN + uint8_t th_off:4, /* data offset */ + th_x2:4; /* (unused) */ +#elif DNET_BYTESEX == DNET_LIL_ENDIAN + uint8_t th_x2:4, + th_off:4; +#else +# error "need to include <dnet.h>" +#endif + uint8_t th_flags; /* control flags */ + uint16_t th_win; /* window */ + uint16_t th_sum; /* checksum */ + uint16_t th_urp; /* urgent pointer */ +}; + +/* + * TCP control flags (th_flags) + */ +#define TH_FIN 0x01 /* end of data */ +#define TH_SYN 0x02 /* synchronize sequence numbers */ +#define TH_RST 0x04 /* reset connection */ +#define TH_PUSH 0x08 /* push */ +#define TH_ACK 0x10 /* acknowledgment number set */ +#define TH_URG 0x20 /* urgent pointer set */ +#define TH_ECE 0x40 /* ECN echo, RFC 3168 */ +#define TH_CWR 0x80 /* congestion window reduced */ + +#define TCP_PORT_MAX 65535 /* maximum port */ +#define TCP_WIN_MAX 65535 /* maximum (unscaled) window */ + +/* + * Sequence number comparison macros + */ +#define TCP_SEQ_LT(a,b) ((int)((a)-(b)) < 0) +#define TCP_SEQ_LEQ(a,b) ((int)((a)-(b)) <= 0) +#define TCP_SEQ_GT(a,b) ((int)((a)-(b)) > 0) +#define TCP_SEQ_GEQ(a,b) ((int)((a)-(b)) >= 0) + +/* + * TCP FSM states + */ +#define TCP_STATE_CLOSED 0 /* closed */ +#define TCP_STATE_LISTEN 1 /* listening from connection */ +#define TCP_STATE_SYN_SENT 2 /* active, have sent SYN */ +#define TCP_STATE_SYN_RECEIVED 3 /* have sent and received SYN */ + +#define TCP_STATE_ESTABLISHED 4 /* established */ +#define TCP_STATE_CLOSE_WAIT 5 /* rcvd FIN, waiting for close */ + +#define TCP_STATE_FIN_WAIT_1 6 /* have closed, sent FIN */ +#define TCP_STATE_CLOSING 7 /* closed xchd FIN, await FIN-ACK */ +#define TCP_STATE_LAST_ACK 8 /* had FIN and close, await FIN-ACK */ + +#define TCP_STATE_FIN_WAIT_2 9 /* have closed, FIN is acked */ +#define TCP_STATE_TIME_WAIT 10 /* in 2*MSL quiet wait after close */ +#define TCP_STATE_MAX 11 + +/* + * Options (opt_type) - http://www.iana.org/assignments/tcp-parameters + */ +#define TCP_OPT_EOL 0 /* end of option list */ +#define TCP_OPT_NOP 1 /* no operation */ +#define TCP_OPT_MSS 2 /* maximum segment size */ +#define TCP_OPT_WSCALE 3 /* window scale factor, RFC 1072 */ +#define TCP_OPT_SACKOK 4 /* SACK permitted, RFC 2018 */ +#define TCP_OPT_SACK 5 /* SACK, RFC 2018 */ +#define TCP_OPT_ECHO 6 /* echo (obsolete), RFC 1072 */ +#define TCP_OPT_ECHOREPLY 7 /* echo reply (obsolete), RFC 1072 */ +#define TCP_OPT_TIMESTAMP 8 /* timestamp, RFC 1323 */ +#define TCP_OPT_POCONN 9 /* partial order conn, RFC 1693 */ +#define TCP_OPT_POSVC 10 /* partial order service, RFC 1693 */ +#define TCP_OPT_CC 11 /* connection count, RFC 1644 */ +#define TCP_OPT_CCNEW 12 /* CC.NEW, RFC 1644 */ +#define TCP_OPT_CCECHO 13 /* CC.ECHO, RFC 1644 */ +#define TCP_OPT_ALTSUM 14 /* alt checksum request, RFC 1146 */ +#define TCP_OPT_ALTSUMDATA 15 /* alt checksum data, RFC 1146 */ +#define TCP_OPT_SKEETER 16 /* Skeeter */ +#define TCP_OPT_BUBBA 17 /* Bubba */ +#define TCP_OPT_TRAILSUM 18 /* trailer checksum */ +#define TCP_OPT_MD5 19 /* MD5 signature, RFC 2385 */ +#define TCP_OPT_SCPS 20 /* SCPS capabilities */ +#define TCP_OPT_SNACK 21 /* selective negative acks */ +#define TCP_OPT_REC 22 /* record boundaries */ +#define TCP_OPT_CORRUPT 23 /* corruption experienced */ +#define TCP_OPT_SNAP 24 /* SNAP */ +#define TCP_OPT_TCPCOMP 26 /* TCP compression filter */ +#define TCP_OPT_MAX 27 + +#define TCP_OPT_TYPEONLY(type) \ + ((type) == TCP_OPT_EOL || (type) == TCP_OPT_NOP) + +/* + * TCP option (following TCP header) + */ +struct tcp_opt { + uint8_t opt_type; /* option type */ + uint8_t opt_len; /* option length >= TCP_OPT_LEN */ + union tcp_opt_data { + uint16_t mss; /* TCP_OPT_MSS */ + uint8_t wscale; /* TCP_OPT_WSCALE */ + uint16_t sack[19]; /* TCP_OPT_SACK */ + uint32_t echo; /* TCP_OPT_ECHO{REPLY} */ + uint32_t timestamp[2]; /* TCP_OPT_TIMESTAMP */ + uint32_t cc; /* TCP_OPT_CC{NEW,ECHO} */ + uint8_t cksum; /* TCP_OPT_ALTSUM */ + uint8_t md5[16]; /* TCP_OPT_MD5 */ + uint8_t data8[TCP_OPT_LEN_MAX - TCP_OPT_LEN]; + } opt_data; +} __attribute__((__packed__)); + +#ifndef __GNUC__ +# pragma pack() +#endif + +#define tcp_pack_hdr(hdr, sport, dport, seq, ack, flags, win, urp) do { \ + struct tcp_hdr *tcp_pack_p = (struct tcp_hdr *)(hdr); \ + tcp_pack_p->th_sport = htons(sport); \ + tcp_pack_p->th_dport = htons(dport); \ + tcp_pack_p->th_seq = htonl(seq); \ + tcp_pack_p->th_ack = htonl(ack); \ + tcp_pack_p->th_x2 = 0; tcp_pack_p->th_off = 5; \ + tcp_pack_p->th_flags = flags; \ + tcp_pack_p->th_win = htons(win); \ + tcp_pack_p->th_urp = htons(urp); \ +} while (0) + +#endif /* DNET_TCP_H */ diff --git a/ext/dnet/dnet/udp.h b/ext/dnet/dnet/udp.h new file mode 100644 index 000000000..73839a92a --- /dev/null +++ b/ext/dnet/dnet/udp.h @@ -0,0 +1,32 @@ +/* + * udp.h + * + * User Datagram Protocol (RFC 768). + * + * Copyright (c) 2000 Dug Song <dugsong@monkey.org> + * + * $Id: udp.h,v 1.8 2002/04/02 05:05:39 dugsong Exp $ + */ + +#ifndef DNET_UDP_H +#define DNET_UDP_H + +#define UDP_HDR_LEN 8 + +struct udp_hdr { + uint16_t uh_sport; /* source port */ + uint16_t uh_dport; /* destination port */ + uint16_t uh_ulen; /* udp length (including header) */ + uint16_t uh_sum; /* udp checksum */ +}; + +#define UDP_PORT_MAX 65535 + +#define udp_pack_hdr(hdr, sport, dport, ulen) do { \ + struct udp_hdr *udp_pack_p = (struct udp_hdr *)(hdr); \ + udp_pack_p->uh_sport = htons(sport); \ + udp_pack_p->uh_dport = htons(dport); \ + udp_pack_p->uh_ulen = htons(ulen); \ +} while (0) + +#endif /* DNET_UDP_H */ diff --git a/ext/ply/CHANGES b/ext/ply/CHANGES new file mode 100644 index 000000000..9c7334066 --- /dev/null +++ b/ext/ply/CHANGES @@ -0,0 +1,158 @@ +Version 1.3 +------------------------------ +12/10/02: jmdyck + Various minor adjustments to the code that Dave checked in today. + Updated test/yacc_{inf,unused}.exp to reflect today's changes. + +12/10/02: beazley + Incorporated a variety of minor bug fixes to empty production + handling and infinite recursion checking. Contributed by + Michael Dyck. + +12/10/02: beazley + Removed bogus recover() method call in yacc.restart() + +Version 1.2 +------------------------------ +11/27/02: beazley + Lexer and parser objects are now available as an attribute + of tokens and slices respectively. For example: + + def t_NUMBER(t): + r'\d+' + print t.lexer + + def p_expr_plus(t): + 'expr: expr PLUS expr' + print t.lexer + print t.parser + + This can be used for state management (if needed). + +10/31/02: beazley + Modified yacc.py to work with Python optimize mode. To make + this work, you need to use + + yacc.yacc(optimize=1) + + Furthermore, you need to first run Python in normal mode + to generate the necessary parsetab.py files. After that, + you can use python -O or python -OO. + + Note: optimized mode turns off a lot of error checking. + Only use when you are sure that your grammar is working. + Make sure parsetab.py is up to date! + +10/30/02: beazley + Added cloning of Lexer objects. For example: + + import copy + l = lex.lex() + lc = copy.copy(l) + + l.input("Some text") + lc.input("Some other text") + ... + + This might be useful if the same "lexer" is meant to + be used in different contexts---or if multiple lexers + are running concurrently. + +10/30/02: beazley + Fixed subtle bug with first set computation and empty productions. + Patch submitted by Michael Dyck. + +10/30/02: beazley + Fixed error messages to use "filename:line: message" instead + of "filename:line. message". This makes error reporting more + friendly to emacs. Patch submitted by François Pinard. + +10/30/02: beazley + Improvements to parser.out file. Terminals and nonterminals + are sorted instead of being printed in random order. + Patch submitted by François Pinard. + +10/30/02: beazley + Improvements to parser.out file output. Rules are now printed + in a way that's easier to understand. Contributed by Russ Cox. + +10/30/02: beazley + Added 'nonassoc' associativity support. This can be used + to disable the chaining of operators like a < b < c. + To use, simply specify 'nonassoc' in the precedence table + + precedence = ( + ('nonassoc', 'LESSTHAN', 'GREATERTHAN'), # Nonassociative operators + ('left', 'PLUS', 'MINUS'), + ('left', 'TIMES', 'DIVIDE'), + ('right', 'UMINUS'), # Unary minus operator + ) + + Patch contributed by Russ Cox. + +10/30/02: beazley + Modified the lexer to provide optional support for Python -O and -OO + modes. To make this work, Python *first* needs to be run in + unoptimized mode. This reads the lexing information and creates a + file "lextab.py". Then, run lex like this: + + # module foo.py + ... + ... + lex.lex(optimize=1) + + Once the lextab file has been created, subsequent calls to + lex.lex() will read data from the lextab file instead of using + introspection. In optimized mode (-O, -OO) everything should + work normally despite the loss of doc strings. + + To change the name of the file 'lextab.py' use the following: + + lex.lex(lextab="footab") + + (this creates a file footab.py) + + +Version 1.1 October 25, 2001 +------------------------------ + +10/25/01: beazley + Modified the table generator to produce much more compact data. + This should greatly reduce the size of the parsetab.py[c] file. + Caveat: the tables still need to be constructed so a little more + work is done in parsetab on import. + +10/25/01: beazley + There may be a possible bug in the cycle detector that reports errors + about infinite recursion. I'm having a little trouble tracking it + down, but if you get this problem, you can disable the cycle + detector as follows: + + yacc.yacc(check_recursion = 0) + +10/25/01: beazley + Fixed a bug in lex.py that sometimes caused illegal characters to be + reported incorrectly. Reported by Sverre Jørgensen. + +7/8/01 : beazley + Added a reference to the underlying lexer object when tokens are handled by + functions. The lexer is available as the 'lexer' attribute. This + was added to provide better lexing support for languages such as Fortran + where certain types of tokens can't be conveniently expressed as regular + expressions (and where the tokenizing function may want to perform a + little backtracking). Suggested by Pearu Peterson. + +6/20/01 : beazley + Modified yacc() function so that an optional starting symbol can be specified. + For example: + + yacc.yacc(start="statement") + + Normally yacc always treats the first production rule as the starting symbol. + However, if you are debugging your grammar it may be useful to specify + an alternative starting symbol. Idea suggested by Rich Salz. + +Version 1.0 June 18, 2001 +-------------------------- +Initial public offering + diff --git a/ext/ply/COPYING b/ext/ply/COPYING new file mode 100644 index 000000000..b1e3f5a26 --- /dev/null +++ b/ext/ply/COPYING @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + <one line to give the library's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + <signature of Ty Coon>, 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/ext/ply/README b/ext/ply/README new file mode 100644 index 000000000..35b458d4c --- /dev/null +++ b/ext/ply/README @@ -0,0 +1,249 @@ +PLY (Python Lex-Yacc) Version 1.2 (November 27, 2002) + +David M. Beazley +Department of Computer Science +University of Chicago +Chicago, IL 60637 +beazley@cs.uchicago.edu + +Copyright (C) 2001 David M. Beazley + +$Header: /home/stever/bk/newmem2/ext/ply/README 1.1 03/06/06 14:53:34-00:00 stever@ $ + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +See the file COPYING for a complete copy of the LGPL. + +Introduction +============ + +PLY is a 100% Python implementation of the common parsing tools lex +and yacc. Although several other parsing tools are available for +Python, there are several reasons why you might want to consider PLY: + + - The tools are very closely modeled after traditional lex/yacc. + If you know how to use these tools in C, you will find PLY + to be similar. + + - PLY provides *very* extensive error reporting and diagnostic + information to assist in parser construction. The original + implementation was developed for instructional purposes. As + a result, the system tries to identify the most common types + of errors made by novice users. + + - PLY provides full support for empty productions, error recovery, + precedence specifiers, and moderately ambiguous grammars. + + - Parsing is based on LR-parsing which is fast, memory efficient, + better suited to large grammars, and which has a number of nice + properties when dealing with syntax errors and other parsing problems. + Currently, PLY builds its parsing tables using the SLR algorithm which + is slightly weaker than LALR(1) used in traditional yacc. + + - Like John Aycock's excellent SPARK toolkit, PLY uses Python + reflection to build lexers and parsers. This greatly simplifies + the task of parser construction since it reduces the number of files + and eliminates the need to run a separate lex/yacc tool before + running your program. + + - PLY can be used to build parsers for "real" programming languages. + Although it is not ultra-fast due to its Python implementation, + PLY can be used to parse grammars consisting of several hundred + rules (as might be found for a language like C). The lexer and LR + parser are also reasonably efficient when parsing typically + sized programs. + +The original version of PLY was developed for an Introduction to +Compilers course where students used it to build a compiler for a +simple Pascal-like language. Their compiler had to include lexical +analysis, parsing, type checking, type inference, and generation of +assembly code for the SPARC processor. Because of this, the current +implementation has been extensively tested and debugged. In addition, +most of the API and error checking steps have been adapted to address +common usability problems. + +How to Use +========== + +PLY consists of two files : lex.py and yacc.py. To use the system, +simply copy these files to your project and import them like standard +Python modules. + +The file doc/ply.html contains complete documentation on how to use +the system. + +The example directory contains several different examples including a +PLY specification for ANSI C as given in K&R 2nd Ed. Note: To use +the examples, you will need to copy the lex.py and yacc.py files to +the example directory. + +A simple example is found at the end of this document + +Requirements +============ +PLY requires the use of Python 2.0 or greater. It should work on +just about any platform. + +Resources +========= + +More information about PLY can be obtained on the PLY webpage at: + + http://systems.cs.uchicago.edu/ply + +For a detailed overview of parsing theory, consult the excellent +book "Compilers : Principles, Techniques, and Tools" by Aho, Sethi, and +Ullman. The topics found in "Lex & Yacc" by Levine, Mason, and Brown +may also be useful. + +Given that this is the first release, I welcome your comments on how +to improve the current implementation. See the TODO file for things that +still need to be done. + +Acknowledgments +=============== + +A special thanks is in order for all of the students in CS326 who +suffered through about 25 different versions of these tools :-). + +Example +======= + +Here is a simple example showing a PLY implementation of a calculator with variables. + +# ----------------------------------------------------------------------------- +# calc.py +# +# A simple calculator with variables. +# ----------------------------------------------------------------------------- + +tokens = ( + 'NAME','NUMBER', + 'PLUS','MINUS','TIMES','DIVIDE','EQUALS', + 'LPAREN','RPAREN', + ) + +# Tokens + +t_PLUS = r'\+' +t_MINUS = r'-' +t_TIMES = r'\*' +t_DIVIDE = r'/' +t_EQUALS = r'=' +t_LPAREN = r'\(' +t_RPAREN = r'\)' +t_NAME = r'[a-zA-Z_][a-zA-Z0-9_]*' + +def t_NUMBER(t): + r'\d+' + try: + t.value = int(t.value) + except ValueError: + print "Integer value too large", t.value + t.value = 0 + return t + +# Ignored characters +t_ignore = " \t" + +def t_newline(t): + r'\n+' + t.lineno += t.value.count("\n") + +def t_error(t): + print "Illegal character '%s'" % t.value[0] + t.skip(1) + +# Build the lexer +import lex +lex.lex() + +# Precedence rules for the arithmetic operators +precedence = ( + ('left','PLUS','MINUS'), + ('left','TIMES','DIVIDE'), + ('right','UMINUS'), + ) + +# dictionary of names (for storing variables) +names = { } + +def p_statement_assign(t): + 'statement : NAME EQUALS expression' + names[t[1]] = t[3] + +def p_statement_expr(t): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[2] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +def p_error(t): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc() + +while 1: + try: + s = raw_input('calc > ') + except EOFError: + break + yacc.parse(s) + + + + + + + + + + + + + + + + + diff --git a/ext/ply/TODO b/ext/ply/TODO new file mode 100644 index 000000000..b2978150d --- /dev/null +++ b/ext/ply/TODO @@ -0,0 +1,22 @@ +The PLY to-do list: + +$Header: /home/stever/bk/newmem2/ext/ply/TODO 1.1 03/06/06 14:53:34-00:00 stever@ $ + +1. Create a Python package using distutils + +2. More interesting parsing examples. + +3. Work on the ANSI C grammar so that it can actually parse C programs. To do this, + some extra code needs to be added to the lexer to deal with typedef names and enumeration + constants. + +4. Get LALR(1) to work. Hard, but not impossible. + +5. More tests in the test directory. + +6. Performance improvements and cleanup in yacc.py. + +7. More documentation. + +8. Lots and lots of cleanup. + diff --git a/ext/ply/doc/ply.html b/ext/ply/doc/ply.html new file mode 100644 index 000000000..2596066fe --- /dev/null +++ b/ext/ply/doc/ply.html @@ -0,0 +1,1642 @@ +<html> +<head> +<title>PLY (Python Lex-Yacc)</title> +</head> +<body bgcolor="#ffffff"> + +<h1>PLY (Python Lex-Yacc)</h1> + +<b> +David M. Beazley <br> +Department of Computer Science <br> +University of Chicago <br> +Chicago, IL 60637 <br> +beazley@cs.uchicago.edu <br> +</b> + +<p> +Documentation version: $Header: /home/stever/bk/newmem2/ext/ply/doc/ply.html 1.1 03/06/06 14:53:34-00:00 stever@ $ + +<h2>Introduction</h2> + +PLY is a Python-only implementation of the popular compiler +construction tools lex and yacc. The implementation borrows ideas +from a number of previous efforts; most notably John Aycock's SPARK +toolkit. However, the overall flavor of the implementation is more +closely modeled after the C version of lex and yacc. The other +significant feature of PLY is that it provides extensive input +validation and error reporting--much more so than other Python parsing +tools. + +<p> +Early versions of PLY were developed to support the Introduction to +Compilers Course at the University of Chicago. In this course, +students built a fully functional compiler for a simple Pascal-like +language. Their compiler, implemented entirely in Python, had to +include lexical analysis, parsing, type checking, type inference, +nested scoping, and code generation for the SPARC processor. +Approximately 30 different compiler implementations were completed in +this course. Most of PLY's interface and operation has been motivated by common +usability problems encountered by students. + +<p> +Because PLY was primarily developed as an instructional tool, you will +find it to be <em>MUCH</em> more picky about token and grammar rule +specification than most other Python parsing tools. In part, this +added formality is meant to catch common programming mistakes made by +novice users. However, advanced users will also find such features to +be useful when building complicated grammars for real programming +languages. It should also be noted that PLY does not provide much in the way +of bells and whistles (e.g., automatic construction of abstract syntax trees, +tree traversal, etc.). Instead, you will find a bare-bones, yet +fully capable lex/yacc implementation written entirely in Python. + +<p> +The rest of this document assumes that you are somewhat familar with +parsing theory, syntax directed translation, and automatic tools such +as lex and yacc. If you are unfamilar with these topics, you will +probably want to consult an introductory text such as "Compilers: +Principles, Techniques, and Tools", by Aho, Sethi, and Ullman. "Lex +and Yacc" by John Levine may also be handy. + +<h2>PLY Overview</h2> + +PLY consists of two separate tools; <tt>lex.py</tt> and +<tt>yacc.py</tt>. <tt>lex.py</tt> is used to break input text into a +collection of tokens specified by a collection of regular expression +rules. <tt>yacc.py</tt> is used to recognize language syntax that has +been specified in the form of a context free grammar. Currently, +<tt>yacc.py</tt> uses LR parsing and generates its parsing tables +using the SLR algorithm. LALR(1) parsing may be supported in a future +release. + +<p> +The two tools are meant to work together. Specifically, +<tt>lex.py</tt> provides an external interface in the form of a +<tt>token()</tt> function that returns the next valid token on the +input stream. <tt>yacc.py</tt> calls this repeatedly to retrieve +tokens and invoke grammar rules. The output of <tt>yacc.py</tt> is +often an Abstract Syntax Tree (AST). However, this is entirely up to +the user. If desired, <tt>yacc.py</tt> can also be used to implement +simple one-pass compilers. + +<p> +Like its Unix counterpart, <tt>yacc.py</tt> provides most of the +features you expect including extensive error checking, grammar +validation, support for empty productions, error tokens, and ambiguity +resolution via precedence rules. The primary difference between +<tt>yacc.py</tt> and <tt>yacc</tt> is the use of SLR parsing instead +of LALR(1). Although this slightly restricts the types of grammars +than can be successfully parsed, it is sufficiently powerful to handle most +kinds of normal programming language constructs. + +<p> +Finally, it is important to note that PLY relies on reflection +(introspection) to build its lexers and parsers. Unlike traditional +lex/yacc which require a special input file that is converted into a +separate source file, the specifications given to PLY <em>are</em> +valid Python programs. This means that there are no extra source +files nor is there a special compiler construction step (e.g., running +yacc to generate Python code for the compiler). + +<h2>Lex Example</h2> + +<tt>lex.py</tt> is used to write tokenizers. To do this, each token +must be defined by a regular expression rule. The following file +implements a very simple lexer for tokenizing simple integer expressions: + +<blockquote> +<pre> +# ------------------------------------------------------------ +# calclex.py +# +# tokenizer for a simple expression evaluator for +# numbers and +,-,*,/ +# ------------------------------------------------------------ +import lex + +# List of token names. This is always required +tokens = ( + 'NUMBER', + 'PLUS', + 'MINUS', + 'TIMES', + 'DIVIDE', + 'LPAREN', + 'RPAREN', +) + +# Regular expression rules for simple tokens +t_PLUS = r'\+' +t_MINUS = r'-' +t_TIMES = r'\*' +t_DIVIDE = r'/' +t_LPAREN = r'\(' +t_RPAREN = r'\)' + +# A regular expression rule with some action code +def t_NUMBER(t): + r'\d+' + try: + t.value = int(t.value) + except ValueError: + print "Line %d: Number %s is too large!" % (t.lineno,t.value) + t.value = 0 + return t + +# Define a rule so we can track line numbers +def t_newline(t): + r'\n+' + t.lineno += len(t.value) + +# A string containing ignored characters (spaces and tabs) +t_ignore = ' \t' + +# Error handling rule +def t_error(t): + print "Illegal character '%s'" % t.value[0] + t.skip(1) + +# Build the lexer +lex.lex() + +# Test it out +data = ''' +3 + 4 * 10 + + -20 *2 +''' + +# Give the lexer some input +lex.input(data) + +# Tokenize +while 1: + tok = lex.token() + if not tok: break # No more input + print tok +</pre> +</blockquote> + +In the example, the <tt>tokens</tt> list defines all of the possible +token names that can be produced by the lexer. This list is always required +and is used to perform a variety of validation checks. Following the <tt>tokens</tt> +list, regular expressions are written for each token. Each of these +rules are defined by making declarations with a special prefix <tt>t_</tt> to indicate that it +defines a token. For simple tokens, the regular expression can +be specified as strings such as this (note: Python raw strings are used since they are the +most convenient way to write regular expression strings): + +<blockquote> +<pre> +t_PLUS = r'\+' +</pre> +</blockquote> + +In this case, the name following the <tt>t_</tt> must exactly match one of the +names supplied in <tt>tokens</tt>. If some kind of action needs to be performed, +a token rule can be specified as a function. For example: + +<blockquote> +<pre> +def t_NUMBER(t): + r'\d+' + try: + t.value = int(t.value) + except ValueError: + print "Number %s is too large!" % t.value + t.value = 0 + return t +</pre> +</blockquote> + +In this case, the regular expression rule is specified in the function documentation string. +The function always takes a single argument which is an instance of +<tt>LexToken</tt>. This object has attributes of <tt>t.type</tt> which is the token type, +<tt>t.value</tt> which is the lexeme, and <tt>t.lineno</tt> which is the current line number. +By default, <tt>t.type</tt> is set to the name following the <tt>t_</tt> prefix. The action +function can modify the contents of the <tt>LexToken</tt> object as appropriate. However, +when it is done, the resulting token should be returned. If no value is returned by the action +function, the token is simply discarded and the next token read. + +<p> +The rule <tt>t_newline()</tt> illustrates a regular expression rule +for a discarded token. In this case, a rule is written to match +newlines so that proper line number tracking can be performed. +By returning no value, the function causes the newline character to be +discarded. + +<p> +The special <tt>t_ignore</tt> rule is reserved by <tt>lex.py</tt> for characters +that should be completely ignored in the input stream. +Usually this is used to skip over whitespace and other non-essential characters. +Although it is possible to define a regular expression rule for whitespace in a manner +similar to <tt>t_newline()</tt>, the use of <tt>t_ignore</tt> provides substantially better +lexing performance because it is handled as a special case and is checked in a much +more efficient manner than the normal regular expression rules. + +<p> +Finally, the <tt>t_error()</tt> +function is used to handle lexing errors that occur when illegal +characters are detected. In this case, the <tt>t.value</tt> attribute contains the +rest of the input string that has not been tokenized. In the example, we simply print +the offending character and skip ahead one character by calling <tt>t.skip(1)</tt>. + +<p> +To build the lexer, the function <tt>lex.lex()</tt> is used. This function +uses Python reflection (or introspection) to read the the regular expression rules +out of the calling context and build the lexer. Once the lexer has been built, two functions can +be used to control the lexer. + +<ul> +<li><tt>lex.input(data)</tt>. Reset the lexer and store a new input string. +<li><tt>lex.token()</tt>. Return the next token. Returns a special <tt>LexToken</tt> instance on success or +None if the end of the input text has been reached. +</ul> + +The code at the bottom of the example shows how the lexer is actually used. When executed, +the following output will be produced: + +<blockquote> +<pre> +$ python example.py +LexToken(NUMBER,3,2) +LexToken(PLUS,'+',2) +LexToken(NUMBER,4,2) +LexToken(TIMES,'*',2) +LexToken(NUMBER,10,2) +LexToken(PLUS,'+',3) +LexToken(MINUS,'-',3) +LexToken(NUMBER,20,3) +LexToken(TIMES,'*',3) +LexToken(NUMBER,2,3) +</pre> +</blockquote> + +<h2>Lex Implementation Notes</h2> + +<ul> +<li><tt>lex.py</tt> uses the <tt>re</tt> module to do its patten matching. When building the master regular expression, +rules are added in the following order: +<p> +<ol> +<li>All tokens defined by functions are added in the same order as they appear in the lexer file. +<li>Tokens defined by strings are added by sorting them in order of decreasing regular expression length (longer expressions +are added first). +</ol> +<p> +Without this ordering, it can be difficult to correctly match certain types of tokens. For example, if you +wanted to have separate tokens for "=" and "==", you need to make sure that "==" is checked first. By sorting regular +expressions in order of decreasing length, this problem is solved for rules defined as strings. For functions, +the order can be explicitly controlled since rules appearing first are checked first. + +<P> +<li>The lexer requires input to be supplied as a single input string. Since most machines have more than enough memory, this +rarely presents a performance concern. However, it means that the lexer currently can't be used with streaming data +such as open files or sockets. This limitation is primarily a side-effect of using the <tt>re</tt> module. + +<p> +<li> +To handle reserved words, it is usually easier to just match an identifier and do a special name lookup in a function +like this: + +<blockquote> +<pre> +reserved = { + 'if' : 'IF', + 'then' : 'THEN', + 'else' : 'ELSE', + 'while' : 'WHILE', + ... +} + +def t_ID(t): + r'[a-zA-Z_][a-zA-Z_0-9]*' + t.type = reserved.get(t.value,'ID') # Check for reserved words + return t +</pre> +</blockquote> + +<p> +<li>The lexer requires tokens to be defined as class instances with <tt>t.type</tt>, <tt>t.value</tt>, and <tt>t.lineno</tt> +attributes. By default, tokens are created as instances of the <tt>LexToken</tt> class defined internally to <tt>lex.py</tt>. +If desired, you can create new kinds of tokens provided that they have the three required attributes. However, +in practice, it is probably safer to stick with the default. + +<p> +<li>The only safe attribute for assigning token properties is <tt>t.value</tt>. In some cases, you may want to attach +a number of different properties to a token (e.g., symbol table entries for identifiers). To do this, replace <tt>t.value</tt> +with a tuple or class instance. For example: + +<blockquote> +<pre> +def t_ID(t): + ... + # For identifiers, create a (lexeme, symtab) tuple + t.value = (t.value, symbol_lookup(t.value)) + ... + return t +</pre> +</blockquote> + +Although allowed, do NOT assign additional attributes to the token object. For example, +<blockquote> +<pre> +def t_ID(t): + ... + # Bad implementation of above + t.symtab = symbol_lookup(t.value) + ... +</pre> +</blockquote> + +The reason you don't want to do this is that the <tt>yacc.py</tt> +module only provides public access to the <tt>t.value</tt> attribute of each token. +Therefore, any other attributes you assign are inaccessible (if you are familiar +with the internals of C lex/yacc, <tt>t.value</tt> is the same as <tt>yylval.tok</tt>). + +<p> +<li>To track line numbers, the lexer internally maintains a line +number variable. Each token automatically gets the value of the +current line number in the <tt>t.lineno</tt> attribute. To modify the +current line number, simply change the <tt>t.lineno</tt> attribute +in a function rule (as previously shown for +<tt>t_newline()</tt>). Even if the resulting token is discarded, +changes to the line number remain in effect for subsequent tokens. + +<p> +<li>To support multiple scanners in the same application, the <tt>lex.lex()</tt> function +actually returns a special <tt>Lexer</tt> object. This object has two methods +<tt>input()</tt> and <tt>token()</tt> that can be used to supply input and get tokens. For example: + +<blockquote> +<pre> +lexer = lex.lex() +lexer.input(sometext) +while 1: + tok = lexer.token() + if not tok: break + print tok +</pre> +</blockquote> + +The functions <tt>lex.input()</tt> and <tt>lex.token()</tt> are bound to the <tt>input()</tt> +and <tt>token()</tt> methods of the last lexer created by the lex module. + + +<p> +<li>To reduce compiler startup time and improve performance, the lexer can be built in optimized mode as follows: + +<blockquote> +<pre> +lex.lex(optimize=1) +</pre> +</blockquote> + +When used, most error checking and validation is disabled. This provides a slight performance +gain while tokenizing and tends to chop a few tenths of a second off startup time. Since it disables +error checking, this mode is not the default and is not recommended during development. However, once +you have your compiler fully working, it is usually safe to disable the error checks. + +<p> +<li>You can enable some additional debugging by building the lexer like this: + +<blockquote> +<pre> +lex.lex(debug=1) +</pre> +</blockquote> + +<p> +<li>To help you debug your lexer, <tt>lex.py</tt> comes with a simple main program which will either +tokenize input read from standard input or from a file. To use it, simply put this in your lexer: + +<blockquote> +<pre> +if __name__ == '__main__': + lex.runmain() +</pre> +</blockquote> + +Then, run you lexer as a main program such as <tt>python mylex.py</tt> + +<p> +<li>Since the lexer is written entirely in Python, its performance is +largely determined by that of the Python <tt>re</tt> module. Although +the lexer has been written to be as efficient as possible, it's not +blazingly fast when used on very large input files. Sorry. If +performance is concern, you might consider upgrading to the most +recent version of Python, creating a hand-written lexer, or offloading +the lexer into a C extension module. In defense of <tt>lex.py</tt>, +it's performance is not <em>that</em> bad when used on reasonably +sized input files. For instance, lexing a 4700 line C program with +32000 input tokens takes about 20 seconds on a 200 Mhz PC. Obviously, +it will run much faster on a more speedy machine. + +</ul> + +<h2>Parsing basics</h2> + +<tt>yacc.py</tt> is used to parse language syntax. Before showing an +example, there are a few important bits of background that must be +mentioned. First, <tt>syntax</tt> is usually specified in terms of a +context free grammar (CFG). For example, if you wanted to parse +simple arithmetic expressions, you might first write an unambiguous +grammar specification like this: + +<blockquote> +<pre> +expression : expression + term + | expression - term + | term + +term : term * factor + | term / factor + | factor + +factor : NUMBER + | ( expression ) +</pre> +</blockquote> + +Next, the semantic behavior of a language is often specified using a +technique known as syntax directed translation. In syntax directed +translation, attributes are attached to each symbol in a given grammar +rule along with an action. Whenever a particular grammar rule is +recognized, the action describes what to do. For example, given the +expression grammar above, you might write the specification for a +simple calculator like this: + +<blockquote> +<pre> +Grammar Action +-------------------------------- -------------------------------------------- +expression0 : expression1 + term expression0.val = expression1.val + term.val + | expression1 - term expression0.val = expression1.val - term.val + | term expression0.val = term.val + +term0 : term1 * factor term0.val = term1.val * factor.val + | term1 / factor term0.val = term1.val / factor.val + | factor term0.val = factor.val + +factor : NUMBER factor.val = int(NUMBER.lexval) + | ( expression ) factor.val = expression.val +</pre> +</blockquote> + +Finally, Yacc uses a parsing technique known as LR-parsing or shift-reduce parsing. LR parsing is a +bottom up technique that tries to recognize the right-hand-side of various grammar rules. +Whenever a valid right-hand-side is found in the input, the appropriate action code is triggered and the +grammar symbols are replaced by the grammar symbol on the left-hand-side. + +<p> +LR parsing is commonly implemented by shifting grammar symbols onto a stack and looking at the stack and the next +input token for patterns. The details of the algorithm can be found in a compiler text, but the +following example illustrates the steps that are performed if you wanted to parse the expression +<tt>3 + 5 * (10 - 20)</tt> using the grammar defined above: + +<blockquote> +<pre> +Step Symbol Stack Input Tokens Action +---- --------------------- --------------------- ------------------------------- +1 $ 3 + 5 * ( 10 - 20 )$ Shift 3 +2 $ 3 + 5 * ( 10 - 20 )$ Reduce factor : NUMBER +3 $ factor + 5 * ( 10 - 20 )$ Reduce term : factor +4 $ term + 5 * ( 10 - 20 )$ Reduce expr : term +5 $ expr + 5 * ( 10 - 20 )$ Shift + +6 $ expr + 5 * ( 10 - 20 )$ Shift 5 +7 $ expr + 5 * ( 10 - 20 )$ Reduce factor : NUMBER +8 $ expr + factor * ( 10 - 20 )$ Reduce term : factor +9 $ expr + term * ( 10 - 20 )$ Shift * +10 $ expr + term * ( 10 - 20 )$ Shift ( +11 $ expr + term * ( 10 - 20 )$ Shift 10 +12 $ expr + term * ( 10 - 20 )$ Reduce factor : NUMBER +13 $ expr + term * ( factor - 20 )$ Reduce term : factor +14 $ expr + term * ( term - 20 )$ Reduce expr : term +15 $ expr + term * ( expr - 20 )$ Shift - +16 $ expr + term * ( expr - 20 )$ Shift 20 +17 $ expr + term * ( expr - 20 )$ Reduce factor : NUMBER +18 $ expr + term * ( expr - factor )$ Reduce term : factor +19 $ expr + term * ( expr - term )$ Reduce expr : expr - term +20 $ expr + term * ( expr )$ Shift ) +21 $ expr + term * ( expr ) $ Reduce factor : (expr) +22 $ expr + term * factor $ Reduce term : term * factor +23 $ expr + term $ Reduce expr : expr + term +24 $ expr $ Reduce expr +25 $ $ Success! +</pre> +</blockquote> + +When parsing the expression, an underlying state machine and the current input token determine what to do next. +If the next token looks like part of a valid grammar rule (based on other items on the stack), it is generally shifted +onto the stack. If the top of the stack contains a valid right-hand-side of a grammar rule, it is +usually "reduced" and the symbols replaced with the symbol on the left-hand-side. When this reduction occurs, the +appropriate action is triggered (if defined). If the input token can't be shifted and the top of stack doesn't match +any grammar rules, a syntax error has occurred and the parser must take some kind of recovery step (or bail out). + +<p> +It is important to note that the underlying implementation is actually built around a large finite-state machine +and some tables. The construction of these tables is quite complicated and beyond the scope of this discussion. +However, subtle details of this process explain why, in the example above, the parser chooses to shift a token +onto the stack in step 9 rather than reducing the rule <tt>expr : expr + term</tt>. + +<h2>Yacc example</h2> + +Suppose you wanted to make a grammar for simple arithmetic expressions as previously described. Here is +how you would do it with <tt>yacc.py</tt>: + +<blockquote> +<pre> +# Yacc example + +import yacc + +# Get the token map from the lexer. This is required. +from calclex import tokens + +def p_expression_plus(t): + 'expression : expression PLUS term' + t[0] = t[1] + t[3] + +def p_expression_minus(t): + 'expression : expression MINUS term' + t[0] = t[1] - t[3] + +def p_expression_term(t): + 'expression : term' + t[0] = t[1] + +def p_term_times(t): + 'term : term TIMES factor' + t[0] = t[1] * t[3] + +def p_term_div(t): + 'term : term DIVIDE factor' + t[0] = t[1] / t[3] + +def p_term_factor(t): + 'term : factor' + t[0] = t[1] + +def p_factor_num(t): + 'factor : NUMBER' + t[0] = t[1] + +def p_factor_expr(t): + 'factor : LPAREN expression RPAREN' + t[0] = t[2] + +# Error rule for syntax errors +def p_error(t): + print "Syntax error in input!" + +# Build the parser +yacc.yacc() + +while 1: + try: + s = raw_input('calc > ') + except EOFError: + break + if not s: continue + result = yacc.parse(s) + print result +</pre> +</blockquote> + +In this example, each grammar rule is defined by a Python function where the docstring to that function contains the +appropriate context-free grammar specification (an idea borrowed from John Aycock's SPARK toolkit). Each function accepts a single +argument <tt>t</tt> that is a sequence containing the values of each grammar symbol in the corresponding rule. The values of +<tt>t[i]</tt> are mapped to grammar symbols as shown here: + +<blockquote> +<pre> +def p_expression_plus(t): + 'expression : expression PLUS term' + # ^ ^ ^ ^ + # t[0] t[1] t[2] t[3] + + t[0] = t[1] + t[3] +</pre> +</blockquote> + +For tokens, the "value" in the corresponding <tt>t[i]</tt> is the +<em>same</em> as the value of the <tt>t.value</tt> attribute assigned +in the lexer module. For non-terminals, the value is determined by +whatever is placed in <tt>t[0]</tt> when rules are reduced. This +value can be anything at all. However, it probably most common for +the value to be a simple Python type, a tuple, or an instance. In this example, we +are relying on the fact that the <tt>NUMBER</tt> token stores an integer value in its value +field. All of the other rules simply perform various types of integer operations and store +the result. + +<p> +The first rule defined in the yacc specification determines the starting grammar +symbol (in this case, a rule for <tt>expression</tt> appears first). Whenever +the starting rule is reduced by the parser and no more input is available, parsing +stops and the final value is returned (this value will be whatever the top-most rule +placed in <tt>t[0]</tt>). + +<p>The <tt>p_error(t)</tt> rule is defined to catch syntax errors. See the error handling section +below for more detail. + +<p> +To build the parser, call the <tt>yacc.yacc()</tt> function. This function +looks at the module and attempts to construct all of the LR parsing tables for the grammar +you have specified. The first time <tt>yacc.yacc()</tt> is invoked, you will get a message +such as this: + +<blockquote> +<pre> +$ python calcparse.py +yacc: Generating SLR parsing table... +calc > +</pre> +</blockquote> + +Since table construction is relatively expensive (especially for large +grammars), the resulting parsing table is written to the current +directory in a file called <tt>parsetab.py</tt>. In addition, a +debugging file called <tt>parser.out</tt> is created. On subsequent +executions, <tt>yacc</tt> will reload the table from +<tt>parsetab.py</tt> unless it has detected a change in the underlying +grammar (in which case the tables and <tt>parsetab.py</tt> file are +regenerated). + +<p> +If any errors are detected in your grammar specification, <tt>yacc.py</tt> will produce +diagnostic messages and possibly raise an exception. Some of the errors that can be detected include: + +<ul> +<li>Duplicated function names (if more than one rule function have the same name in the grammar file). +<li>Shift/reduce and reduce/reduce conflicts generated by ambiguous grammars. +<li>Badly specified grammar rules. +<li>Infinite recursion (rules that can never terminate). +<li>Unused rules and tokens +<li>Undefined rules and tokens +</ul> + +The next few sections now discuss a few finer points of grammar construction. + +<h2>Combining Grammar Rule Functions</h2> + +When grammar rules are similar, they can be combined into a single function. +For example, consider the two rules in our earlier example: + +<blockquote> +<pre> +def p_expression_plus(t): + 'expression : expression PLUS term' + t[0] = t[1] + t[3] + +def p_expression_minus(t): + 'expression : expression MINUS term' + t[0] = t[1] - t[3] +</pre> +</blockquote> + +Instead of writing two functions, you might write a single function like this: + +<blockquote> +<pre> +def p_expression(t): + '''expression : expression PLUS term + | expression MINUS term''' + if t[2] == '+': + t[0] = t[1] + t[3] + elif t[2] == '-': + t[0] = t[1] - t[3] +</pre> +</blockquote> + +In general, the doc string for any given function can contain multiple grammar rules. So, it would +have also been legal (although possibly confusing) to write this: + +<blockquote> +<pre> +def p_binary_operators(t): + '''expression : expression PLUS term + | expression MINUS term + term : term TIMES factor + | term DIVIDE factor''' + if t[2] == '+': + t[0] = t[1] + t[3] + elif t[2] == '-': + t[0] = t[1] - t[3] + elif t[2] == '*': + t[0] = t[1] * t[3] + elif t[2] == '/': + t[0] = t[1] / t[3] +</pre> +</blockquote> + +When combining grammar rules into a single function, it is usually a good idea for all of the rules to have +a similar structure (e.g., the same number of terms). Otherwise, the corresponding action code may be more +complicated than necessary. + +<h2>Empty Productions</h2> + +<tt>yacc.py</tt> can handle empty productions by defining a rule like this: + +<blockquote> +<pre> +def p_empty(t): + 'empty :' + pass +</pre> +</blockquote> + +Now to use the empty production, simply use 'empty' as a symbol. For example: + +<blockquote> +<pre> +def p_optitem(t): + 'optitem : item' + ' | empty' + ... +</pre> +</blockquote> + +<h2>Dealing With Ambiguous Grammars</h2> + +The expression grammar given in the earlier example has been written in a special format to eliminate ambiguity. +However, in many situations, it is extremely difficult or awkward to write grammars in this format. A +much more natural way to express the grammar is in a more compact form like this: + +<blockquote> +<pre> +expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression + | LPAREN expression RPAREN + | NUMBER +</pre> +</blockquote> + +Unfortunately, this grammar specification is ambiguous. For example, if you are parsing the string +"3 * 4 + 5", there is no way to tell how the operators are supposed to be grouped. +For example, does this expression mean "(3 * 4) + 5" or is it "3 * (4+5)"? + +<p> +When an ambiguous grammar is given to <tt>yacc.py</tt> it will print messages about "shift/reduce conflicts" +or a "reduce/reduce conflicts". A shift/reduce conflict is caused when the parser generator can't decide +whether or not to reduce a rule or shift a symbol on the parsing stack. For example, consider +the string "3 * 4 + 5" and the internal parsing stack: + +<blockquote> +<pre> +Step Symbol Stack Input Tokens Action +---- --------------------- --------------------- ------------------------------- +1 $ 3 * 4 + 5$ Shift 3 +2 $ 3 * 4 + 5$ Reduce : expression : NUMBER +3 $ expr * 4 + 5$ Shift * +4 $ expr * 4 + 5$ Shift 4 +5 $ expr * 4 + 5$ Reduce: expression : NUMBER +6 $ expr * expr + 5$ SHIFT/REDUCE CONFLICT ???? +</pre> +</blockquote> + +In this case, when the parser reaches step 6, it has two options. One is the reduce the +rule <tt>expr : expr * expr</tt> on the stack. The other option is to shift the +token <tt>+</tt> on the stack. Both options are perfectly legal from the rules +of the context-free-grammar. + +<p> +By default, all shift/reduce conflicts are resolved in favor of shifting. Therefore, in the above +example, the parser will always shift the <tt>+</tt> instead of reducing. Although this +strategy works in many cases (including the ambiguous if-then-else), it is not enough for arithmetic +expressions. In fact, in the above example, the decision to shift <tt>+</tt> is completely wrong---we should have +reduced <tt>expr * expr</tt> since multiplication has higher precedence than addition. + +<p>To resolve ambiguity, especially in expression grammars, <tt>yacc.py</tt> allows individual +tokens to be assigned a precedence level and associativity. This is done by adding a variable +<tt>precedence</tt> to the grammar file like this: + +<blockquote> +<pre> +precedence = ( + ('left', 'PLUS', 'MINUS'), + ('left', 'TIMES', 'DIVIDE'), +) +</pre> +</blockquote> + +This declaration specifies that <tt>PLUS</tt>/<tt>MINUS</tt> have +the same precedence level and are left-associative and that +<tt>TIMES</tt>/<tt>DIVIDE</tt> have the same precedence and are left-associative. +Furthermore, the declaration specifies that <tt>TIMES</tt>/<tt>DIVIDE</tt> have higher +precedence than <tt>PLUS</tt>/<tt>MINUS</tt> (since they appear later in the +precedence specification). + +<p> +The precedence specification is used to attach a numerical precedence value and associativity direction +to each grammar rule. This is always determined by the precedence of the right-most terminal symbol. Therefore, +if PLUS/MINUS had a precedence of 1 and TIMES/DIVIDE had a precedence of 2, the grammar rules +would have precedence values as follows: + +<blockquote> +<pre> +expression : expression PLUS expression # prec = 1, left + | expression MINUS expression # prec = 1, left + | expression TIMES expression # prec = 2, left + | expression DIVIDE expression # prec = 2, left + | LPAREN expression RPAREN # prec = unknown + | NUMBER # prec = unknown +</pre> +</blockquote> + +When shift/reduce conflicts are encountered, the parser generator resolves the conflict by +looking at the precedence rules and associativity specifiers. + +<p> +<ol> +<li>If the current token has higher precedence, it is shifted. +<li>If the grammar rule on the stack has higher precedence, the rule is reduced. +<li>If the current token and the grammar rule have the same precedence, the +rule is reduced for left associativity, whereas the token is shifted for right associativity. +<li>If nothing is known about the precedence, shift/reduce conflicts are resolved in +favor of shifting (the default). +</ol> + +<p> +When shift/reduce conflicts are resolved using the first three techniques (with the help of +precedence rules), <tt>yacc.py</tt> will report no errors or conflicts in the grammar. + +<p> +One problem with the precedence specifier technique is that it is sometimes necessary to +change the precedence of an operator in certain contents. For example, consider a unary-minus operator +in "3 + 4 * -5". Normally, unary minus has a very high precedence--being evaluated before the multiply. +However, in our precedence specifier, MINUS has a lower precedence than TIMES. To deal with this, +precedence rules can be given for fictitious tokens like this: + +<blockquote> +<pre> +precedence = ( + ('left', 'PLUS', 'MINUS'), + ('left', 'TIMES', 'DIVIDE'), + ('right', 'UMINUS'), # Unary minus operator +) +</pre> +</blockquote> + +Now, in the grammar file, we can write our unary minus rule like this: + +<blockquote> +<pre> +def p_expr_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] +</pre> +</blockquote> + +In this case, <tt>%prec UMINUS</tt> overrides the default rule precedence--setting it to that +of UMINUS in the precedence specifier. + +<p> +It is also possible to specify non-associativity in the <tt>precedence</tt> table. This would +be used when you <em>don't</em> want operations to chain together. For example, suppose +you wanted to support a comparison operators like <tt><</tt> and <tt>></tt> but you didn't want to allow +combinations like <tt>a < b < c</tt>. To do this, simply specify a rule like this: + +<blockquote> +<pre> +precedence = ( + ('nonassoc', 'LESSTHAN', 'GREATERTHAN'), # Nonassociative operators + ('left', 'PLUS', 'MINUS'), + ('left', 'TIMES', 'DIVIDE'), + ('right', 'UMINUS'), # Unary minus operator +) +</pre> +</blockquote> + +<p> +Reduce/reduce conflicts are caused when there are multiple grammar +rules that can be applied to a given set of symbols. This kind of +conflict is almost always bad and is always resolved by picking the +rule that appears first in the grammar file. Reduce/reduce conflicts +are almost always caused when different sets of grammar rules somehow +generate the same set of symbols. For example: + +<blockquote> +<pre> +assignment : ID EQUALS NUMBER + | ID EQUALS expression + +expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression + | LPAREN expression RPAREN + | NUMBER +</pre> +</blockquote> + +In this case, a reduce/reduce conflict exists between these two rules: + +<blockquote> +<pre> +assignment : ID EQUALS NUMBER +expression : NUMBER +</pre> +</blockquote> + +For example, if you wrote "a = 5", the parser can't figure out if this +is supposed to reduced as <tt>assignment : ID EQUALS NUMBER</tt> or +whether it's supposed to reduce the 5 as an expression and then reduce +the rule <tt>assignment : ID EQUALS expression</tt>. + +<h2>The parser.out file</h2> + +Tracking down shift/reduce and reduce/reduce conflicts is one of the finer pleasures of using an LR +parsing algorithm. To assist in debugging, <tt>yacc.py</tt> creates a debugging file called +'parser.out' when it generates the parsing table. The contents of this file look like the following: + +<blockquote> +<pre> +Unused terminals: + + +Grammar + +Rule 1 expression -> expression PLUS expression +Rule 2 expression -> expression MINUS expression +Rule 3 expression -> expression TIMES expression +Rule 4 expression -> expression DIVIDE expression +Rule 5 expression -> NUMBER +Rule 6 expression -> LPAREN expression RPAREN + +Terminals, with rules where they appear + +TIMES : 3 +error : +MINUS : 2 +RPAREN : 6 +LPAREN : 6 +DIVIDE : 4 +PLUS : 1 +NUMBER : 5 + +Nonterminals, with rules where they appear + +expression : 1 1 2 2 3 3 4 4 6 0 + + +Parsing method: SLR + + +state 0 + + S' -> . expression + expression -> . expression PLUS expression + expression -> . expression MINUS expression + expression -> . expression TIMES expression + expression -> . expression DIVIDE expression + expression -> . NUMBER + expression -> . LPAREN expression RPAREN + + NUMBER shift and go to state 3 + LPAREN shift and go to state 2 + + +state 1 + + S' -> expression . + expression -> expression . PLUS expression + expression -> expression . MINUS expression + expression -> expression . TIMES expression + expression -> expression . DIVIDE expression + + PLUS shift and go to state 6 + MINUS shift and go to state 5 + TIMES shift and go to state 4 + DIVIDE shift and go to state 7 + + +state 2 + + expression -> LPAREN . expression RPAREN + expression -> . expression PLUS expression + expression -> . expression MINUS expression + expression -> . expression TIMES expression + expression -> . expression DIVIDE expression + expression -> . NUMBER + expression -> . LPAREN expression RPAREN + + NUMBER shift and go to state 3 + LPAREN shift and go to state 2 + + +state 3 + + expression -> NUMBER . + + $ reduce using rule 5 + PLUS reduce using rule 5 + MINUS reduce using rule 5 + TIMES reduce using rule 5 + DIVIDE reduce using rule 5 + RPAREN reduce using rule 5 + + +state 4 + + expression -> expression TIMES . expression + expression -> . expression PLUS expression + expression -> . expression MINUS expression + expression -> . expression TIMES expression + expression -> . expression DIVIDE expression + expression -> . NUMBER + expression -> . LPAREN expression RPAREN + + NUMBER shift and go to state 3 + LPAREN shift and go to state 2 + + +state 5 + + expression -> expression MINUS . expression + expression -> . expression PLUS expression + expression -> . expression MINUS expression + expression -> . expression TIMES expression + expression -> . expression DIVIDE expression + expression -> . NUMBER + expression -> . LPAREN expression RPAREN + + NUMBER shift and go to state 3 + LPAREN shift and go to state 2 + + +state 6 + + expression -> expression PLUS . expression + expression -> . expression PLUS expression + expression -> . expression MINUS expression + expression -> . expression TIMES expression + expression -> . expression DIVIDE expression + expression -> . NUMBER + expression -> . LPAREN expression RPAREN + + NUMBER shift and go to state 3 + LPAREN shift and go to state 2 + + +state 7 + + expression -> expression DIVIDE . expression + expression -> . expression PLUS expression + expression -> . expression MINUS expression + expression -> . expression TIMES expression + expression -> . expression DIVIDE expression + expression -> . NUMBER + expression -> . LPAREN expression RPAREN + + NUMBER shift and go to state 3 + LPAREN shift and go to state 2 + + +state 8 + + expression -> LPAREN expression . RPAREN + expression -> expression . PLUS expression + expression -> expression . MINUS expression + expression -> expression . TIMES expression + expression -> expression . DIVIDE expression + + RPAREN shift and go to state 13 + PLUS shift and go to state 6 + MINUS shift and go to state 5 + TIMES shift and go to state 4 + DIVIDE shift and go to state 7 + + +state 9 + + expression -> expression TIMES expression . + expression -> expression . PLUS expression + expression -> expression . MINUS expression + expression -> expression . TIMES expression + expression -> expression . DIVIDE expression + + $ reduce using rule 3 + PLUS reduce using rule 3 + MINUS reduce using rule 3 + TIMES reduce using rule 3 + DIVIDE reduce using rule 3 + RPAREN reduce using rule 3 + + ! PLUS [ shift and go to state 6 ] + ! MINUS [ shift and go to state 5 ] + ! TIMES [ shift and go to state 4 ] + ! DIVIDE [ shift and go to state 7 ] + +state 10 + + expression -> expression MINUS expression . + expression -> expression . PLUS expression + expression -> expression . MINUS expression + expression -> expression . TIMES expression + expression -> expression . DIVIDE expression + + $ reduce using rule 2 + PLUS reduce using rule 2 + MINUS reduce using rule 2 + RPAREN reduce using rule 2 + TIMES shift and go to state 4 + DIVIDE shift and go to state 7 + + ! TIMES [ reduce using rule 2 ] + ! DIVIDE [ reduce using rule 2 ] + ! PLUS [ shift and go to state 6 ] + ! MINUS [ shift and go to state 5 ] + +state 11 + + expression -> expression PLUS expression . + expression -> expression . PLUS expression + expression -> expression . MINUS expression + expression -> expression . TIMES expression + expression -> expression . DIVIDE expression + + $ reduce using rule 1 + PLUS reduce using rule 1 + MINUS reduce using rule 1 + RPAREN reduce using rule 1 + TIMES shift and go to state 4 + DIVIDE shift and go to state 7 + + ! TIMES [ reduce using rule 1 ] + ! DIVIDE [ reduce using rule 1 ] + ! PLUS [ shift and go to state 6 ] + ! MINUS [ shift and go to state 5 ] + +state 12 + + expression -> expression DIVIDE expression . + expression -> expression . PLUS expression + expression -> expression . MINUS expression + expression -> expression . TIMES expression + expression -> expression . DIVIDE expression + + $ reduce using rule 4 + PLUS reduce using rule 4 + MINUS reduce using rule 4 + TIMES reduce using rule 4 + DIVIDE reduce using rule 4 + RPAREN reduce using rule 4 + + ! PLUS [ shift and go to state 6 ] + ! MINUS [ shift and go to state 5 ] + ! TIMES [ shift and go to state 4 ] + ! DIVIDE [ shift and go to state 7 ] + +state 13 + + expression -> LPAREN expression RPAREN . + + $ reduce using rule 6 + PLUS reduce using rule 6 + MINUS reduce using rule 6 + TIMES reduce using rule 6 + DIVIDE reduce using rule 6 + RPAREN reduce using rule 6 +</pre> +</blockquote> + +In the file, each state of the grammar is described. Within each state the "." indicates the current +location of the parse within any applicable grammar rules. In addition, the actions for each valid +input token are listed. When a shift/reduce or reduce/reduce conflict arises, rules <em>not</em> selected +are prefixed with an !. For example: + +<blockquote> +<pre> + ! TIMES [ reduce using rule 2 ] + ! DIVIDE [ reduce using rule 2 ] + ! PLUS [ shift and go to state 6 ] + ! MINUS [ shift and go to state 5 ] +</pre> +</blockquote> + +By looking at these rules (and with a little practice), you can usually track down the source +of most parsing conflicts. It should also be stressed that not all shift-reduce conflicts are +bad. However, the only way to be sure that they are resolved correctly is to look at <tt>parser.out</tt>. + +<h2>Syntax Error Handling</h2> + +When a syntax error occurs during parsing, the error is immediately +detected (i.e., the parser does not read any more tokens beyond the +source of the error). Error recovery in LR parsers is a delicate +topic that involves ancient rituals and black-magic. The recovery mechanism +provided by <tt>yacc.py</tt> is comparable to Unix yacc so you may want +consult a book like O'Reilly's "Lex and Yacc" for some of the finer details. + +<p> +When a syntax error occurs, <tt>yacc.py</tt> performs the following steps: + +<ol> +<li>On the first occurrence of an error, the user-defined <tt>p_error()</tt> function +is called with the offending token as an argument. Afterwards, the parser enters +an "error-recovery" mode in which it will not make future calls to <tt>p_error()</tt> until it +has successfully shifted at least 3 tokens onto the parsing stack. + +<p> +<li>If no recovery action is taken in <tt>p_error()</tt>, the offending lookahead token is replaced +with a special <tt>error</tt> token. + +<p> +<li>If the offending lookahead token is already set to <tt>error</tt>, the top item of the parsing stack is +deleted. + +<p> +<li>If the entire parsing stack is unwound, the parser enters a restart state and attempts to start +parsing from its initial state. + +<p> +<li>If a grammar rule accepts <tt>error</tt> as a token, it will be +shifted onto the parsing stack. + +<p> +<li>If the top item of the parsing stack is <tt>error</tt>, lookahead tokens will be discarded until the +parser can successfully shift a new symbol or reduce a rule involving <tt>error</tt>. +</ol> + +<h4>Recovery and resynchronization with error rules</h4> + +The most well-behaved approach for handling syntax errors is to write grammar rules that include the <tt>error</tt> +token. For example, suppose your language had a grammar rule for a print statement like this: + +<blockquote> +<pre> +def p_statement_print(t): + 'statement : PRINT expr SEMI' + ... +</pre> +</blockquote> + +To account for the possibility of a bad expression, you might write an additional grammar rule like this: + +<blockquote> +<pre> +def p_statement_print_error(t): + 'statement : PRINT error SEMI' + print "Syntax error in print statement. Bad expression" + +</pre> +</blockquote> + +In this case, the <tt>error</tt> token will match any sequence of +tokens that might appear up to the first semicolon that is +encountered. Once the semicolon is reached, the rule will be +invoked and the <tt>error</tt> token will go away. + +<p> +This type of recovery is sometimes known as parser resynchronization. +The <tt>error</tt> token acts as a wildcard for any bad input text and +the token immediately following <tt>error</tt> acts as a +synchronization token. + +<p> +It is important to note that the <tt>error</tt> token usually does not appear as the last token +on the right in an error rule. For example: + +<blockquote> +<pre> +def p_statement_print_error(t): + 'statement : PRINT error' + print "Syntax error in print statement. Bad expression" +</pre> +</blockquote> + +This is because the first bad token encountered will cause the rule to +be reduced--which may make it difficult to recover if more bad tokens +immediately follow. + +<h4>Panic mode recovery</h4> + +An alternative error recovery scheme is to enter a panic mode recovery in which tokens are +discarded to a point where the parser might be able to recover in some sensible manner. + +<p> +Panic mode recovery is implemented entirely in the <tt>p_error()</tt> function. For example, this +function starts discarding tokens until it reaches a closing '}'. Then, it restarts the +parser in its initial state. + +<blockquote> +<pre> +def p_error(t): + print "Whoa. You are seriously hosed." + # Read ahead looking for a closing '}' + while 1: + tok = yacc.token() # Get the next token + if not tok or tok.type == 'RBRACE': break + yacc.restart() +</pre> +</blockquote> + +<p> +This function simply discards the bad token and tells the parser that the error was ok. + +<blockquote> +<pre> +def p_error(t): + print "Syntax error at token", t.type + # Just discard the token and tell the parser it's okay. + yacc.errok() +</pre> +</blockquote> + +<P> +Within the <tt>p_error()</tt> function, three functions are available to control the behavior +of the parser: +<p> +<ul> +<li><tt>yacc.errok()</tt>. This resets the parser state so it doesn't think it's in error-recovery +mode. This will prevent an <tt>error</tt> token from being generated and will reset the internal +error counters so that the next syntax error will call <tt>p_error()</tt> again. + +<p> +<li><tt>yacc.token()</tt>. This returns the next token on the input stream. + +<p> +<li><tt>yacc.restart()</tt>. This discards the entire parsing stack and resets the parser +to its initial state. +</ul> + +Note: these functions are only available when invoking <tt>p_error()</tt> and are not available +at any other time. + +<p> +To supply the next lookahead token to the parser, <tt>p_error()</tt> can return a token. This might be +useful if trying to synchronize on special characters. For example: + +<blockquote> +<pre> +def p_error(t): + # Read ahead looking for a terminating ";" + while 1: + tok = yacc.token() # Get the next token + if not tok or tok.type == 'SEMI': break + yacc.errok() + + # Return SEMI to the parser as the next lookahead token + return tok +</pre> +</blockquote> + +<h4>General comments on error handling</h4> + +For normal types of languages, error recovery with error rules and resynchronization characters is probably the most reliable +technique. This is because you can instrument the grammar to catch errors at selected places where it is relatively easy +to recover and continue parsing. Panic mode recovery is really only useful in certain specialized applications where you might want +to discard huge portions of the input text to find a valid restart point. + +<h2>Line Number Tracking</h2> + +<tt>yacc.py</tt> automatically tracks line numbers for all of the grammar symbols and tokens it processes. To retrieve the line +numbers, two functions are used in grammar rules: + +<ul> +<li><tt>t.lineno(num)</tt>. Return the starting line number for symbol <em>num</em> +<li><tt>t.linespan(num)</tt>. Return a tuple (startline,endline) with the starting and ending line number for symbol <em>num</em>. +</ul> + +For example: + +<blockquote> +<pre> +def t_expression(t): + 'expression : expression PLUS expression' + t.lineno(1) # Line number of the left expression + t.lineno(2) # line number of the PLUS operator + t.lineno(3) # line number of the right expression + ... + start,end = t.linespan(3) # Start,end lines of the right expression + +</pre> +</blockquote> + +Since line numbers are managed internally by the parser, there is usually no need to modify the line +numbers. However, if you want to save the line numbers in a parse-tree node, you will need to make your own +private copy. + +<h2>AST Construction</h2> + +<tt>yacc.py</tt> provides no special functions for constructing an abstract syntax tree. However, such +construction is easy enough to do on your own. Simply create a data structure for abstract syntax tree nodes +and assign nodes to <tt>t[0]</tt> in each rule. + +For example: + +<blockquote> +<pre> +class Expr: pass + +class BinOp(Expr): + def __init__(self,left,op,right): + self.type = "binop" + self.left = left + self.right = right + self.op = op + +class Number(Expr): + def __init__(self,value): + self.type = "number" + self.value = value + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + + t[0] = BinOp(t[1],t[2],t[3]) + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = Number(t[1]) +</pre> +</blockquote> + +To simplify tree traversal, it may make sense to pick a very generic tree structure for your parse tree nodes. +For example: + +<blockquote> +<pre> +class Node: + def __init__(self,type,children=None,leaf=None): + self.type = type + if children: + self.children = children + else: + self.children = [ ] + self.leaf = leaf + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + + t[0] = Node("binop", [t[1],t[3]], t[2]) +</pre> +</blockquote> + +<h2>Yacc implementation notes</h2> + +<ul> +<li>By default, <tt>yacc.py</tt> relies on <tt>lex.py</tt> for tokenizing. However, an alternative tokenizer +can be supplied as follows: + +<blockquote> +<pre> +yacc.parse(lexer=x) +</pre> +</blockquote> +in this case, <tt>x</tt> must be a Lexer object that minimally has a <tt>x.token()</tt> method for retrieving the next +token. If an input string is given to <tt>yacc.parse()</tt>, the lexer must also have an <tt>x.input()</tt> method. + +<p> +<li>By default, the yacc generates tables in debugging mode (which produces the parser.out file and other output). +To disable this, use + +<blockquote> +<pre> +yacc.yacc(debug=0) +</pre> +</blockquote> + +<p> +<li>To change the name of the <tt>parsetab.py</tt> file, use: + +<blockquote> +<pre> +yacc.yacc(tabmodule="foo") +</pre> +</blockquote> + +<P> +<li>To print copious amounts of debugging during parsing, use: + +<blockquote> +<pre> +yacc.parse(debug=1) +</pre> +</blockquote> + +<p> +<li>The <tt>yacc.yacc()</tt> function really returns a parser object. If you want to support multiple +parsers in the same application, do this: + +<blockquote> +<pre> +p = yacc.yacc() +... +p.parse() +</pre> +</blockquote> + +Note: The function <tt>yacc.parse()</tt> is bound to the last parser that was generated. + +<p> +<li>Since the generation of the SLR tables is relatively expensive, previously generated tables are +cached and reused if possible. The decision to regenerate the tables is determined by taking an MD5 +checksum of all grammar rules and precedence rules. Only in the event of a mismatch are the tables regenerated. + +<p> +It should be noted that table generation is reasonably efficient, even for grammars that involve around a 100 rules +and several hundred states. For more complex languages such as C, table generation may take 30-60 seconds on a slow +machine. Please be patient. + +<p> +<li>Since LR parsing is mostly driven by tables, the performance of the parser is largely independent of the +size of the grammar. The biggest bottlenecks will be the lexer and the complexity of your grammar rules. +</ul> + +<h2>Parser and Lexer State Management</h2> + +In advanced parsing applications, you may want to have multiple +parsers and lexers. Furthermore, the parser may want to control the +behavior of the lexer in some way. + +<p> +To do this, it is important to note that both the lexer and parser are +actually implemented as objects. These objects are returned by the +<tt>lex()</tt> and <tt>yacc()</tt> functions respectively. For example: + +<blockquote> +<pre> +lexer = lex.lex() # Return lexer object +parser = yacc.yacc() # Return parser object +</pre> +</blockquote> + +Within lexer and parser rules, these objects are also available. In the lexer, +the "lexer" attribute of a token refers to the lexer object in use. For example: + +<blockquote> +<pre> +def t_NUMBER(t): + r'\d+' + ... + print t.lexer # Show lexer object +</pre> +</blockquote> + +In the parser, the "lexer" and "parser" attributes refer to the lexer +and parser objects respectively. + +<blockquote> +<pre> +def p_expr_plus(t): + 'expr : expr PLUS expr' + ... + print t.parser # Show parser object + print t.lexer # Show lexer object +</pre> +</blockquote> + +If necessary, arbitrary attributes can be attached to the lexer or parser object. +For example, if you wanted to have different parsing modes, you could attach a mode +attribute to the parser object and look at it later. + +<h2>Using Python's Optimized Mode</h2> + +Because PLY uses information from doc-strings, parsing and lexing +information must be gathered while running the Python interpreter in +normal mode (i.e., not with the -O or -OO options). However, if you +specify optimized mode like this: + +<blockquote> +<pre> +lex.lex(optimize=1) +yacc.yacc(optimize=1) +</pre> +</blockquote> + +then PLY can later be used when Python runs in optimized mode. To make this work, +make sure you first run Python in normal mode. Once the lexing and parsing tables +have been generated the first time, run Python in optimized mode. PLY will use +the tables without the need for doc strings. + +<p> +Beware: running PLY in optimized mode disables a lot of error +checking. You should only do this when your project has stabilized +and you don't need to do any debugging. + +<h2>Where to go from here?</h2> + +The <tt>examples</tt> directory of the PLY distribution contains several simple examples. Please consult a +compilers textbook for the theory and underlying implementation details or LR parsing. + +</body> +</html> + + + + + + + diff --git a/ext/ply/example/ansic/README b/ext/ply/example/ansic/README new file mode 100644 index 000000000..e049d3b4e --- /dev/null +++ b/ext/ply/example/ansic/README @@ -0,0 +1,2 @@ +This example is incomplete. Was going to specify an ANSI C parser. +This is part of it. diff --git a/ext/ply/example/ansic/clex.py b/ext/ply/example/ansic/clex.py new file mode 100644 index 000000000..afd995208 --- /dev/null +++ b/ext/ply/example/ansic/clex.py @@ -0,0 +1,161 @@ +# ---------------------------------------------------------------------- +# clex.py +# +# A lexer for ANSI C. +# ---------------------------------------------------------------------- + +import lex + +# Reserved words +reserved = ( + 'AUTO', 'BREAK', 'CASE', 'CHAR', 'CONST', 'CONTINUE', 'DEFAULT', 'DO', 'DOUBLE', + 'ELSE', 'ENUM', 'EXTERN', 'FLOAT', 'FOR', 'GOTO', 'IF', 'INT', 'LONG', 'REGISTER', + 'RETURN', 'SHORT', 'SIGNED', 'SIZEOF', 'STATIC', 'STRUCT', 'SWITCH', 'TYPEDEF', + 'UNION', 'UNSIGNED', 'VOID', 'VOLATILE', 'WHILE', + ) + +tokens = reserved + ( + # Literals (identifier, integer constant, float constant, string constant, char const) + 'ID', 'TYPEID', 'ICONST', 'FCONST', 'SCONST', 'CCONST', + + # Operators (+,-,*,/,%,|,&,~,^,<<,>>, ||, &&, !, <, <=, >, >=, ==, !=) + 'PLUS', 'MINUS', 'TIMES', 'DIVIDE', 'MOD', + 'OR', 'AND', 'NOT', 'XOR', 'LSHIFT', 'RSHIFT', + 'LOR', 'LAND', 'LNOT', + 'LT', 'LE', 'GT', 'GE', 'EQ', 'NE', + + # Assignment (=, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |=) + 'EQUALS', 'TIMESEQUAL', 'DIVEQUAL', 'MODEQUAL', 'PLUSEQUAL', 'MINUSEQUAL', + 'LSHIFTEQUAL','RSHIFTEQUAL', 'ANDEQUAL', 'XOREQUAL', 'OREQUAL', + + # Increment/decrement (++,--) + 'PLUSPLUS', 'MINUSMINUS', + + # Structure dereference (->) + 'ARROW', + + # Conditional operator (?) + 'CONDOP', + + # Delimeters ( ) [ ] { } , . ; : + 'LPAREN', 'RPAREN', + 'LBRACKET', 'RBRACKET', + 'LBRACE', 'RBRACE', + 'COMMA', 'PERIOD', 'SEMI', 'COLON', + + # Ellipsis (...) + 'ELLIPSIS', + ) + +# Completely ignored characters +t_ignore = ' \t\x0c' + +# Newlines +def t_NEWLINE(t): + r'\n+' + t.lineno += t.value.count("\n") + +# Operators +t_PLUS = r'\+' +t_MINUS = r'-' +t_TIMES = r'\*' +t_DIVIDE = r'/' +t_MOD = r'%' +t_OR = r'\|' +t_AND = r'&' +t_NOT = r'~' +t_XOR = r'^' +t_LSHIFT = r'<<' +t_RSHIFT = r'>>' +t_LOR = r'\|\|' +t_LAND = r'&&' +t_LNOT = r'!' +t_LT = r'<' +t_GT = r'>' +t_LE = r'<=' +t_GE = r'>=' +t_EQ = r'==' +t_NE = r'!=' + +# Assignment operators + +t_EQUALS = r'=' +t_TIMESEQUAL = r'\*=' +t_DIVEQUAL = r'/=' +t_MODEQUAL = r'%=' +t_PLUSEQUAL = r'\+=' +t_MINUSEQUAL = r'-=' +t_LSHIFTEQUAL = r'<<=' +t_RSHIFTEQUAL = r'>>=' +t_ANDEQUAL = r'&=' +t_OREQUAL = r'\|=' +t_XOREQUAL = r'^=' + +# Increment/decrement +t_PLUSPLUS = r'\+\+' +t_MINUSMINUS = r'--' + +# -> +t_ARROW = r'->' + +# ? +t_CONDOP = r'\?' + +# Delimeters +t_LPAREN = r'\(' +t_RPAREN = r'\)' +t_LBRACKET = r'\[' +t_RBRACKET = r'\]' +t_LBRACE = r'\{' +t_RBRACE = r'\}' +t_COMMA = r',' +t_PERIOD = r'\.' +t_SEMI = r';' +t_COLON = r':' +t_ELLIPSIS = r'\.\.\.' + +# Identifiers and reserved words + +reserved_map = { } +for r in reserved: + reserved_map[r.lower()] = r + +def t_ID(t): + r'[A-Za-z_][\w_]*' + t.type = reserved_map.get(t.value,"ID") + return t + +# Integer literal +t_ICONST = r'\d+([uU]|[lL]|[uU][lL]|[lL][uU])?' + +# Floating literal +t_FCONST = r'((\d+)(\.\d+)(e(\+|-)?(\d+))? | (\d+)e(\+|-)?(\d+))([lL]|[fF])?' + +# String literal +t_SCONST = r'\"([^\\\n]|(\\.))*?\"' + +# Character constant 'c' or L'c' +t_CCONST = r'(L)?\'([^\\\n]|(\\.))*?\'' + +# Comments +def t_comment(t): + r' /\*(.|\n)*?\*/' + t.lineno += t.value.count('\n') + +# Preprocessor directive (ignored) +def t_preprocessor(t): + r'\#(.)*?\n' + t.lineno += 1 + +def t_error(t): + print "Illegal character %s" % repr(t.value[0]) + t.skip(1) + +lexer = lex.lex(optimize=1) +if __name__ == "__main__": + lex.runmain(lexer) + + + + + diff --git a/ext/ply/example/ansic/cparse.py b/ext/ply/example/ansic/cparse.py new file mode 100644 index 000000000..ddfd5c72b --- /dev/null +++ b/ext/ply/example/ansic/cparse.py @@ -0,0 +1,859 @@ +# ----------------------------------------------------------------------------- +# cparse.py +# +# Simple parser for ANSI C. Based on the grammar in K&R, 2nd Ed. +# ----------------------------------------------------------------------------- + +import yacc +import clex + +# Get the token map +tokens = clex.tokens + +# translation-unit: + +def p_translation_unit_1(t): + 'translation_unit : external_declaration' + pass + +def p_translation_unit_2(t): + 'translation_unit : translation_unit external_declaration' + pass + +# external-declaration: + +def p_external_declaration_1(t): + 'external_declaration : function_definition' + pass + +def p_external_declaration_2(t): + 'external_declaration : declaration' + pass + +# function-definition: + +def p_function_definition_1(t): + 'function_definition : declaration_specifiers declarator declaration_list compound_statement' + pass + +def p_function_definition_2(t): + 'function_definition : declarator declaration_list compound_statement' + pass + +def p_function_definition_3(t): + 'function_definition : declarator compound_statement' + pass + +def p_function_definition_4(t): + 'function_definition : declaration_specifiers declarator compound_statement' + pass + +# declaration: + +def p_declaration_1(t): + 'declaration : declaration_specifiers init_declarator_list SEMI' + pass + +def p_declaration_2(t): + 'declaration : declaration_specifiers SEMI' + pass + +# declaration-list: + +def p_declaration_list_1(t): + 'declaration_list : declaration' + pass + +def p_declaration_list_2(t): + 'declaration_list : declaration_list declaration ' + pass + +# declaration-specifiers +def p_declaration_specifiers_1(t): + 'declaration_specifiers : storage_class_specifier declaration_specifiers' + pass + +def p_declaration_specifiers_2(t): + 'declaration_specifiers : type_specifier declaration_specifiers' + pass + +def p_declaration_specifiers_3(t): + 'declaration_specifiers : type_qualifier declaration_specifiers' + pass + +def p_declaration_specifiers_4(t): + 'declaration_specifiers : storage_class_specifier' + pass + +def p_declaration_specifiers_5(t): + 'declaration_specifiers : type_specifier' + pass + +def p_declaration_specifiers_6(t): + 'declaration_specifiers : type_qualifier' + pass + +# storage-class-specifier +def p_storage_class_specifier(t): + '''storage_class_specifier : AUTO + | REGISTER + | STATIC + | EXTERN + | TYPEDEF + ''' + pass + +# type-specifier: +def p_type_specifier(t): + '''type_specifier : VOID + | CHAR + | SHORT + | INT + | LONG + | FLOAT + | DOUBLE + | SIGNED + | UNSIGNED + | struct_or_union_specifier + | enum_specifier + | TYPEID + ''' + pass + +# type-qualifier: +def p_type_qualifier(t): + '''type_qualifier : CONST + | VOLATILE''' + pass + +# struct-or-union-specifier + +def p_struct_or_union_specifier_1(t): + 'struct_or_union_specifier : struct_or_union ID LBRACE struct_declaration_list RBRACE' + pass + +def p_struct_or_union_specifier_2(t): + 'struct_or_union_specifier : struct_or_union LBRACE struct_declaration_list RBRACE' + pass + +def p_struct_or_union_specifier_3(t): + 'struct_or_union_specifier : struct_or_union ID' + pass + +# struct-or-union: +def p_struct_or_union(t): + '''struct_or_union : STRUCT + | UNION + ''' + pass + +# struct-declaration-list: + +def p_struct_declaration_list_1(t): + 'struct_declaration_list : struct_declaration' + pass + +def p_struct_declaration_list_2(t): + 'struct_declaration_list : struct_declarator_list struct_declaration' + pass + +# init-declarator-list: + +def p_init_declarator_list_1(t): + 'init_declarator_list : init_declarator' + pass + +def p_init_declarator_list_2(t): + 'init_declarator_list : init_declarator_list COMMA init_declarator' + pass + +# init-declarator + +def p_init_declarator_1(t): + 'init_declarator : declarator' + pass + +def p_init_declarator_2(t): + 'init_declarator : declarator EQUALS initializer' + pass + +# struct-declaration: + +def p_struct_declaration(t): + 'struct_declaration : specifier_qualifier_list struct_declarator_list SEMI' + pass + +# specifier-qualifier-list: + +def p_specifier_qualifier_list_1(t): + 'specifier_qualifier_list : type_specifier specifier_qualifier_list' + pass + +def p_specifier_qualifier_list_2(t): + 'specifier_qualifier_list : type_specifier' + pass + +def p_specifier_qualifier_list_3(t): + 'specifier_qualifier_list : type_qualifier specifier_qualifier_list' + pass + +def p_specifier_qualifier_list_4(t): + 'specifier_qualifier_list : type_qualifier' + pass + +# struct-declarator-list: + +def p_struct_declarator_list_1(t): + 'struct_declarator_list : struct_declarator' + pass + +def p_struct_declarator_list_2(t): + 'struct_declarator_list : struct_declarator_list COMMA struct_declarator' + pass + +# struct-declarator: + +def p_struct_declarator_1(t): + 'struct_declarator : declarator' + pass + +def p_struct_declarator_2(t): + 'struct_declarator : declarator COLON constant_expression' + pass + +def p_struct_declarator_3(t): + 'struct_declarator : COLON constant_expression' + pass + +# enum-specifier: + +def p_enum_specifier_1(t): + 'enum_specifier : ENUM ID LBRACE enumerator_list RBRACE' + pass + +def p_enum_specifier_2(t): + 'enum_specifier : ENUM LBRACE enumerator_list RBRACE' + pass + +def p_enum_specifier_3(t): + 'enum_specifier : ENUM ID' + pass + +# enumerator_list: +def p_enumerator_list_1(t): + 'enumerator_list : enumerator' + pass + +def p_enumerator_list_2(t): + 'enumerator_list : enumerator_list COMMA enumerator' + pass + +# enumerator: +def p_enumerator_1(t): + 'enumerator : ID' + pass + +def p_enumerator_2(t): + 'enumerator : ID EQUALS constant_expression' + pass + +# declarator: + +def p_declarator_1(t): + 'declarator : pointer direct_declarator' + pass + +def p_declarator_2(t): + 'declarator : direct_declarator' + pass + +# direct-declarator: + +def p_direct_declarator_1(t): + 'direct_declarator : ID' + pass + +def p_direct_declarator_2(t): + 'direct_declarator : LPAREN declarator RPAREN' + pass + +def p_direct_declarator_3(t): + 'direct_declarator : direct_declarator LBRACKET constant_expression_opt RBRACKET' + pass + +def p_direct_declarator_4(t): + 'direct_declarator : direct_declarator LPAREN parameter_type_list RPAREN ' + pass + +def p_direct_declarator_5(t): + 'direct_declarator : direct_declarator LPAREN identifier_list RPAREN ' + pass + +def p_direct_declarator_6(t): + 'direct_declarator : direct_declarator LPAREN RPAREN ' + pass + +# pointer: +def p_pointer_1(t): + 'pointer : TIMES type_qualifier_list' + pass + +def p_pointer_2(t): + 'pointer : TIMES' + pass + +def p_pointer_3(t): + 'pointer : TIMES type_qualifier_list pointer' + pass + +def p_pointer_4(t): + 'pointer : TIMES pointer' + pass + +# type-qualifier-list: + +def p_type_qualifier_list_1(t): + 'type_qualifier_list : type_qualifier' + pass + +def p_type_qualifier_list_2(t): + 'type_qualifier_list : type_qualifier_list type_qualifier' + pass + +# parameter-type-list: + +def p_parameter_type_list_1(t): + 'parameter_type_list : parameter_list' + pass + +def p_parameter_type_list_2(t): + 'parameter_type_list : parameter_list COMMA ELLIPSIS' + pass + +# parameter-list: + +def p_parameter_list_1(t): + 'parameter_list : parameter_declaration' + pass + +def p_parameter_list_2(t): + 'parameter_list : parameter_list COMMA parameter_declaration' + pass + +# parameter-declaration: +def p_parameter_declaration_1(t): + 'parameter_declaration : declaration_specifiers declarator' + pass + +def p_parameter_declaration_2(t): + 'parameter_declaration : declaration_specifiers abstract_declarator_opt' + pass + +# identifier-list: +def p_identifier_list_1(t): + 'identifier_list : ID' + pass + +def p_identifier_list_2(t): + 'identifier_list : identifier_list COMMA ID' + pass + +# initializer: + +def p_initializer_1(t): + 'initializer : assignment_expression' + pass + +def p_initializer_2(t): + '''initializer : LBRACE initializer_list RBRACE + | LBRACE initializer_list COMMA RBRACE''' + pass + +# initializer-list: + +def p_initializer_list_1(t): + 'initializer_list : initializer' + pass + +def p_initializer_list_2(t): + 'initializer_list : initializer_list COMMA initializer' + pass + +# type-name: + +def p_type_name(t): + 'type_name : specifier_qualifier_list abstract_declarator_opt' + pass + +def p_abstract_declarator_opt_1(t): + 'abstract_declarator_opt : empty' + pass + +def p_abstract_declarator_opt_2(t): + 'abstract_declarator_opt : abstract_declarator' + pass + +# abstract-declarator: + +def p_abstract_declarator_1(t): + 'abstract_declarator : pointer ' + pass + +def p_abstract_declarator_2(t): + 'abstract_declarator : pointer direct_abstract_declarator' + pass + +def p_abstract_declarator_3(t): + 'abstract_declarator : direct_abstract_declarator' + pass + +# direct-abstract-declarator: + +def p_direct_abstract_declarator_1(t): + 'direct_abstract_declarator : LPAREN abstract_declarator RPAREN' + pass + +def p_direct_abstract_declarator_2(t): + 'direct_abstract_declarator : direct_abstract_declarator LBRACKET constant_expression_opt RBRACKET' + pass + +def p_direct_abstract_declarator_3(t): + 'direct_abstract_declarator : LBRACKET constant_expression_opt RBRACKET' + pass + +def p_direct_abstract_declarator_4(t): + 'direct_abstract_declarator : direct_abstract_declarator LPAREN parameter_type_list_opt RPAREN' + pass + +def p_direct_abstract_declarator_5(t): + 'direct_abstract_declarator : LPAREN parameter_type_list_opt RPAREN' + pass + +# Optional fields in abstract declarators + +def p_constant_expression_opt_1(t): + 'constant_expression_opt : empty' + pass + +def p_constant_expression_opt_2(t): + 'constant_expression_opt : constant_expression' + pass + +def p_parameter_type_list_opt_1(t): + 'parameter_type_list_opt : empty' + pass + +def p_parameter_type_list_opt_2(t): + 'parameter_type_list_opt : parameter_type_list' + pass + +# statement: + +def p_statement(t): + ''' + statement : labeled_statement + | expression_statement + | compound_statement + | selection_statement + | iteration_statement + | jump_statement + ''' + pass + +# labeled-statement: + +def p_labeled_statement_1(t): + 'labeled_statement : ID COLON statement' + pass + +def p_labeled_statement_2(t): + 'labeled_statement : CASE constant_expression COLON statement' + pass + +def p_labeled_statement_3(t): + 'labeled_statement : DEFAULT COLON statement' + pass + +# expression-statement: +def p_expression_statement(t): + 'expression_statement : expression_opt SEMI' + pass + +# compound-statement: + +def p_compound_statement_1(t): + 'compound_statement : LBRACE declaration_list statement_list RBRACE' + pass + +def p_compound_statement_2(t): + 'compound_statement : LBRACE statement_list RBRACE' + pass + +def p_compound_statement_3(t): + 'compound_statement : LBRACE declaration_list RBRACE' + pass + +def p_compound_statement_4(t): + 'compound_statement : LBRACE RBRACE' + pass + +# statement-list: + +def p_statement_list_1(t): + 'statement_list : statement' + pass + +def p_statement_list_2(t): + 'statement_list : statement_list statement' + pass + +# selection-statement + +def p_selection_statement_1(t): + 'selection_statement : IF LPAREN expression RPAREN statement' + pass + +def p_selection_statement_2(t): + 'selection_statement : IF LPAREN expression RPAREN statement ELSE statement ' + pass + +def p_selection_statement_3(t): + 'selection_statement : SWITCH LPAREN expression RPAREN statement ' + pass + +# iteration_statement: + +def p_iteration_statement_1(t): + 'iteration_statement : WHILE LPAREN expression RPAREN statement' + pass + +def p_iteration_statement_2(t): + 'iteration_statement : FOR LPAREN expression_opt SEMI expression_opt SEMI expression_opt RPAREN statement ' + pass + +def p_iteration_statement_3(t): + 'iteration_statement : DO statement WHILE LPAREN expression RPAREN SEMI' + pass + +# jump_statement: + +def p_jump_statement_1(t): + 'jump_statement : GOTO ID SEMI' + pass + +def p_jump_statement_2(t): + 'jump_statement : CONTINUE SEMI' + pass + +def p_jump_statement_3(t): + 'jump_statement : BREAK SEMI' + pass + +def p_jump_statement_4(t): + 'jump_statement : RETURN expression_opt SEMI' + pass + +def p_expression_opt_1(t): + 'expression_opt : empty' + pass + +def p_expression_opt_2(t): + 'expression_opt : expression' + pass + +# expression: +def p_expression_1(t): + 'expression : assignment_expression' + pass + +def p_expression_2(t): + 'expression : expression COMMA assignment_expression' + pass + +# assigment_expression: +def p_assignment_expression_1(t): + 'assignment_expression : conditional_expression' + pass + +def p_assignment_expression_2(t): + 'assignment_expression : unary_expression assignment_operator assignment_expression' + pass + +# assignment_operator: +def p_assignment_operator(t): + ''' + assignment_operator : EQUALS + | TIMESEQUAL + | DIVEQUAL + | MODEQUAL + | PLUSEQUAL + | MINUSEQUAL + | LSHIFTEQUAL + | RSHIFTEQUAL + | ANDEQUAL + | OREQUAL + | XOREQUAL + ''' + pass + +# conditional-expression +def p_conditional_expression_1(t): + 'conditional_expression : logical_or_expression' + pass + +def p_conditional_expression_2(t): + 'conditional_expression : logical_or_expression CONDOP expression COLON conditional_expression ' + pass + +# constant-expression + +def p_constant_expression(t): + 'constant_expression : conditional_expression' + pass + +# logical-or-expression + +def p_logical_or_expression_1(t): + 'logical_or_expression : logical_and_expression' + pass + +def p_logical_or_expression_2(t): + 'logical_or_expression : logical_or_expression LOR logical_and_expression' + pass + +# logical-and-expression + +def p_logical_and_expression_1(t): + 'logical_and_expression : inclusive_or_expression' + pass + +def p_logical_and_expression_2(t): + 'logical_and_expression : logical_and_expression LAND inclusive_or_expression' + pass + +# inclusive-or-expression: + +def p_inclusive_or_expression_1(t): + 'inclusive_or_expression : exclusive_or_expression' + pass + +def p_inclusive_or_expression_2(t): + 'inclusive_or_expression : inclusive_or_expression OR exclusive_or_expression' + pass + +# exclusive-or-expression: + +def p_exclusive_or_expression_1(t): + 'exclusive_or_expression : and_expression' + pass + +def p_exclusive_or_expression_2(t): + 'exclusive_or_expression : exclusive_or_expression XOR and_expression' + pass + +# AND-expression + +def p_and_expression_1(t): + 'and_expression : equality_expression' + pass + +def p_and_expression_2(t): + 'and_expression : and_expression AND equality_expression' + pass + + +# equality-expression: +def p_equality_expression_1(t): + 'equality_expression : relational_expression' + pass + +def p_equality_expression_2(t): + 'equality_expression : equality_expression EQ relational_expression' + pass + +def p_equality_expression_3(t): + 'equality_expression : equality_expression NE relational_expression' + pass + + +# relational-expression: +def p_relational_expression_1(t): + 'relational_expression : shift_expression' + pass + +def p_relational_expression_2(t): + 'relational_expression : relational_expression LT shift_expression' + pass + +def p_relational_expression_3(t): + 'relational_expression : relational_expression GT shift_expression' + pass + +def p_relational_expression_4(t): + 'relational_expression : relational_expression LE shift_expression' + pass + +def p_relational_expression_5(t): + 'relational_expression : relational_expression GE shift_expression' + pass + +# shift-expression + +def p_shift_expression_1(t): + 'shift_expression : additive_expression' + pass + +def p_shift_expression_2(t): + 'shift_expression : shift_expression LSHIFT additive_expression' + pass + +def p_shift_expression_3(t): + 'shift_expression : shift_expression RSHIFT additive_expression' + pass + +# additive-expression + +def p_additive_expression_1(t): + 'additive_expression : multiplicative_expression' + pass + +def p_additive_expression_2(t): + 'additive_expression : additive_expression PLUS multiplicative_expression' + pass + +def p_additive_expression_3(t): + 'additive_expression : additive_expression MINUS multiplicative_expression' + pass + +# multiplicative-expression + +def p_multiplicative_expression_1(t): + 'multiplicative_expression : cast_expression' + pass + +def p_multiplicative_expression_2(t): + 'multiplicative_expression : multiplicative_expression TIMES cast_expression' + pass + +def p_multiplicative_expression_3(t): + 'multiplicative_expression : multiplicative_expression DIVIDE cast_expression' + pass + +def p_multiplicative_expression_4(t): + 'multiplicative_expression : multiplicative_expression MOD cast_expression' + pass + +# cast-expression: + +def p_cast_expression_1(t): + 'cast_expression : unary_expression' + pass + +def p_cast_expression_2(t): + 'cast_expression : LPAREN type_name RPAREN cast_expression' + pass + +# unary-expression: +def p_unary_expression_1(t): + 'unary_expression : postfix_expression' + pass + +def p_unary_expression_2(t): + 'unary_expression : PLUSPLUS unary_expression' + pass + +def p_unary_expression_3(t): + 'unary_expression : MINUSMINUS unary_expression' + pass + +def p_unary_expression_4(t): + 'unary_expression : unary_operator cast_expression' + pass + +def p_unary_expression_5(t): + 'unary_expression : SIZEOF unary_expression' + pass + +def p_unary_expression_6(t): + 'unary_expression : SIZEOF LPAREN type_name RPAREN' + pass + +#unary-operator +def p_unary_operator(t): + '''unary_operator : AND + | TIMES + | PLUS + | MINUS + | NOT + | LNOT ''' + pass + +# postfix-expression: +def p_postfix_expression_1(t): + 'postfix_expression : primary_expression' + pass + +def p_postfix_expression_2(t): + 'postfix_expression : postfix_expression LBRACKET expression RBRACKET' + pass + +def p_postfix_expression_3(t): + 'postfix_expression : postfix_expression LPAREN argument_expression_list RPAREN' + pass + +def p_postfix_expression_4(t): + 'postfix_expression : postfix_expression LPAREN RPAREN' + pass + +def p_postfix_expression_5(t): + 'postfix_expression : postfix_expression PERIOD ID' + pass + +def p_postfix_expression_6(t): + 'postfix_expression : postfix_expression ARROW ID' + pass + +def p_postfix_expression_7(t): + 'postfix_expression : postfix_expression PLUSPLUS' + pass + +def p_postfix_expression_8(t): + 'postfix_expression : postfix_expression MINUSMINUS' + pass + +# primary-expression: +def p_primary_expression(t): + '''primary_expression : ID + | constant + | SCONST + | LPAREN expression RPAREN''' + pass + +# argument-expression-list: +def p_argument_expression_list(t): + '''argument_expression_list : assignment_expression + | argument_expression_list COMMA assignment_expression''' + pass + +# constant: +def p_constant(t): + '''constant : ICONST + | FCONST + | CCONST''' + pass + + +def p_empty(t): + 'empty : ' + pass + +def p_error(t): + print "Whoa. We're hosed" + +import profile +# Build the grammar +profile.run("yacc.yacc()") + + + + diff --git a/ext/ply/example/calc/calc.py b/ext/ply/example/calc/calc.py new file mode 100644 index 000000000..aeb23c246 --- /dev/null +++ b/ext/ply/example/calc/calc.py @@ -0,0 +1,108 @@ +# ----------------------------------------------------------------------------- +# calc.py +# +# A simple calculator with variables. This is from O'Reilly's +# "Lex and Yacc", p. 63. +# ----------------------------------------------------------------------------- + +tokens = ( + 'NAME','NUMBER', + 'PLUS','MINUS','TIMES','DIVIDE','EQUALS', + 'LPAREN','RPAREN', + ) + +# Tokens + +t_PLUS = r'\+' +t_MINUS = r'-' +t_TIMES = r'\*' +t_DIVIDE = r'/' +t_EQUALS = r'=' +t_LPAREN = r'\(' +t_RPAREN = r'\)' +t_NAME = r'[a-zA-Z_][a-zA-Z0-9_]*' + +def t_NUMBER(t): + r'\d+' + try: + t.value = int(t.value) + except ValueError: + print "Integer value too large", t.value + t.value = 0 + return t + +t_ignore = " \t" + +def t_newline(t): + r'\n+' + t.lineno += t.value.count("\n") + +def t_error(t): + print "Illegal character '%s'" % t.value[0] + t.skip(1) + +# Build the lexer +import lex +lex.lex() + +# Parsing rules + +precedence = ( + ('left','PLUS','MINUS'), + ('left','TIMES','DIVIDE'), + ('right','UMINUS'), + ) + +# dictionary of names +names = { } + +def p_statement_assign(t): + 'statement : NAME EQUALS expression' + names[t[1]] = t[3] + +def p_statement_expr(t): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[2] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +def p_error(t): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc() + +while 1: + try: + s = raw_input('calc > ') + except EOFError: + break + yacc.parse(s) diff --git a/ext/ply/example/hedit/hedit.py b/ext/ply/example/hedit/hedit.py new file mode 100644 index 000000000..f00427bf5 --- /dev/null +++ b/ext/ply/example/hedit/hedit.py @@ -0,0 +1,44 @@ +# ----------------------------------------------------------------------------- +# hedit.py +# +# Paring of Fortran H Edit descriptions (Contributed by Pearu Peterson) +# +# These tokens can't be easily tokenized because they are of the following +# form: +# +# nHc1...cn +# +# where n is a positive integer and c1 ... cn are characters. +# +# This example shows how to modify the state of the lexer to parse +# such tokens +# ----------------------------------------------------------------------------- + +tokens = ( + 'H_EDIT_DESCRIPTOR', + ) + +# Tokens +t_ignore = " \t\n" + +def t_H_EDIT_DESCRIPTOR(t): + r"\d+H.*" # This grabs all of the remaining text + i = t.value.index('H') + n = eval(t.value[:i]) + + # Adjust the tokenizing position + t.lexer.lexpos -= len(t.value) - (i+1+n) + + t.value = t.value[i+1:i+1+n] + return t + +def t_error(t): + print "Illegal character '%s'" % t.value[0] + t.skip(1) + +# Build the lexer +import lex +lex.lex() +lex.runmain() + + diff --git a/ext/ply/example/optcalc/README b/ext/ply/example/optcalc/README new file mode 100644 index 000000000..6d196f0ee --- /dev/null +++ b/ext/ply/example/optcalc/README @@ -0,0 +1,9 @@ +An example showing how to use Python optimized mode. +To run: + + - First run 'python calc.py' + + - Then run 'python -OO calc.py' + +If working corretly, the second version should run the +same way. diff --git a/ext/ply/example/optcalc/calc.py b/ext/ply/example/optcalc/calc.py new file mode 100644 index 000000000..fa66cda5b --- /dev/null +++ b/ext/ply/example/optcalc/calc.py @@ -0,0 +1,110 @@ +# ----------------------------------------------------------------------------- +# calc.py +# +# A simple calculator with variables. This is from O'Reilly's +# "Lex and Yacc", p. 63. +# ----------------------------------------------------------------------------- + +tokens = ( + 'NAME','NUMBER', + 'PLUS','MINUS','TIMES','DIVIDE','EQUALS', + 'LPAREN','RPAREN', + ) + +# Tokens + +t_PLUS = r'\+' +t_MINUS = r'-' +t_TIMES = r'\*' +t_DIVIDE = r'/' +t_EQUALS = r'=' +t_LPAREN = r'\(' +t_RPAREN = r'\)' +t_NAME = r'[a-zA-Z_][a-zA-Z0-9_]*' + +def t_NUMBER(t): + r'\d+' + try: + t.value = int(t.value) + except ValueError: + print "Integer value too large", t.value + t.value = 0 + return t + +t_ignore = " \t" + +def t_newline(t): + r'\n+' + t.lineno += t.value.count("\n") + +def t_error(t): + print "Illegal character '%s'" % t.value[0] + t.skip(1) + +# Build the lexer +import lex +lex.lex(optimize=1) + +# Parsing rules + +precedence = ( + ('left','PLUS','MINUS'), + ('left','TIMES','DIVIDE'), + ('right','UMINUS'), + ) + +# dictionary of names +names = { } + +def p_statement_assign(t): + 'statement : NAME EQUALS expression' + names[t[1]] = t[3] + +def p_statement_expr(t): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[2] == '/': t[0] = t[1] / t[3] + elif t[2] == '<': t[0] = t[1] < t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +def p_error(t): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc(optimize=1) + +while 1: + try: + s = raw_input('calc > ') + except EOFError: + break + yacc.parse(s) + diff --git a/ext/ply/lex.py b/ext/ply/lex.py new file mode 100644 index 000000000..7ad7a394b --- /dev/null +++ b/ext/ply/lex.py @@ -0,0 +1,681 @@ +#----------------------------------------------------------------------------- +# ply: lex.py +# +# Author: David M. Beazley (beazley@cs.uchicago.edu) +# Department of Computer Science +# University of Chicago +# Chicago, IL 60637 +# +# Copyright (C) 2001, David M. Beazley +# +# $Header: /home/stever/bk/newmem2/ext/ply/lex.py 1.1 03/06/06 14:53:34-00:00 stever@ $ +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See the file COPYING for a complete copy of the LGPL. +# +# +# This module automatically constructs a lexical analysis module from regular +# expression rules defined in a user-defined module. The idea is essentially the same +# as that used in John Aycock's Spark framework, but the implementation works +# at the module level rather than requiring the use of classes. +# +# This module tries to provide an interface that is closely modeled after +# the traditional lex interface in Unix. It also differs from Spark +# in that: +# +# - It provides more extensive error checking and reporting if +# the user supplies a set of regular expressions that can't +# be compiled or if there is any other kind of a problem in +# the specification. +# +# - The interface is geared towards LALR(1) and LR(1) parser +# generators. That is tokens are generated one at a time +# rather than being generated in advanced all in one step. +# +# There are a few limitations of this module +# +# - The module interface makes it somewhat awkward to support more +# than one lexer at a time. Although somewhat inelegant from a +# design perspective, this is rarely a practical concern for +# most compiler projects. +# +# - The lexer requires that the entire input text be read into +# a string before scanning. I suppose that most machines have +# enough memory to make this a minor issues, but it makes +# the lexer somewhat difficult to use in interactive sessions +# or with streaming data. +# +#----------------------------------------------------------------------------- + +r""" +lex.py + +This module builds lex-like scanners based on regular expression rules. +To use the module, simply write a collection of regular expression rules +and actions like this: + +# lexer.py +import lex + +# Define a list of valid tokens +tokens = ( + 'IDENTIFIER', 'NUMBER', 'PLUS', 'MINUS' + ) + +# Define tokens as functions +def t_IDENTIFIER(t): + r' ([a-zA-Z_](\w|_)* ' + return t + +def t_NUMBER(t): + r' \d+ ' + return t + +# Some simple tokens with no actions +t_PLUS = r'\+' +t_MINUS = r'-' + +# Initialize the lexer +lex.lex() + +The tokens list is required and contains a complete list of all valid +token types that the lexer is allowed to produce. Token types are +restricted to be valid identifiers. This means that 'MINUS' is a valid +token type whereas '-' is not. + +Rules are defined by writing a function with a name of the form +t_rulename. Each rule must accept a single argument which is +a token object generated by the lexer. This token has the following +attributes: + + t.type = type string of the token. This is initially set to the + name of the rule without the leading t_ + t.value = The value of the lexeme. + t.lineno = The value of the line number where the token was encountered + +For example, the t_NUMBER() rule above might be called with the following: + + t.type = 'NUMBER' + t.value = '42' + t.lineno = 3 + +Each rule returns the token object it would like to supply to the +parser. In most cases, the token t is returned with few, if any +modifications. To discard a token for things like whitespace or +comments, simply return nothing. For instance: + +def t_whitespace(t): + r' \s+ ' + pass + +For faster lexing, you can also define this in terms of the ignore set like this: + +t_ignore = ' \t' + +The characters in this string are ignored by the lexer. Use of this feature can speed +up parsing significantly since scanning will immediately proceed to the next token. + +lex requires that the token returned by each rule has an attribute +t.type. Other than this, rules are free to return any kind of token +object that they wish and may construct a new type of token object +from the attributes of t (provided the new object has the required +type attribute). + +If illegal characters are encountered, the scanner executes the +function t_error(t) where t is a token representing the rest of the +string that hasn't been matched. If this function isn't defined, a +LexError exception is raised. The .text attribute of this exception +object contains the part of the string that wasn't matched. + +The t.skip(n) method can be used to skip ahead n characters in the +input stream. This is usually only used in the error handling rule. +For instance, the following rule would print an error message and +continue: + +def t_error(t): + print "Illegal character in input %s" % t.value[0] + t.skip(1) + +Of course, a nice scanner might wish to skip more than one character +if the input looks very corrupted. + +The lex module defines a t.lineno attribute on each token that can be used +to track the current line number in the input. The value of this +variable is not modified by lex so it is up to your lexer module +to correctly update its value depending on the lexical properties +of the input language. To do this, you might write rules such as +the following: + +def t_newline(t): + r' \n+ ' + t.lineno += t.value.count("\n") + +To initialize your lexer so that it can be used, simply call the lex.lex() +function in your rule file. If there are any errors in your +specification, warning messages or an exception will be generated to +alert you to the problem. + +(dave: this needs to be rewritten) +To use the newly constructed lexer from another module, simply do +this: + + import lex + import lexer + plex.input("position = initial + rate*60") + + while 1: + token = plex.token() # Get a token + if not token: break # No more tokens + ... do whatever ... + +Assuming that the module 'lexer' has initialized plex as shown +above, parsing modules can safely import 'plex' without having +to import the rule file or any additional imformation about the +scanner you have defined. +""" + +# ----------------------------------------------------------------------------- + + +__version__ = "1.3" + +import re, types, sys, copy + +# Exception thrown when invalid token encountered and no default +class LexError(Exception): + def __init__(self,message,s): + self.args = (message,) + self.text = s + +# Token class +class LexToken: + def __str__(self): + return "LexToken(%s,%r,%d)" % (self.type,self.value,self.lineno) + def __repr__(self): + return str(self) + def skip(self,n): + try: + self._skipn += n + except AttributeError: + self._skipn = n + +# ----------------------------------------------------------------------------- +# Lexer class +# +# input() - Store a new string in the lexer +# token() - Get the next token +# ----------------------------------------------------------------------------- + +class Lexer: + def __init__(self): + self.lexre = None # Master regular expression + self.lexdata = None # Actual input data (as a string) + self.lexpos = 0 # Current position in input text + self.lexlen = 0 # Length of the input text + self.lexindexfunc = [ ] # Reverse mapping of groups to functions and types + self.lexerrorf = None # Error rule (if any) + self.lextokens = None # List of valid tokens + self.lexignore = None # Ignored characters + self.lineno = 1 # Current line number + self.debug = 0 # Debugging mode + self.optimize = 0 # Optimized mode + self.token = self.errtoken + + def __copy__(self): + c = Lexer() + c.lexre = self.lexre + c.lexdata = self.lexdata + c.lexpos = self.lexpos + c.lexlen = self.lexlen + c.lenindexfunc = self.lexindexfunc + c.lexerrorf = self.lexerrorf + c.lextokens = self.lextokens + c.lexignore = self.lexignore + c.lineno = self.lineno + c.optimize = self.optimize + c.token = c.realtoken + + # ------------------------------------------------------------ + # input() - Push a new string into the lexer + # ------------------------------------------------------------ + def input(self,s): + if not isinstance(s,types.StringType): + raise ValueError, "Expected a string" + self.lexdata = s + self.lexpos = 0 + self.lexlen = len(s) + self.token = self.realtoken + + # Change the token routine to point to realtoken() + global token + if token == self.errtoken: + token = self.token + + # ------------------------------------------------------------ + # errtoken() - Return error if token is called with no data + # ------------------------------------------------------------ + def errtoken(self): + raise RuntimeError, "No input string given with input()" + + # ------------------------------------------------------------ + # token() - Return the next token from the Lexer + # + # Note: This function has been carefully implemented to be as fast + # as possible. Don't make changes unless you really know what + # you are doing + # ------------------------------------------------------------ + def realtoken(self): + # Make local copies of frequently referenced attributes + lexpos = self.lexpos + lexlen = self.lexlen + lexignore = self.lexignore + lexdata = self.lexdata + + while lexpos < lexlen: + # This code provides some short-circuit code for whitespace, tabs, and other ignored characters + if lexdata[lexpos] in lexignore: + lexpos += 1 + continue + + # Look for a regular expression match + m = self.lexre.match(lexdata,lexpos) + if m: + i = m.lastindex + lexpos = m.end() + tok = LexToken() + tok.value = m.group() + tok.lineno = self.lineno + tok.lexer = self + func,tok.type = self.lexindexfunc[i] + if not func: + self.lexpos = lexpos + return tok + + # If token is processed by a function, call it + self.lexpos = lexpos + newtok = func(tok) + self.lineno = tok.lineno # Update line number + + # Every function must return a token, if nothing, we just move to next token + if not newtok: continue + + # Verify type of the token. If not in the token map, raise an error + if not self.optimize: + if not self.lextokens.has_key(newtok.type): + raise LexError, ("%s:%d: Rule '%s' returned an unknown token type '%s'" % ( + func.func_code.co_filename, func.func_code.co_firstlineno, + func.__name__, newtok.type),lexdata[lexpos:]) + + return newtok + + # No match. Call t_error() if defined. + if self.lexerrorf: + tok = LexToken() + tok.value = self.lexdata[lexpos:] + tok.lineno = self.lineno + tok.type = "error" + tok.lexer = self + oldpos = lexpos + newtok = self.lexerrorf(tok) + lexpos += getattr(tok,"_skipn",0) + if oldpos == lexpos: + # Error method didn't change text position at all. This is an error. + self.lexpos = lexpos + raise LexError, ("Scanning error. Illegal character '%s'" % (lexdata[lexpos]), lexdata[lexpos:]) + if not newtok: continue + self.lexpos = lexpos + return newtok + + self.lexpos = lexpos + raise LexError, ("No match found", lexdata[lexpos:]) + + # No more input data + self.lexpos = lexpos + 1 + return None + + +# ----------------------------------------------------------------------------- +# validate_file() +# +# This checks to see if there are duplicated t_rulename() functions or strings +# in the parser input file. This is done using a simple regular expression +# match on each line in the filename. +# ----------------------------------------------------------------------------- + +def validate_file(filename): + import os.path + base,ext = os.path.splitext(filename) + if ext != '.py': return 1 # No idea what the file is. Return OK + + try: + f = open(filename) + lines = f.readlines() + f.close() + except IOError: + return 1 # Oh well + + fre = re.compile(r'\s*def\s+(t_[a-zA-Z_0-9]*)\(') + sre = re.compile(r'\s*(t_[a-zA-Z_0-9]*)\s*=') + counthash = { } + linen = 1 + noerror = 1 + for l in lines: + m = fre.match(l) + if not m: + m = sre.match(l) + if m: + name = m.group(1) + prev = counthash.get(name) + if not prev: + counthash[name] = linen + else: + print "%s:%d: Rule %s redefined. Previously defined on line %d" % (filename,linen,name,prev) + noerror = 0 + linen += 1 + return noerror + +# ----------------------------------------------------------------------------- +# _read_lextab(module) +# +# Reads lexer table from a lextab file instead of using introspection. +# ----------------------------------------------------------------------------- + +def _read_lextab(lexer, fdict, module): + exec "import %s as lextab" % module + lexer.lexre = re.compile(lextab._lexre, re.VERBOSE) + lexer.lexindexfunc = lextab._lextab + for i in range(len(lextab._lextab)): + t = lexer.lexindexfunc[i] + if t: + if t[0]: + lexer.lexindexfunc[i] = (fdict[t[0]],t[1]) + lexer.lextokens = lextab._lextokens + lexer.lexignore = lextab._lexignore + if lextab._lexerrorf: + lexer.lexerrorf = fdict[lextab._lexerrorf] + +# ----------------------------------------------------------------------------- +# lex(module) +# +# Build all of the regular expression rules from definitions in the supplied module +# ----------------------------------------------------------------------------- +def lex(module=None,debug=0,optimize=0,lextab="lextab"): + ldict = None + regex = "" + error = 0 + files = { } + lexer = Lexer() + lexer.debug = debug + lexer.optimize = optimize + global token,input + + if module: + if not isinstance(module, types.ModuleType): + raise ValueError,"Expected a module" + + ldict = module.__dict__ + + else: + # No module given. We might be able to get information from the caller. + try: + raise RuntimeError + except RuntimeError: + e,b,t = sys.exc_info() + f = t.tb_frame + f = f.f_back # Walk out to our calling function + ldict = f.f_globals # Grab its globals dictionary + + if optimize and lextab: + try: + _read_lextab(lexer,ldict, lextab) + if not lexer.lexignore: lexer.lexignore = "" + token = lexer.token + input = lexer.input + return lexer + + except ImportError: + pass + + # Get the tokens map + tokens = ldict.get("tokens",None) + if not tokens: + raise SyntaxError,"lex: module does not define 'tokens'" + if not (isinstance(tokens,types.ListType) or isinstance(tokens,types.TupleType)): + raise SyntaxError,"lex: tokens must be a list or tuple." + + # Build a dictionary of valid token names + lexer.lextokens = { } + if not optimize: + + # Utility function for verifying tokens + def is_identifier(s): + for c in s: + if not (c.isalnum() or c == '_'): return 0 + return 1 + + for n in tokens: + if not is_identifier(n): + print "lex: Bad token name '%s'" % n + error = 1 + if lexer.lextokens.has_key(n): + print "lex: Warning. Token '%s' multiply defined." % n + lexer.lextokens[n] = None + else: + for n in tokens: lexer.lextokens[n] = None + + + if debug: + print "lex: tokens = '%s'" % lexer.lextokens.keys() + + # Get a list of symbols with the t_ prefix + tsymbols = [f for f in ldict.keys() if f[:2] == 't_'] + + # Now build up a list of functions and a list of strings + fsymbols = [ ] + ssymbols = [ ] + for f in tsymbols: + if isinstance(ldict[f],types.FunctionType): + fsymbols.append(ldict[f]) + elif isinstance(ldict[f],types.StringType): + ssymbols.append((f,ldict[f])) + else: + print "lex: %s not defined as a function or string" % f + error = 1 + + # Sort the functions by line number + fsymbols.sort(lambda x,y: cmp(x.func_code.co_firstlineno,y.func_code.co_firstlineno)) + + # Sort the strings by regular expression length + ssymbols.sort(lambda x,y: (len(x[1]) < len(y[1])) - (len(x[1]) > len(y[1]))) + + # Check for non-empty symbols + if len(fsymbols) == 0 and len(ssymbols) == 0: + raise SyntaxError,"lex: no rules of the form t_rulename are defined." + + # Add all of the rules defined with actions first + for f in fsymbols: + + line = f.func_code.co_firstlineno + file = f.func_code.co_filename + files[file] = None + + if not optimize: + if f.func_code.co_argcount > 1: + print "%s:%d: Rule '%s' has too many arguments." % (file,line,f.__name__) + error = 1 + continue + + if f.func_code.co_argcount < 1: + print "%s:%d: Rule '%s' requires an argument." % (file,line,f.__name__) + error = 1 + continue + + if f.__name__ == 't_ignore': + print "%s:%d: Rule '%s' must be defined as a string." % (file,line,f.__name__) + error = 1 + continue + + if f.__name__ == 't_error': + lexer.lexerrorf = f + continue + + if f.__doc__: + if not optimize: + try: + c = re.compile(f.__doc__, re.VERBOSE) + except re.error,e: + print "%s:%d: Invalid regular expression for rule '%s'. %s" % (file,line,f.__name__,e) + error = 1 + continue + + if debug: + print "lex: Adding rule %s -> '%s'" % (f.__name__,f.__doc__) + + # Okay. The regular expression seemed okay. Let's append it to the master regular + # expression we're building + + if (regex): regex += "|" + regex += "(?P<%s>%s)" % (f.__name__,f.__doc__) + else: + print "%s:%d: No regular expression defined for rule '%s'" % (file,line,f.__name__) + + # Now add all of the simple rules + for name,r in ssymbols: + + if name == 't_ignore': + lexer.lexignore = r + continue + + if not optimize: + if name == 't_error': + raise SyntaxError,"lex: Rule 't_error' must be defined as a function" + error = 1 + continue + + if not lexer.lextokens.has_key(name[2:]): + print "lex: Rule '%s' defined for an unspecified token %s." % (name,name[2:]) + error = 1 + continue + try: + c = re.compile(r,re.VERBOSE) + except re.error,e: + print "lex: Invalid regular expression for rule '%s'. %s" % (name,e) + error = 1 + continue + if debug: + print "lex: Adding rule %s -> '%s'" % (name,r) + + if regex: regex += "|" + regex += "(?P<%s>%s)" % (name,r) + + if not optimize: + for f in files.keys(): + if not validate_file(f): + error = 1 + try: + if debug: + print "lex: regex = '%s'" % regex + lexer.lexre = re.compile(regex, re.VERBOSE) + + # Build the index to function map for the matching engine + lexer.lexindexfunc = [ None ] * (max(lexer.lexre.groupindex.values())+1) + for f,i in lexer.lexre.groupindex.items(): + handle = ldict[f] + if isinstance(handle,types.FunctionType): + lexer.lexindexfunc[i] = (handle,handle.__name__[2:]) + else: + # If rule was specified as a string, we build an anonymous + # callback function to carry out the action + lexer.lexindexfunc[i] = (None,f[2:]) + + # If a lextab was specified, we create a file containing the precomputed + # regular expression and index table + + if lextab and optimize: + lt = open(lextab+".py","w") + lt.write("# %s.py. This file automatically created by PLY. Don't edit.\n" % lextab) + lt.write("_lexre = %s\n" % repr(regex)) + lt.write("_lextab = [\n"); + for i in range(0,len(lexer.lexindexfunc)): + t = lexer.lexindexfunc[i] + if t: + if t[0]: + lt.write(" ('%s',%s),\n"% (t[0].__name__, repr(t[1]))) + else: + lt.write(" (None,%s),\n" % repr(t[1])) + else: + lt.write(" None,\n") + + lt.write("]\n"); + lt.write("_lextokens = %s\n" % repr(lexer.lextokens)) + lt.write("_lexignore = %s\n" % repr(lexer.lexignore)) + if (lexer.lexerrorf): + lt.write("_lexerrorf = %s\n" % repr(lexer.lexerrorf.__name__)) + else: + lt.write("_lexerrorf = None\n") + lt.close() + + except re.error,e: + print "lex: Fatal error. Unable to compile regular expression rules. %s" % e + error = 1 + if error: + raise SyntaxError,"lex: Unable to build lexer." + if not lexer.lexerrorf: + print "lex: Warning. no t_error rule is defined." + + if not lexer.lexignore: lexer.lexignore = "" + + # Create global versions of the token() and input() functions + token = lexer.token + input = lexer.input + + return lexer + +# ----------------------------------------------------------------------------- +# run() +# +# This runs the lexer as a main program +# ----------------------------------------------------------------------------- + +def runmain(lexer=None,data=None): + if not data: + try: + filename = sys.argv[1] + f = open(filename) + data = f.read() + f.close() + except IndexError: + print "Reading from standard input (type EOF to end):" + data = sys.stdin.read() + + if lexer: + _input = lexer.input + else: + _input = input + _input(data) + if lexer: + _token = lexer.token + else: + _token = token + + while 1: + tok = _token() + if not tok: break + print "(%s,'%s',%d)" % (tok.type, tok.value, tok.lineno) + + + + diff --git a/ext/ply/test/README b/ext/ply/test/README new file mode 100644 index 000000000..bca748497 --- /dev/null +++ b/ext/ply/test/README @@ -0,0 +1,9 @@ +This directory mostly contains tests for various types of error +conditions. To run: + + $ python testlex.py . + $ python testyacc.py . + +(make sure lex.py and yacc.py exist in this directory before +running the tests). + diff --git a/ext/ply/test/calclex.py b/ext/ply/test/calclex.py new file mode 100644 index 000000000..f8eb91a09 --- /dev/null +++ b/ext/ply/test/calclex.py @@ -0,0 +1,46 @@ +# ----------------------------------------------------------------------------- +# calclex.py +# ----------------------------------------------------------------------------- + +tokens = ( + 'NAME','NUMBER', + 'PLUS','MINUS','TIMES','DIVIDE','EQUALS', + 'LPAREN','RPAREN', + ) + +# Tokens + +t_PLUS = r'\+' +t_MINUS = r'-' +t_TIMES = r'\*' +t_DIVIDE = r'/' +t_EQUALS = r'=' +t_LPAREN = r'\(' +t_RPAREN = r'\)' +t_NAME = r'[a-zA-Z_][a-zA-Z0-9_]*' + +def t_NUMBER(t): + r'\d+' + try: + t.value = int(t.value) + except ValueError: + print "Integer value too large", t.value + t.value = 0 + return t + +t_ignore = " \t" + +def t_newline(t): + r'\n+' + t.lineno += t.value.count("\n") + +def t_error(t): + print "Illegal character '%s'" % t.value[0] + t.skip(1) + +# Build the lexer +import lex +lex.lex() + + + diff --git a/ext/ply/test/lex_doc1.exp b/ext/ply/test/lex_doc1.exp new file mode 100644 index 000000000..29381911d --- /dev/null +++ b/ext/ply/test/lex_doc1.exp @@ -0,0 +1 @@ +./lex_doc1.py:15: No regular expression defined for rule 't_NUMBER' diff --git a/ext/ply/test/lex_doc1.py b/ext/ply/test/lex_doc1.py new file mode 100644 index 000000000..fb0fb885e --- /dev/null +++ b/ext/ply/test/lex_doc1.py @@ -0,0 +1,27 @@ +# lex_token.py +# +# Missing documentation string + +import lex + +tokens = [ + "PLUS", + "MINUS", + "NUMBER", + ] + +t_PLUS = r'\+' +t_MINUS = r'-' +def t_NUMBER(t): + pass + +def t_error(t): + pass + + +import sys +sys.tracebacklimit = 0 + +lex.lex() + + diff --git a/ext/ply/test/lex_dup1.exp b/ext/ply/test/lex_dup1.exp new file mode 100644 index 000000000..22bca3190 --- /dev/null +++ b/ext/ply/test/lex_dup1.exp @@ -0,0 +1,2 @@ +./lex_dup1.py:17: Rule t_NUMBER redefined. Previously defined on line 15 +SyntaxError: lex: Unable to build lexer. diff --git a/ext/ply/test/lex_dup1.py b/ext/ply/test/lex_dup1.py new file mode 100644 index 000000000..88bbe00e9 --- /dev/null +++ b/ext/ply/test/lex_dup1.py @@ -0,0 +1,27 @@ +# lex_token.py +# +# Duplicated rule specifiers + +import lex + +tokens = [ + "PLUS", + "MINUS", + "NUMBER", + ] + +t_PLUS = r'\+' +t_MINUS = r'-' +t_NUMBER = r'\d+' + +t_NUMBER = r'\d+' + +def t_error(t): + pass + +import sys +sys.tracebacklimit = 0 + +lex.lex() + + diff --git a/ext/ply/test/lex_dup2.exp b/ext/ply/test/lex_dup2.exp new file mode 100644 index 000000000..883bdad46 --- /dev/null +++ b/ext/ply/test/lex_dup2.exp @@ -0,0 +1,2 @@ +./lex_dup2.py:19: Rule t_NUMBER redefined. Previously defined on line 15 +SyntaxError: lex: Unable to build lexer. diff --git a/ext/ply/test/lex_dup2.py b/ext/ply/test/lex_dup2.py new file mode 100644 index 000000000..65e0b21a2 --- /dev/null +++ b/ext/ply/test/lex_dup2.py @@ -0,0 +1,31 @@ +# lex_token.py +# +# Duplicated rule specifiers + +import lex + +tokens = [ + "PLUS", + "MINUS", + "NUMBER", + ] + +t_PLUS = r'\+' +t_MINUS = r'-' +def t_NUMBER(t): + r'\d+' + pass + +def t_NUMBER(t): + r'\d+' + pass + +def t_error(t): + pass + +import sys +sys.tracebacklimit = 0 + +lex.lex() + + diff --git a/ext/ply/test/lex_dup3.exp b/ext/ply/test/lex_dup3.exp new file mode 100644 index 000000000..916612aa1 --- /dev/null +++ b/ext/ply/test/lex_dup3.exp @@ -0,0 +1,2 @@ +./lex_dup3.py:17: Rule t_NUMBER redefined. Previously defined on line 15 +SyntaxError: lex: Unable to build lexer. diff --git a/ext/ply/test/lex_dup3.py b/ext/ply/test/lex_dup3.py new file mode 100644 index 000000000..424101823 --- /dev/null +++ b/ext/ply/test/lex_dup3.py @@ -0,0 +1,29 @@ +# lex_token.py +# +# Duplicated rule specifiers + +import lex + +tokens = [ + "PLUS", + "MINUS", + "NUMBER", + ] + +t_PLUS = r'\+' +t_MINUS = r'-' +t_NUMBER = r'\d+' + +def t_NUMBER(t): + r'\d+' + pass + +def t_error(t): + pass + +import sys +sys.tracebacklimit = 0 + +lex.lex() + + diff --git a/ext/ply/test/lex_empty.exp b/ext/ply/test/lex_empty.exp new file mode 100644 index 000000000..af38602d5 --- /dev/null +++ b/ext/ply/test/lex_empty.exp @@ -0,0 +1 @@ +SyntaxError: lex: no rules of the form t_rulename are defined. diff --git a/ext/ply/test/lex_empty.py b/ext/ply/test/lex_empty.py new file mode 100644 index 000000000..6472832f1 --- /dev/null +++ b/ext/ply/test/lex_empty.py @@ -0,0 +1,18 @@ +# lex_token.py +# +# No rules defined + +import lex + +tokens = [ + "PLUS", + "MINUS", + "NUMBER", + ] + +import sys +sys.tracebacklimit = 0 + +lex.lex() + + diff --git a/ext/ply/test/lex_error1.exp b/ext/ply/test/lex_error1.exp new file mode 100644 index 000000000..baa19e5b3 --- /dev/null +++ b/ext/ply/test/lex_error1.exp @@ -0,0 +1 @@ +lex: Warning. no t_error rule is defined. diff --git a/ext/ply/test/lex_error1.py b/ext/ply/test/lex_error1.py new file mode 100644 index 000000000..ed7980346 --- /dev/null +++ b/ext/ply/test/lex_error1.py @@ -0,0 +1,22 @@ +# lex_token.py +# +# Missing t_error() rule + +import lex + +tokens = [ + "PLUS", + "MINUS", + "NUMBER", + ] + +t_PLUS = r'\+' +t_MINUS = r'-' +t_NUMBER = r'\d+' + +import sys +sys.tracebacklimit = 0 + +lex.lex() + + diff --git a/ext/ply/test/lex_error2.exp b/ext/ply/test/lex_error2.exp new file mode 100644 index 000000000..fb1b55c8b --- /dev/null +++ b/ext/ply/test/lex_error2.exp @@ -0,0 +1 @@ +SyntaxError: lex: Rule 't_error' must be defined as a function diff --git a/ext/ply/test/lex_error2.py b/ext/ply/test/lex_error2.py new file mode 100644 index 000000000..80020f72b --- /dev/null +++ b/ext/ply/test/lex_error2.py @@ -0,0 +1,24 @@ +# lex_token.py +# +# t_error defined, but not function + +import lex + +tokens = [ + "PLUS", + "MINUS", + "NUMBER", + ] + +t_PLUS = r'\+' +t_MINUS = r'-' +t_NUMBER = r'\d+' + +t_error = "foo" + +import sys +sys.tracebacklimit = 0 + +lex.lex() + + diff --git a/ext/ply/test/lex_error3.exp b/ext/ply/test/lex_error3.exp new file mode 100644 index 000000000..936828f93 --- /dev/null +++ b/ext/ply/test/lex_error3.exp @@ -0,0 +1,2 @@ +./lex_error3.py:17: Rule 't_error' requires an argument. +SyntaxError: lex: Unable to build lexer. diff --git a/ext/ply/test/lex_error3.py b/ext/ply/test/lex_error3.py new file mode 100644 index 000000000..46facf589 --- /dev/null +++ b/ext/ply/test/lex_error3.py @@ -0,0 +1,25 @@ +# lex_token.py +# +# t_error defined as function, but with wrong # args + +import lex + +tokens = [ + "PLUS", + "MINUS", + "NUMBER", + ] + +t_PLUS = r'\+' +t_MINUS = r'-' +t_NUMBER = r'\d+' + +def t_error(): + pass + +import sys +sys.tracebacklimit = 0 + +lex.lex() + + diff --git a/ext/ply/test/lex_error4.exp b/ext/ply/test/lex_error4.exp new file mode 100644 index 000000000..242516576 --- /dev/null +++ b/ext/ply/test/lex_error4.exp @@ -0,0 +1,2 @@ +./lex_error4.py:17: Rule 't_error' has too many arguments. +SyntaxError: lex: Unable to build lexer. diff --git a/ext/ply/test/lex_error4.py b/ext/ply/test/lex_error4.py new file mode 100644 index 000000000..d777fee84 --- /dev/null +++ b/ext/ply/test/lex_error4.py @@ -0,0 +1,25 @@ +# lex_token.py +# +# t_error defined as function, but too many args + +import lex + +tokens = [ + "PLUS", + "MINUS", + "NUMBER", + ] + +t_PLUS = r'\+' +t_MINUS = r'-' +t_NUMBER = r'\d+' + +def t_error(t,s): + pass + +import sys +sys.tracebacklimit = 0 + +lex.lex() + + diff --git a/ext/ply/test/lex_hedit.exp b/ext/ply/test/lex_hedit.exp new file mode 100644 index 000000000..0b09827c6 --- /dev/null +++ b/ext/ply/test/lex_hedit.exp @@ -0,0 +1,3 @@ +(H_EDIT_DESCRIPTOR,'abc',1) +(H_EDIT_DESCRIPTOR,'abcdefghij',1) +(H_EDIT_DESCRIPTOR,'xy',1) diff --git a/ext/ply/test/lex_hedit.py b/ext/ply/test/lex_hedit.py new file mode 100644 index 000000000..68f9fcbd1 --- /dev/null +++ b/ext/ply/test/lex_hedit.py @@ -0,0 +1,44 @@ +# ----------------------------------------------------------------------------- +# hedit.py +# +# Paring of Fortran H Edit descriptions (Contributed by Pearu Peterson) +# +# These tokens can't be easily tokenized because they are of the following +# form: +# +# nHc1...cn +# +# where n is a positive integer and c1 ... cn are characters. +# +# This example shows how to modify the state of the lexer to parse +# such tokens +# ----------------------------------------------------------------------------- + +tokens = ( + 'H_EDIT_DESCRIPTOR', + ) + +# Tokens +t_ignore = " \t\n" + +def t_H_EDIT_DESCRIPTOR(t): + r"\d+H.*" # This grabs all of the remaining text + i = t.value.index('H') + n = eval(t.value[:i]) + + # Adjust the tokenizing position + t.lexer.lexpos -= len(t.value) - (i+1+n) + t.value = t.value[i+1:i+1+n] + return t + +def t_error(t): + print "Illegal character '%s'" % t.value[0] + t.skip(1) + +# Build the lexer +import lex +lex.lex() +lex.runmain(data="3Habc 10Habcdefghij 2Hxy") + + + diff --git a/ext/ply/test/lex_ignore.exp b/ext/ply/test/lex_ignore.exp new file mode 100644 index 000000000..c3b04a154 --- /dev/null +++ b/ext/ply/test/lex_ignore.exp @@ -0,0 +1,2 @@ +./lex_ignore.py:17: Rule 't_ignore' must be defined as a string. +SyntaxError: lex: Unable to build lexer. diff --git a/ext/ply/test/lex_ignore.py b/ext/ply/test/lex_ignore.py new file mode 100644 index 000000000..49c303f81 --- /dev/null +++ b/ext/ply/test/lex_ignore.py @@ -0,0 +1,29 @@ +# lex_token.py +# +# Improperly specific ignore declaration + +import lex + +tokens = [ + "PLUS", + "MINUS", + "NUMBER", + ] + +t_PLUS = r'\+' +t_MINUS = r'-' +t_NUMBER = r'\d+' + +def t_ignore(t): + ' \t' + pass + +def t_error(t): + pass + +import sys +sys.tracebacklimit = 0 + +lex.lex() + + diff --git a/ext/ply/test/lex_re1.exp b/ext/ply/test/lex_re1.exp new file mode 100644 index 000000000..634eefefe --- /dev/null +++ b/ext/ply/test/lex_re1.exp @@ -0,0 +1,2 @@ +lex: Invalid regular expression for rule 't_NUMBER'. unbalanced parenthesis +SyntaxError: lex: Unable to build lexer. diff --git a/ext/ply/test/lex_re1.py b/ext/ply/test/lex_re1.py new file mode 100644 index 000000000..4a055ad72 --- /dev/null +++ b/ext/ply/test/lex_re1.py @@ -0,0 +1,25 @@ +# lex_token.py +# +# Bad regular expression in a string + +import lex + +tokens = [ + "PLUS", + "MINUS", + "NUMBER", + ] + +t_PLUS = r'\+' +t_MINUS = r'-' +t_NUMBER = r'(\d+' + +def t_error(t): + pass + +import sys +sys.tracebacklimit = 0 + +lex.lex() + + diff --git a/ext/ply/test/lex_rule1.exp b/ext/ply/test/lex_rule1.exp new file mode 100644 index 000000000..0c23ca294 --- /dev/null +++ b/ext/ply/test/lex_rule1.exp @@ -0,0 +1,2 @@ +lex: t_NUMBER not defined as a function or string +SyntaxError: lex: Unable to build lexer. diff --git a/ext/ply/test/lex_rule1.py b/ext/ply/test/lex_rule1.py new file mode 100644 index 000000000..ff3764ea1 --- /dev/null +++ b/ext/ply/test/lex_rule1.py @@ -0,0 +1,25 @@ +# lex_token.py +# +# Rule defined as some other type + +import lex + +tokens = [ + "PLUS", + "MINUS", + "NUMBER", + ] + +t_PLUS = r'\+' +t_MINUS = r'-' +t_NUMBER = 1 + +def t_error(t): + pass + +import sys +sys.tracebacklimit = 0 + +lex.lex() + + diff --git a/ext/ply/test/lex_token1.exp b/ext/ply/test/lex_token1.exp new file mode 100644 index 000000000..3792831fa --- /dev/null +++ b/ext/ply/test/lex_token1.exp @@ -0,0 +1 @@ +SyntaxError: lex: module does not define 'tokens' diff --git a/ext/ply/test/lex_token1.py b/ext/ply/test/lex_token1.py new file mode 100644 index 000000000..e8eca2b63 --- /dev/null +++ b/ext/ply/test/lex_token1.py @@ -0,0 +1,19 @@ +# lex_token.py +# +# Tests for absence of tokens variable + +import lex + +t_PLUS = r'\+' +t_MINUS = r'-' +t_NUMBER = r'\d+' + +def t_error(t): + pass + +import sys +sys.tracebacklimit = 0 + +lex.lex() + + diff --git a/ext/ply/test/lex_token2.exp b/ext/ply/test/lex_token2.exp new file mode 100644 index 000000000..3f98fe51d --- /dev/null +++ b/ext/ply/test/lex_token2.exp @@ -0,0 +1 @@ +SyntaxError: lex: tokens must be a list or tuple. diff --git a/ext/ply/test/lex_token2.py b/ext/ply/test/lex_token2.py new file mode 100644 index 000000000..38b34dabe --- /dev/null +++ b/ext/ply/test/lex_token2.py @@ -0,0 +1,21 @@ +# lex_token.py +# +# Tests for tokens of wrong type + +import lex + +tokens = "PLUS MINUS NUMBER" + +t_PLUS = r'\+' +t_MINUS = r'-' +t_NUMBER = r'\d+' + +def t_error(t): + pass + +import sys +sys.tracebacklimit = 0 + +lex.lex() + + diff --git a/ext/ply/test/lex_token3.exp b/ext/ply/test/lex_token3.exp new file mode 100644 index 000000000..d991d3c37 --- /dev/null +++ b/ext/ply/test/lex_token3.exp @@ -0,0 +1,2 @@ +lex: Rule 't_MINUS' defined for an unspecified token MINUS. +SyntaxError: lex: Unable to build lexer. diff --git a/ext/ply/test/lex_token3.py b/ext/ply/test/lex_token3.py new file mode 100644 index 000000000..909f9180d --- /dev/null +++ b/ext/ply/test/lex_token3.py @@ -0,0 +1,24 @@ +# lex_token.py +# +# tokens is right type, but is missing a token for one rule + +import lex + +tokens = [ + "PLUS", + "NUMBER", + ] + +t_PLUS = r'\+' +t_MINUS = r'-' +t_NUMBER = r'\d+' + +def t_error(t): + pass + +import sys +sys.tracebacklimit = 0 + +lex.lex() + + diff --git a/ext/ply/test/lex_token4.exp b/ext/ply/test/lex_token4.exp new file mode 100644 index 000000000..3dd88e05a --- /dev/null +++ b/ext/ply/test/lex_token4.exp @@ -0,0 +1,2 @@ +lex: Bad token name '-' +SyntaxError: lex: Unable to build lexer. diff --git a/ext/ply/test/lex_token4.py b/ext/ply/test/lex_token4.py new file mode 100644 index 000000000..d77d1662c --- /dev/null +++ b/ext/ply/test/lex_token4.py @@ -0,0 +1,26 @@ +# lex_token.py +# +# Bad token name + +import lex + +tokens = [ + "PLUS", + "MINUS", + "-", + "NUMBER", + ] + +t_PLUS = r'\+' +t_MINUS = r'-' +t_NUMBER = r'\d+' + +def t_error(t): + pass + +import sys +sys.tracebacklimit = 0 + +lex.lex() + + diff --git a/ext/ply/test/lex_token5.exp b/ext/ply/test/lex_token5.exp new file mode 100644 index 000000000..d7bcb2e7c --- /dev/null +++ b/ext/ply/test/lex_token5.exp @@ -0,0 +1 @@ +lex.LexError: ./lex_token5.py:16: Rule 't_NUMBER' returned an unknown token type 'NUM' diff --git a/ext/ply/test/lex_token5.py b/ext/ply/test/lex_token5.py new file mode 100644 index 000000000..d9b0c96aa --- /dev/null +++ b/ext/ply/test/lex_token5.py @@ -0,0 +1,31 @@ +# lex_token.py +# +# Return a bad token name + +import lex + +tokens = [ + "PLUS", + "MINUS", + "NUMBER", + ] + +t_PLUS = r'\+' +t_MINUS = r'-' + +def t_NUMBER(t): + r'\d+' + t.type = "NUM" + return t + +def t_error(t): + pass + +import sys +sys.tracebacklimit = 0 + +lex.lex() +lex.input("1234") +t = lex.token() + + diff --git a/ext/ply/test/testlex.py b/ext/ply/test/testlex.py new file mode 100755 index 000000000..df000b83d --- /dev/null +++ b/ext/ply/test/testlex.py @@ -0,0 +1,57 @@ +#!/usr/local/bin +# ---------------------------------------------------------------------- +# testlex.py +# +# Run tests for the lexing module +# ---------------------------------------------------------------------- + +import sys,os,glob + +if len(sys.argv) < 2: + print "Usage: python testlex.py directory" + raise SystemExit + +dirname = None +make = 0 + +for o in sys.argv[1:]: + if o == '-make': + make = 1 + else: + dirname = o + break + +if not dirname: + print "Usage: python testlex.py [-make] directory" + raise SystemExit + +f = glob.glob("%s/%s" % (dirname,"lex_*.py")) + +print "**** Running tests for lex ****" + +for t in f: + name = t[:-3] + print "Testing %-32s" % name, + if make: + if not os.path.exists("%s.exp" % name): + os.system("python %s.py >%s.exp 2>&1" % (name,name)) + passed = 1 + else: + os.system("python %s.py >%s.out 2>&1" % (name,name)) + a = os.system("diff %s.out %s.exp >%s.dif" % (name,name,name)) + if a == 0: + passed = 1 + else: + passed = 0 + + if passed: + print "Passed" + else: + print "Failed. See %s.dif" % name + + + + + + + diff --git a/ext/ply/test/testyacc.py b/ext/ply/test/testyacc.py new file mode 100644 index 000000000..a185cbb29 --- /dev/null +++ b/ext/ply/test/testyacc.py @@ -0,0 +1,58 @@ +#!/usr/local/bin +# ---------------------------------------------------------------------- +# testyacc.py +# +# Run tests for the yacc module +# ---------------------------------------------------------------------- + +import sys,os,glob + +if len(sys.argv) < 2: + print "Usage: python testyacc.py directory" + raise SystemExit + +dirname = None +make = 0 + +for o in sys.argv[1:]: + if o == '-make': + make = 1 + else: + dirname = o + break + +if not dirname: + print "Usage: python testyacc.py [-make] directory" + raise SystemExit + +f = glob.glob("%s/%s" % (dirname,"yacc_*.py")) + +print "**** Running tests for yacc ****" + +for t in f: + name = t[:-3] + print "Testing %-32s" % name, + os.system("rm -f %s/parsetab.*" % dirname) + if make: + if not os.path.exists("%s.exp" % name): + os.system("python %s.py >%s.exp 2>&1" % (name,name)) + passed = 1 + else: + os.system("python %s.py >%s.out 2>&1" % (name,name)) + a = os.system("diff %s.out %s.exp >%s.dif" % (name,name,name)) + if a == 0: + passed = 1 + else: + passed = 0 + + if passed: + print "Passed" + else: + print "Failed. See %s.dif" % name + + + + + + + diff --git a/ext/ply/test/yacc_badargs.exp b/ext/ply/test/yacc_badargs.exp new file mode 100644 index 000000000..b145c51f2 --- /dev/null +++ b/ext/ply/test/yacc_badargs.exp @@ -0,0 +1,3 @@ +./yacc_badargs.py:21: Rule 'p_statement_assign' has too many arguments. +./yacc_badargs.py:25: Rule 'p_statement_expr' requires an argument. +yacc.YaccError: Unable to construct parser. diff --git a/ext/ply/test/yacc_badargs.py b/ext/ply/test/yacc_badargs.py new file mode 100644 index 000000000..12075efcc --- /dev/null +++ b/ext/ply/test/yacc_badargs.py @@ -0,0 +1,67 @@ +# ----------------------------------------------------------------------------- +# yacc_badargs.py +# +# Rules with wrong # args +# ----------------------------------------------------------------------------- +import sys +sys.tracebacklimit = 0 + +from calclex import tokens + +# Parsing rules +precedence = ( + ('left','PLUS','MINUS'), + ('left','TIMES','DIVIDE'), + ('right','UMINUS'), + ) + +# dictionary of names +names = { } + +def p_statement_assign(t,s): + 'statement : NAME EQUALS expression' + names[t[1]] = t[3] + +def p_statement_expr(): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[3] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +def p_error(t): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc() + + + + diff --git a/ext/ply/test/yacc_badprec.exp b/ext/ply/test/yacc_badprec.exp new file mode 100644 index 000000000..7764b0246 --- /dev/null +++ b/ext/ply/test/yacc_badprec.exp @@ -0,0 +1 @@ +yacc.YaccError: precedence must be a list or tuple. diff --git a/ext/ply/test/yacc_badprec.py b/ext/ply/test/yacc_badprec.py new file mode 100644 index 000000000..55bf7720d --- /dev/null +++ b/ext/ply/test/yacc_badprec.py @@ -0,0 +1,63 @@ +# ----------------------------------------------------------------------------- +# yacc_badprec.py +# +# Bad precedence specifier +# ----------------------------------------------------------------------------- +import sys +sys.tracebacklimit = 0 + +from calclex import tokens + +# Parsing rules +precedence = "blah" + +# dictionary of names +names = { } + +def p_statement_assign(t): + 'statement : NAME EQUALS expression' + names[t[1]] = t[3] + +def p_statement_expr(t): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[3] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +def p_error(t): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc() + + + + diff --git a/ext/ply/test/yacc_badprec2.exp b/ext/ply/test/yacc_badprec2.exp new file mode 100644 index 000000000..1df1427b2 --- /dev/null +++ b/ext/ply/test/yacc_badprec2.exp @@ -0,0 +1,3 @@ +yacc: Invalid precedence table. +yacc: Generating SLR parsing table... +yacc: 4 shift/reduce conflicts diff --git a/ext/ply/test/yacc_badprec2.py b/ext/ply/test/yacc_badprec2.py new file mode 100644 index 000000000..9cbc99827 --- /dev/null +++ b/ext/ply/test/yacc_badprec2.py @@ -0,0 +1,67 @@ +# ----------------------------------------------------------------------------- +# yacc_badprec2.py +# +# Bad precedence +# ----------------------------------------------------------------------------- +import sys +sys.tracebacklimit = 0 + +from calclex import tokens + +# Parsing rules +precedence = ( + 42, + ('left','TIMES','DIVIDE'), + ('right','UMINUS'), + ) + +# dictionary of names +names = { } + +def p_statement_assign(t): + 'statement : NAME EQUALS expression' + names[t[1]] = t[3] + +def p_statement_expr(t): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[3] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +def p_error(t): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc() + + + + diff --git a/ext/ply/test/yacc_badrule.exp b/ext/ply/test/yacc_badrule.exp new file mode 100644 index 000000000..553779778 --- /dev/null +++ b/ext/ply/test/yacc_badrule.exp @@ -0,0 +1,5 @@ +./yacc_badrule.py:22: Syntax error. Expected ':' +./yacc_badrule.py:26: Syntax error in rule 'statement' +./yacc_badrule.py:31: Syntax error. Expected ':' +./yacc_badrule.py:40: Syntax error. Expected ':' +yacc.YaccError: Unable to construct parser. diff --git a/ext/ply/test/yacc_badrule.py b/ext/ply/test/yacc_badrule.py new file mode 100644 index 000000000..cad3a967e --- /dev/null +++ b/ext/ply/test/yacc_badrule.py @@ -0,0 +1,67 @@ +# ----------------------------------------------------------------------------- +# yacc_badrule.py +# +# Syntax problems in the rule strings +# ----------------------------------------------------------------------------- +import sys +sys.tracebacklimit = 0 + +from calclex import tokens + +# Parsing rules +precedence = ( + ('left','PLUS','MINUS'), + ('left','TIMES','DIVIDE'), + ('right','UMINUS'), + ) + +# dictionary of names +names = { } + +def p_statement_assign(t): + 'statement NAME EQUALS expression' + names[t[1]] = t[3] + +def p_statement_expr(t): + 'statement' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[3] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression: MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +def p_error(t): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc() + + + + diff --git a/ext/ply/test/yacc_badtok.exp b/ext/ply/test/yacc_badtok.exp new file mode 100644 index 000000000..f6e64726c --- /dev/null +++ b/ext/ply/test/yacc_badtok.exp @@ -0,0 +1 @@ +yacc.YaccError: tokens must be a list or tuple. diff --git a/ext/ply/test/yacc_badtok.py b/ext/ply/test/yacc_badtok.py new file mode 100644 index 000000000..a17d26aaa --- /dev/null +++ b/ext/ply/test/yacc_badtok.py @@ -0,0 +1,68 @@ +# ----------------------------------------------------------------------------- +# yacc_badtok.py +# +# A grammar, but tokens is a bad datatype +# ----------------------------------------------------------------------------- + +import sys +sys.tracebacklimit = 0 + +tokens = "Hello" + +# Parsing rules +precedence = ( + ('left','PLUS','MINUS'), + ('left','TIMES','DIVIDE'), + ('right','UMINUS'), + ) + +# dictionary of names +names = { } + +def p_statement_assign(t): + 'statement : NAME EQUALS expression' + names[t[1]] = t[3] + +def p_statement_expr(t): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[3] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +def p_error(t): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc() + + + + diff --git a/ext/ply/test/yacc_dup.exp b/ext/ply/test/yacc_dup.exp new file mode 100644 index 000000000..99f3fe22c --- /dev/null +++ b/ext/ply/test/yacc_dup.exp @@ -0,0 +1,4 @@ +./yacc_dup.py:25: Function p_statement redefined. Previously defined on line 21 +yacc: Warning. Token 'EQUALS' defined, but not used. +yacc: Warning. There is 1 unused token. +yacc: Generating SLR parsing table... diff --git a/ext/ply/test/yacc_dup.py b/ext/ply/test/yacc_dup.py new file mode 100644 index 000000000..557cd0ae1 --- /dev/null +++ b/ext/ply/test/yacc_dup.py @@ -0,0 +1,67 @@ +# ----------------------------------------------------------------------------- +# yacc_dup.py +# +# Duplicated rule name +# ----------------------------------------------------------------------------- +import sys +sys.tracebacklimit = 0 + +from calclex import tokens + +# Parsing rules +precedence = ( + ('left','PLUS','MINUS'), + ('left','TIMES','DIVIDE'), + ('right','UMINUS'), + ) + +# dictionary of names +names = { } + +def p_statement(t): + 'statement : NAME EQUALS expression' + names[t[1]] = t[3] + +def p_statement(t): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[3] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +def p_error(t): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc() + + + + diff --git a/ext/ply/test/yacc_error1.exp b/ext/ply/test/yacc_error1.exp new file mode 100644 index 000000000..980fc905c --- /dev/null +++ b/ext/ply/test/yacc_error1.exp @@ -0,0 +1 @@ +yacc.YaccError: ./yacc_error1.py:59: p_error() requires 1 argument. diff --git a/ext/ply/test/yacc_error1.py b/ext/ply/test/yacc_error1.py new file mode 100644 index 000000000..413004520 --- /dev/null +++ b/ext/ply/test/yacc_error1.py @@ -0,0 +1,67 @@ +# ----------------------------------------------------------------------------- +# yacc_error1.py +# +# Bad p_error() function +# ----------------------------------------------------------------------------- +import sys +sys.tracebacklimit = 0 + +from calclex import tokens + +# Parsing rules +precedence = ( + ('left','PLUS','MINUS'), + ('left','TIMES','DIVIDE'), + ('right','UMINUS'), + ) + +# dictionary of names +names = { } + +def p_statement_assign(t): + 'statement : NAME EQUALS expression' + names[t[1]] = t[3] + +def p_statement_expr(t): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[3] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +def p_error(t,s): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc() + + + + diff --git a/ext/ply/test/yacc_error2.exp b/ext/ply/test/yacc_error2.exp new file mode 100644 index 000000000..d0573b4dd --- /dev/null +++ b/ext/ply/test/yacc_error2.exp @@ -0,0 +1 @@ +yacc.YaccError: ./yacc_error2.py:59: p_error() requires 1 argument. diff --git a/ext/ply/test/yacc_error2.py b/ext/ply/test/yacc_error2.py new file mode 100644 index 000000000..d4fd1d219 --- /dev/null +++ b/ext/ply/test/yacc_error2.py @@ -0,0 +1,67 @@ +# ----------------------------------------------------------------------------- +# yacc_error1.py +# +# Bad p_error() function +# ----------------------------------------------------------------------------- +import sys +sys.tracebacklimit = 0 + +from calclex import tokens + +# Parsing rules +precedence = ( + ('left','PLUS','MINUS'), + ('left','TIMES','DIVIDE'), + ('right','UMINUS'), + ) + +# dictionary of names +names = { } + +def p_statement_assign(t): + 'statement : NAME EQUALS expression' + names[t[1]] = t[3] + +def p_statement_expr(t): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[3] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +def p_error(): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc() + + + + diff --git a/ext/ply/test/yacc_error3.exp b/ext/ply/test/yacc_error3.exp new file mode 100644 index 000000000..31eaee754 --- /dev/null +++ b/ext/ply/test/yacc_error3.exp @@ -0,0 +1 @@ +yacc.YaccError: 'p_error' defined, but is not a function. diff --git a/ext/ply/test/yacc_error3.py b/ext/ply/test/yacc_error3.py new file mode 100644 index 000000000..7093fab48 --- /dev/null +++ b/ext/ply/test/yacc_error3.py @@ -0,0 +1,66 @@ +# ----------------------------------------------------------------------------- +# yacc_error1.py +# +# Bad p_error() function +# ----------------------------------------------------------------------------- +import sys +sys.tracebacklimit = 0 + +from calclex import tokens + +# Parsing rules +precedence = ( + ('left','PLUS','MINUS'), + ('left','TIMES','DIVIDE'), + ('right','UMINUS'), + ) + +# dictionary of names +names = { } + +def p_statement_assign(t): + 'statement : NAME EQUALS expression' + names[t[1]] = t[3] + +def p_statement_expr(t): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[3] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +p_error = "blah" + +import yacc +yacc.yacc() + + + + diff --git a/ext/ply/test/yacc_inf.exp b/ext/ply/test/yacc_inf.exp new file mode 100644 index 000000000..a7f47dada --- /dev/null +++ b/ext/ply/test/yacc_inf.exp @@ -0,0 +1,5 @@ +yacc: Warning. Token 'NUMBER' defined, but not used. +yacc: Warning. There is 1 unused token. +yacc: Infinite recursion detected for symbol 'statement'. +yacc: Infinite recursion detected for symbol 'expression'. +yacc.YaccError: Unable to construct parser. diff --git a/ext/ply/test/yacc_inf.py b/ext/ply/test/yacc_inf.py new file mode 100644 index 000000000..885e2c4df --- /dev/null +++ b/ext/ply/test/yacc_inf.py @@ -0,0 +1,55 @@ +# ----------------------------------------------------------------------------- +# yacc_inf.py +# +# Infinite recursion +# ----------------------------------------------------------------------------- +import sys +sys.tracebacklimit = 0 + +from calclex import tokens + +# Parsing rules +precedence = ( + ('left','PLUS','MINUS'), + ('left','TIMES','DIVIDE'), + ('right','UMINUS'), + ) + +# dictionary of names +names = { } + +def p_statement_assign(t): + 'statement : NAME EQUALS expression' + names[t[1]] = t[3] + +def p_statement_expr(t): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[3] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_error(t): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc() + + + + diff --git a/ext/ply/test/yacc_missing1.exp b/ext/ply/test/yacc_missing1.exp new file mode 100644 index 000000000..065d6a54a --- /dev/null +++ b/ext/ply/test/yacc_missing1.exp @@ -0,0 +1,2 @@ +./yacc_missing1.py:22: Symbol 'location' used, but not defined as a token or a rule. +yacc.YaccError: Unable to construct parser. diff --git a/ext/ply/test/yacc_missing1.py b/ext/ply/test/yacc_missing1.py new file mode 100644 index 000000000..e63904d0e --- /dev/null +++ b/ext/ply/test/yacc_missing1.py @@ -0,0 +1,67 @@ +# ----------------------------------------------------------------------------- +# yacc_missing1.py +# +# Grammar with a missing rule +# ----------------------------------------------------------------------------- +import sys +sys.tracebacklimit = 0 + +from calclex import tokens + +# Parsing rules +precedence = ( + ('left','PLUS','MINUS'), + ('left','TIMES','DIVIDE'), + ('right','UMINUS'), + ) + +# dictionary of names +names = { } + +def p_statement_assign(t): + 'statement : location EQUALS expression' + names[t[1]] = t[3] + +def p_statement_expr(t): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[3] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +def p_error(t): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc() + + + + diff --git a/ext/ply/test/yacc_nodoc.exp b/ext/ply/test/yacc_nodoc.exp new file mode 100644 index 000000000..3f52a3287 --- /dev/null +++ b/ext/ply/test/yacc_nodoc.exp @@ -0,0 +1,2 @@ +./yacc_nodoc.py:25: No documentation string specified in function 'p_statement_expr' +yacc: Generating SLR parsing table... diff --git a/ext/ply/test/yacc_nodoc.py b/ext/ply/test/yacc_nodoc.py new file mode 100644 index 000000000..e3941bdaa --- /dev/null +++ b/ext/ply/test/yacc_nodoc.py @@ -0,0 +1,66 @@ +# ----------------------------------------------------------------------------- +# yacc_nodoc.py +# +# Rule with a missing doc-string +# ----------------------------------------------------------------------------- +import sys +sys.tracebacklimit = 0 + +from calclex import tokens + +# Parsing rules +precedence = ( + ('left','PLUS','MINUS'), + ('left','TIMES','DIVIDE'), + ('right','UMINUS'), + ) + +# dictionary of names +names = { } + +def p_statement_assign(t): + 'statement : NAME EQUALS expression' + names[t[1]] = t[3] + +def p_statement_expr(t): + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[3] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +def p_error(t): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc() + + + + diff --git a/ext/ply/test/yacc_noerror.exp b/ext/ply/test/yacc_noerror.exp new file mode 100644 index 000000000..986fa31fa --- /dev/null +++ b/ext/ply/test/yacc_noerror.exp @@ -0,0 +1,2 @@ +yacc: Warning. no p_error() function is defined. +yacc: Generating SLR parsing table... diff --git a/ext/ply/test/yacc_noerror.py b/ext/ply/test/yacc_noerror.py new file mode 100644 index 000000000..d92f48ea6 --- /dev/null +++ b/ext/ply/test/yacc_noerror.py @@ -0,0 +1,64 @@ +# ----------------------------------------------------------------------------- +# yacc_noerror.py +# +# No p_error() rule defined. +# ----------------------------------------------------------------------------- +import sys +sys.tracebacklimit = 0 + +from calclex import tokens + +# Parsing rules +precedence = ( + ('left','PLUS','MINUS'), + ('left','TIMES','DIVIDE'), + ('right','UMINUS'), + ) + +# dictionary of names +names = { } + +def p_statement_assign(t): + 'statement : NAME EQUALS expression' + names[t[1]] = t[3] + +def p_statement_expr(t): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[3] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +import yacc +yacc.yacc() + + + + diff --git a/ext/ply/test/yacc_nop.exp b/ext/ply/test/yacc_nop.exp new file mode 100644 index 000000000..062878b9e --- /dev/null +++ b/ext/ply/test/yacc_nop.exp @@ -0,0 +1,2 @@ +./yacc_nop.py:25: Warning. Possible grammar rule 'statement_expr' defined without p_ prefix. +yacc: Generating SLR parsing table... diff --git a/ext/ply/test/yacc_nop.py b/ext/ply/test/yacc_nop.py new file mode 100644 index 000000000..c599ffd5d --- /dev/null +++ b/ext/ply/test/yacc_nop.py @@ -0,0 +1,67 @@ +# ----------------------------------------------------------------------------- +# yacc_nop.py +# +# Possible grammar rule defined without p_ prefix +# ----------------------------------------------------------------------------- +import sys +sys.tracebacklimit = 0 + +from calclex import tokens + +# Parsing rules +precedence = ( + ('left','PLUS','MINUS'), + ('left','TIMES','DIVIDE'), + ('right','UMINUS'), + ) + +# dictionary of names +names = { } + +def p_statement_assign(t): + 'statement : NAME EQUALS expression' + names[t[1]] = t[3] + +def statement_expr(t): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[3] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +def p_error(t): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc() + + + + diff --git a/ext/ply/test/yacc_notfunc.exp b/ext/ply/test/yacc_notfunc.exp new file mode 100644 index 000000000..271167341 --- /dev/null +++ b/ext/ply/test/yacc_notfunc.exp @@ -0,0 +1,4 @@ +yacc: Warning. 'p_statement_assign' not defined as a function +yacc: Warning. Token 'EQUALS' defined, but not used. +yacc: Warning. There is 1 unused token. +yacc: Generating SLR parsing table... diff --git a/ext/ply/test/yacc_notfunc.py b/ext/ply/test/yacc_notfunc.py new file mode 100644 index 000000000..f61663d60 --- /dev/null +++ b/ext/ply/test/yacc_notfunc.py @@ -0,0 +1,65 @@ +# ----------------------------------------------------------------------------- +# yacc_notfunc.py +# +# p_rule not defined as a function +# ----------------------------------------------------------------------------- +import sys +sys.tracebacklimit = 0 + +from calclex import tokens + +# Parsing rules +precedence = ( + ('left','PLUS','MINUS'), + ('left','TIMES','DIVIDE'), + ('right','UMINUS'), + ) + +# dictionary of names +names = { } + +p_statement_assign = "Blah" + +def p_statement_expr(t): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[3] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +def p_error(t): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc() + + + + diff --git a/ext/ply/test/yacc_notok.exp b/ext/ply/test/yacc_notok.exp new file mode 100644 index 000000000..708f6f597 --- /dev/null +++ b/ext/ply/test/yacc_notok.exp @@ -0,0 +1 @@ +yacc.YaccError: module does not define a list 'tokens' diff --git a/ext/ply/test/yacc_notok.py b/ext/ply/test/yacc_notok.py new file mode 100644 index 000000000..dfa0059be --- /dev/null +++ b/ext/ply/test/yacc_notok.py @@ -0,0 +1,66 @@ +# ----------------------------------------------------------------------------- +# yacc_notok.py +# +# A grammar, but we forgot to import the tokens list +# ----------------------------------------------------------------------------- + +import sys +sys.tracebacklimit = 0 + +# Parsing rules +precedence = ( + ('left','PLUS','MINUS'), + ('left','TIMES','DIVIDE'), + ('right','UMINUS'), + ) + +# dictionary of names +names = { } + +def p_statement_assign(t): + 'statement : NAME EQUALS expression' + names[t[1]] = t[3] + +def p_statement_expr(t): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[3] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +def p_error(t): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc() + + + + diff --git a/ext/ply/test/yacc_rr.exp b/ext/ply/test/yacc_rr.exp new file mode 100644 index 000000000..0ec556d16 --- /dev/null +++ b/ext/ply/test/yacc_rr.exp @@ -0,0 +1,2 @@ +yacc: Generating SLR parsing table... +yacc: 1 reduce/reduce conflict diff --git a/ext/ply/test/yacc_rr.py b/ext/ply/test/yacc_rr.py new file mode 100644 index 000000000..c061c2c17 --- /dev/null +++ b/ext/ply/test/yacc_rr.py @@ -0,0 +1,71 @@ +# ----------------------------------------------------------------------------- +# yacc_rr.py +# +# A grammar with a reduce/reduce conflict +# ----------------------------------------------------------------------------- +import sys +sys.tracebacklimit = 0 + +from calclex import tokens + +# Parsing rules +precedence = ( + ('left','PLUS','MINUS'), + ('left','TIMES','DIVIDE'), + ('right','UMINUS'), + ) + +# dictionary of names +names = { } + +def p_statement_assign(t): + 'statement : NAME EQUALS expression' + names[t[1]] = t[3] + +def p_statement_assign_2(t): + 'statement : NAME EQUALS NUMBER' + names[t[1]] = t[3] + +def p_statement_expr(t): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[3] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +def p_error(t): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc() + + + + diff --git a/ext/ply/test/yacc_simple.exp b/ext/ply/test/yacc_simple.exp new file mode 100644 index 000000000..de7964b6f --- /dev/null +++ b/ext/ply/test/yacc_simple.exp @@ -0,0 +1 @@ +yacc: Generating SLR parsing table... diff --git a/ext/ply/test/yacc_simple.py b/ext/ply/test/yacc_simple.py new file mode 100644 index 000000000..7b4b40b17 --- /dev/null +++ b/ext/ply/test/yacc_simple.py @@ -0,0 +1,67 @@ +# ----------------------------------------------------------------------------- +# yacc_simple.py +# +# A simple, properly specifier grammar +# ----------------------------------------------------------------------------- +import sys +sys.tracebacklimit = 0 + +from calclex import tokens + +# Parsing rules +precedence = ( + ('left','PLUS','MINUS'), + ('left','TIMES','DIVIDE'), + ('right','UMINUS'), + ) + +# dictionary of names +names = { } + +def p_statement_assign(t): + 'statement : NAME EQUALS expression' + names[t[1]] = t[3] + +def p_statement_expr(t): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[3] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +def p_error(t): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc() + + + + diff --git a/ext/ply/test/yacc_sr.exp b/ext/ply/test/yacc_sr.exp new file mode 100644 index 000000000..7225ad94b --- /dev/null +++ b/ext/ply/test/yacc_sr.exp @@ -0,0 +1,2 @@ +yacc: Generating SLR parsing table... +yacc: 20 shift/reduce conflicts diff --git a/ext/ply/test/yacc_sr.py b/ext/ply/test/yacc_sr.py new file mode 100644 index 000000000..4341f6997 --- /dev/null +++ b/ext/ply/test/yacc_sr.py @@ -0,0 +1,62 @@ +# ----------------------------------------------------------------------------- +# yacc_sr.py +# +# A grammar with shift-reduce conflicts +# ----------------------------------------------------------------------------- +import sys +sys.tracebacklimit = 0 + +from calclex import tokens + +# Parsing rules + +# dictionary of names +names = { } + +def p_statement_assign(t): + 'statement : NAME EQUALS expression' + names[t[1]] = t[3] + +def p_statement_expr(t): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[3] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +def p_error(t): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc() + + + + diff --git a/ext/ply/test/yacc_term1.exp b/ext/ply/test/yacc_term1.exp new file mode 100644 index 000000000..422d2bacd --- /dev/null +++ b/ext/ply/test/yacc_term1.exp @@ -0,0 +1,2 @@ +./yacc_term1.py:22: Illegal rule name 'NUMBER'. Already defined as a token. +yacc.YaccError: Unable to construct parser. diff --git a/ext/ply/test/yacc_term1.py b/ext/ply/test/yacc_term1.py new file mode 100644 index 000000000..97a2e7a60 --- /dev/null +++ b/ext/ply/test/yacc_term1.py @@ -0,0 +1,67 @@ +# ----------------------------------------------------------------------------- +# yacc_term1.py +# +# Terminal used on the left-hand-side +# ----------------------------------------------------------------------------- +import sys +sys.tracebacklimit = 0 + +from calclex import tokens + +# Parsing rules +precedence = ( + ('left','PLUS','MINUS'), + ('left','TIMES','DIVIDE'), + ('right','UMINUS'), + ) + +# dictionary of names +names = { } + +def p_statement_assign(t): + 'NUMBER : NAME EQUALS expression' + names[t[1]] = t[3] + +def p_statement_expr(t): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[3] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +def p_error(t): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc() + + + + diff --git a/ext/ply/test/yacc_unused.exp b/ext/ply/test/yacc_unused.exp new file mode 100644 index 000000000..390754de3 --- /dev/null +++ b/ext/ply/test/yacc_unused.exp @@ -0,0 +1,4 @@ +./yacc_unused.py:60: Symbol 'COMMA' used, but not defined as a token or a rule. +yacc: Symbol 'COMMA' is unreachable. +yacc: Symbol 'exprlist' is unreachable. +yacc.YaccError: Unable to construct parser. diff --git a/ext/ply/test/yacc_unused.py b/ext/ply/test/yacc_unused.py new file mode 100644 index 000000000..4cbd63327 --- /dev/null +++ b/ext/ply/test/yacc_unused.py @@ -0,0 +1,76 @@ +# ----------------------------------------------------------------------------- +# yacc_unused.py +# +# A grammar with an unused rule +# ----------------------------------------------------------------------------- +import sys +sys.tracebacklimit = 0 + +from calclex import tokens + +# Parsing rules +precedence = ( + ('left','PLUS','MINUS'), + ('left','TIMES','DIVIDE'), + ('right','UMINUS'), + ) + +# dictionary of names +names = { } + +def p_statement_assign(t): + 'statement : NAME EQUALS expression' + names[t[1]] = t[3] + +def p_statement_expr(t): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[3] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +def p_expr_list(t): + 'exprlist : exprlist COMMA expression' + pass + +def p_expr_list_2(t): + 'exprlist : expression' + pass + + +def p_error(t): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc() + + + + diff --git a/ext/ply/test/yacc_uprec.exp b/ext/ply/test/yacc_uprec.exp new file mode 100644 index 000000000..b1a71a250 --- /dev/null +++ b/ext/ply/test/yacc_uprec.exp @@ -0,0 +1,2 @@ +./yacc_uprec.py:35: Nothing known about the precedence of 'UMINUS' +yacc.YaccError: Unable to construct parser. diff --git a/ext/ply/test/yacc_uprec.py b/ext/ply/test/yacc_uprec.py new file mode 100644 index 000000000..139ce6318 --- /dev/null +++ b/ext/ply/test/yacc_uprec.py @@ -0,0 +1,62 @@ +# ----------------------------------------------------------------------------- +# yacc_uprec.py +# +# A grammar with a bad %prec specifier +# ----------------------------------------------------------------------------- +import sys +sys.tracebacklimit = 0 + +from calclex import tokens + +# Parsing rules + +# dictionary of names +names = { } + +def p_statement_assign(t): + 'statement : NAME EQUALS expression' + names[t[1]] = t[3] + +def p_statement_expr(t): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[3] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +def p_error(t): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc() + + + + diff --git a/ext/ply/yacc.py b/ext/ply/yacc.py new file mode 100644 index 000000000..1041745ed --- /dev/null +++ b/ext/ply/yacc.py @@ -0,0 +1,1846 @@ +#----------------------------------------------------------------------------- +# ply: yacc.py +# +# Author: David M. Beazley (beazley@cs.uchicago.edu) +# Department of Computer Science +# University of Chicago +# Chicago, IL 60637 +# +# Copyright (C) 2001, David M. Beazley +# +# $Header: /home/stever/bk/newmem2/ext/ply/yacc.py 1.3 03/06/06 14:59:28-00:00 stever@ $ +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See the file COPYING for a complete copy of the LGPL. +# +# +# This implements an LR parser that is constructed from grammar rules defined +# as Python functions. Roughly speaking, this module is a cross between +# John Aycock's Spark system and the GNU bison utility. +# +# Disclaimer: This is a work in progress. SLR parsing seems to work fairly +# well and there is extensive error checking. LALR(1) is in progress. The +# rest of this file is a bit of a mess. Please pardon the dust. +# +# The current implementation is only somewhat object-oriented. The +# LR parser itself is defined in terms of an object (which allows multiple +# parsers to co-exist). However, most of the variables used during table +# construction are defined in terms of global variables. Users shouldn't +# notice unless they are trying to define multiple parsers at the same +# time using threads (in which case they should have their head examined). +#----------------------------------------------------------------------------- + +__version__ = "1.3" + +#----------------------------------------------------------------------------- +# === User configurable parameters === +# +# Change these to modify the default behavior of yacc (if you wish) +#----------------------------------------------------------------------------- + +yaccdebug = 1 # Debugging mode. If set, yacc generates a + # a 'parser.out' file in the current directory + +debug_file = 'parser.out' # Default name of the debugging file +tab_module = 'parsetab' # Default name of the table module +default_lr = 'SLR' # Default LR table generation method + +error_count = 3 # Number of symbols that must be shifted to leave recovery mode + +import re, types, sys, cStringIO, md5, os.path + +# Exception raised for yacc-related errors +class YaccError(Exception): pass + +#----------------------------------------------------------------------------- +# === LR Parsing Engine === +# +# The following classes are used for the LR parser itself. These are not +# used during table construction and are independent of the actual LR +# table generation algorithm +#----------------------------------------------------------------------------- + +# This class is used to hold non-terminal grammar symbols during parsing. +# It normally has the following attributes set: +# .type = Grammar symbol type +# .value = Symbol value +# .lineno = Starting line number +# .endlineno = Ending line number (optional, set automatically) + +class YaccSymbol: + def __str__(self): return self.type + def __repr__(self): return str(self) + +# This class is a wrapper around the objects actually passed to each +# grammar rule. Index lookup and assignment actually assign the +# .value attribute of the underlying YaccSymbol object. +# The lineno() method returns the line number of a given +# item (or 0 if not defined). The linespan() method returns +# a tuple of (startline,endline) representing the range of lines +# for a symbol. + +class YaccSlice: + def __init__(self,s): + self.slice = s + self.pbstack = [] + + def __getitem__(self,n): + return self.slice[n].value + + def __setitem__(self,n,v): + self.slice[n].value = v + + def __len__(self): + return len(self.slice) + + def lineno(self,n): + return getattr(self.slice[n],"lineno",0) + + def linespan(self,n): + startline = getattr(self.slice[n],"lineno",0) + endline = getattr(self.slice[n],"endlineno",startline) + return startline,endline + + def pushback(self,n): + if n <= 0: + raise ValueError, "Expected a positive value" + if n > (len(self.slice)-1): + raise ValueError, "Can't push %d tokens. Only %d are available." % (n,len(self.slice)-1) + for i in range(0,n): + self.pbstack.append(self.slice[-i-1]) + +# The LR Parsing engine. This is defined as a class so that multiple parsers +# can exist in the same process. A user never instantiates this directly. +# Instead, the global yacc() function should be used to create a suitable Parser +# object. + +class Parser: + def __init__(self,magic=None): + + # This is a hack to keep users from trying to instantiate a Parser + # object directly. + + if magic != "xyzzy": + raise YaccError, "Can't instantiate Parser. Use yacc() instead." + + # Reset internal state + self.productions = None # List of productions + self.errorfunc = None # Error handling function + self.action = { } # LR Action table + self.goto = { } # LR goto table + self.require = { } # Attribute require table + self.method = "Unknown LR" # Table construction method used + + def errok(self): + self.errorcount = 0 + + def restart(self): + del self.statestack[:] + del self.symstack[:] + sym = YaccSymbol() + sym.type = '$' + self.symstack.append(sym) + self.statestack.append(0) + + def parse(self,input=None,lexer=None,debug=0): + lookahead = None # Current lookahead symbol + lookaheadstack = [ ] # Stack of lookahead symbols + actions = self.action # Local reference to action table + goto = self.goto # Local reference to goto table + prod = self.productions # Local reference to production list + pslice = YaccSlice(None) # Slice object passed to grammar rules + pslice.parser = self # Parser object + self.errorcount = 0 # Used during error recovery + + # If no lexer was given, we will try to use the lex module + if not lexer: + import lex as lexer + + pslice.lexer = lexer + + # If input was supplied, pass to lexer + if input: + lexer.input(input) + + # Tokenize function + get_token = lexer.token + + statestack = [ ] # Stack of parsing states + self.statestack = statestack + symstack = [ ] # Stack of grammar symbols + self.symstack = symstack + + errtoken = None # Err token + + # The start state is assumed to be (0,$) + statestack.append(0) + sym = YaccSymbol() + sym.type = '$' + symstack.append(sym) + + while 1: + # Get the next symbol on the input. If a lookahead symbol + # is already set, we just use that. Otherwise, we'll pull + # the next token off of the lookaheadstack or from the lexer + if not lookahead: + if not lookaheadstack: + lookahead = get_token() # Get the next token + else: + lookahead = lookaheadstack.pop() + if not lookahead: + lookahead = YaccSymbol() + lookahead.type = '$' + if debug: + print "%-20s : %s" % (lookahead, [xx.type for xx in symstack]) + + # Check the action table + s = statestack[-1] + ltype = lookahead.type + t = actions.get((s,ltype),None) + + if t is not None: + if t > 0: + # shift a symbol on the stack + if ltype == '$': + # Error, end of input + print "yacc: Parse error. EOF" + return + statestack.append(t) + symstack.append(lookahead) + lookahead = None + + # Decrease error count on successful shift + if self.errorcount > 0: + self.errorcount -= 1 + + continue + + if t < 0: + # reduce a symbol on the stack, emit a production + p = prod[-t] + pname = p.name + plen = p.len + + # Get production function + sym = YaccSymbol() + sym.type = pname # Production name + sym.value = None + + if plen: + targ = symstack[-plen-1:] + targ[0] = sym + try: + sym.lineno = targ[1].lineno + sym.endlineno = getattr(targ[-1],"endlineno",targ[-1].lineno) + except AttributeError: + sym.lineno = 0 + del symstack[-plen:] + del statestack[-plen:] + else: + sym.lineno = 0 + targ = [ sym ] + pslice.slice = targ + pslice.pbstack = [] + # Call the grammar rule with our special slice object + p.func(pslice) + + # Validate attributes of the resulting value attribute +# if require: +# try: +# t0 = targ[0] +# r = Requires.get(t0.type,None) +# t0d = t0.__dict__ +# if r: +# for field in r: +# tn = t0 +# for fname in field: +# try: +# tf = tn.__dict__ +# tn = tf.get(fname) +# except StandardError: +# tn = None +# if not tn: +# print "%s:%d: Rule %s doesn't set required attribute '%s'" % \ +# (p.file,p.line,p.name,".".join(field)) +# except TypeError,LookupError: +# print "Bad requires directive " % r +# pass + + + # If there was a pushback, put that on the stack + if pslice.pbstack: + lookaheadstack.append(lookahead) + for _t in pslice.pbstack: + lookaheadstack.append(_t) + lookahead = None + + symstack.append(sym) + statestack.append(goto[statestack[-1],pname]) + continue + + if t == 0: + n = symstack[-1] + return getattr(n,"value",None) + + if t == None: + # We have some kind of parsing error here. To handle this, + # we are going to push the current token onto the tokenstack + # and replace it with an 'error' token. If there are any synchronization + # rules, they may catch it. + # + # In addition to pushing the error token, we call call the user defined p_error() + # function if this is the first syntax error. This function is only called + # if errorcount == 0. + + if not self.errorcount: + self.errorcount = error_count + errtoken = lookahead + if errtoken.type == '$': + errtoken = None # End of file! + if self.errorfunc: + global errok,token,restart + errok = self.errok # Set some special functions available in error recovery + token = get_token + restart = self.restart + tok = self.errorfunc(errtoken) + del errok, token, restart # Delete special functions + + if not self.errorcount: + # User must have done some kind of panic mode recovery on their own. The returned token + # is the next lookahead + lookahead = tok + errtoken = None + continue + else: + if errtoken: + if hasattr(errtoken,"lineno"): lineno = lookahead.lineno + else: lineno = 0 + if lineno: + print "yacc: Syntax error at line %d, token=%s" % (lineno, errtoken.type) + else: + print "yacc: Syntax error, token=%s" % errtoken.type + else: + print "yacc: Parse error in input. EOF" + return + + else: + self.errorcount = error_count + + # case 1: the statestack only has 1 entry on it. If we're in this state, the + # entire parse has been rolled back and we're completely hosed. The token is + # discarded and we just keep going. + + if len(statestack) <= 1 and lookahead.type != '$': + lookahead = None + errtoken = None + # Nuke the pushback stack + del lookaheadstack[:] + continue + + # case 2: the statestack has a couple of entries on it, but we're + # at the end of the file. nuke the top entry and generate an error token + + # Start nuking entries on the stack + if lookahead.type == '$': + # Whoa. We're really hosed here. Bail out + return + + if lookahead.type != 'error': + sym = symstack[-1] + if sym.type == 'error': + # Hmmm. Error is on top of stack, we'll just nuke input + # symbol and continue + lookahead = None + continue + t = YaccSymbol() + t.type = 'error' + if hasattr(lookahead,"lineno"): + t.lineno = lookahead.lineno + t.value = lookahead + lookaheadstack.append(lookahead) + lookahead = t + else: + symstack.pop() + statestack.pop() + + continue + + # Call an error function here + raise RuntimeError, "yacc: internal parser error!!!\n" + +# ----------------------------------------------------------------------------- +# === Parser Construction === +# +# The following functions and variables are used to implement the yacc() function +# itself. This is pretty hairy stuff involving lots of error checking, +# construction of LR items, kernels, and so forth. Although a lot of +# this work is done using global variables, the resulting Parser object +# is completely self contained--meaning that it is safe to repeatedly +# call yacc() with different grammars in the same application. +# ----------------------------------------------------------------------------- + +# ----------------------------------------------------------------------------- +# validate_file() +# +# This function checks to see if there are duplicated p_rulename() functions +# in the parser module file. Without this function, it is really easy for +# users to make mistakes by cutting and pasting code fragments (and it's a real +# bugger to try and figure out why the resulting parser doesn't work). Therefore, +# we just do a little regular expression pattern matching of def statements +# to try and detect duplicates. +# ----------------------------------------------------------------------------- + +def validate_file(filename): + base,ext = os.path.splitext(filename) + if ext != '.py': return 1 # No idea. Assume it's okay. + + try: + f = open(filename) + lines = f.readlines() + f.close() + except IOError: + return 1 # Oh well + + # Match def p_funcname( + fre = re.compile(r'\s*def\s+(p_[a-zA-Z_0-9]*)\(') + counthash = { } + linen = 1 + noerror = 1 + for l in lines: + m = fre.match(l) + if m: + name = m.group(1) + prev = counthash.get(name) + if not prev: + counthash[name] = linen + else: + print "%s:%d: Function %s redefined. Previously defined on line %d" % (filename,linen,name,prev) + noerror = 0 + linen += 1 + return noerror + +# This function looks for functions that might be grammar rules, but which don't have the proper p_suffix. +def validate_dict(d): + for n,v in d.items(): + if n[0:2] == 'p_' and isinstance(v,types.FunctionType): continue + if n[0:2] == 't_': continue + + if n[0:2] == 'p_': + print "yacc: Warning. '%s' not defined as a function" % n + if isinstance(v,types.FunctionType) and v.func_code.co_argcount == 1: + try: + doc = v.__doc__.split(" ") + if doc[1] == ':': + print "%s:%d: Warning. Possible grammar rule '%s' defined without p_ prefix." % (v.func_code.co_filename, v.func_code.co_firstlineno,n) + except StandardError: + pass + +# ----------------------------------------------------------------------------- +# === GRAMMAR FUNCTIONS === +# +# The following global variables and functions are used to store, manipulate, +# and verify the grammar rules specified by the user. +# ----------------------------------------------------------------------------- + +# Initialize all of the global variables used during grammar construction +def initialize_vars(): + global Productions, Prodnames, Prodmap, Terminals + global Nonterminals, First, Follow, Precedence, LRitems + global Errorfunc, Signature, Requires + + Productions = [None] # A list of all of the productions. The first + # entry is always reserved for the purpose of + # building an augmented grammar + + Prodnames = { } # A dictionary mapping the names of nonterminals to a list of all + # productions of that nonterminal. + + Prodmap = { } # A dictionary that is only used to detect duplicate + # productions. + + Terminals = { } # A dictionary mapping the names of terminal symbols to a + # list of the rules where they are used. + + Nonterminals = { } # A dictionary mapping names of nonterminals to a list + # of rule numbers where they are used. + + First = { } # A dictionary of precomputed FIRST(x) symbols + + Follow = { } # A dictionary of precomputed FOLLOW(x) symbols + + Precedence = { } # Precedence rules for each terminal. Contains tuples of the + # form ('right',level) or ('nonassoc', level) or ('left',level) + + LRitems = [ ] # A list of all LR items for the grammar. These are the + # productions with the "dot" like E -> E . PLUS E + + Errorfunc = None # User defined error handler + + Signature = md5.new() # Digital signature of the grammar rules, precedence + # and other information. Used to determined when a + # parsing table needs to be regenerated. + + Requires = { } # Requires list + + # File objects used when creating the parser.out debugging file + global _vf, _vfc + _vf = cStringIO.StringIO() + _vfc = cStringIO.StringIO() + +# ----------------------------------------------------------------------------- +# class Production: +# +# This class stores the raw information about a single production or grammar rule. +# It has a few required attributes: +# +# name - Name of the production (nonterminal) +# prod - A list of symbols making up its production +# number - Production number. +# +# In addition, a few additional attributes are used to help with debugging or +# optimization of table generation. +# +# file - File where production action is defined. +# lineno - Line number where action is defined +# func - Action function +# prec - Precedence level +# lr_next - Next LR item. Example, if we are ' E -> E . PLUS E' +# then lr_next refers to 'E -> E PLUS . E' +# lr_index - LR item index (location of the ".") in the prod list. +# len - Length of the production (number of symbols on right hand side) +# ----------------------------------------------------------------------------- + +class Production: + def __init__(self,**kw): + for k,v in kw.items(): + setattr(self,k,v) + self.lr_index = -1 + self.lr0_added = 0 # Flag indicating whether or not added to LR0 closure + self.usyms = [ ] + + def __str__(self): + if self.prod: + s = "%s -> %s" % (self.name," ".join(self.prod)) + else: + s = "%s -> <empty>" % self.name + return s + + def __repr__(self): + return str(self) + + # Compute lr_items from the production + def lr_item(self,n): + if n > len(self.prod): return None + p = Production() + p.name = self.name + p.prod = list(self.prod) + p.number = self.number + p.lr_index = n + p.prod.insert(n,".") + p.prod = tuple(p.prod) + p.len = len(p.prod) + p.usyms = self.usyms + + # Precompute list of productions immediately following + try: + p.lrafter = Prodnames[p.prod[n+1]] + except (IndexError,KeyError),e: + p.lrafter = [] + try: + p.lrbefore = p.prod[n-1] + except IndexError: + p.lrbefore = None + + return p + +class MiniProduction: + pass + +# Utility function +def is_identifier(s): + for c in s: + if not (c.isalnum() or c == '_'): return 0 + return 1 + +# ----------------------------------------------------------------------------- +# add_production() +# +# Given an action function, this function assembles a production rule. +# The production rule is assumed to be found in the function's docstring. +# This rule has the general syntax: +# +# name1 ::= production1 +# | production2 +# | production3 +# ... +# | productionn +# name2 ::= production1 +# | production2 +# ... +# ----------------------------------------------------------------------------- + +def add_production(f,file,line,prodname,syms): + + if Terminals.has_key(prodname): + print "%s:%d: Illegal rule name '%s'. Already defined as a token." % (file,line,prodname) + return -1 + if prodname == 'error': + print "%s:%d: Illegal rule name '%s'. error is a reserved word." % (file,line,prodname) + return -1 + + if not is_identifier(prodname): + print "%s:%d: Illegal rule name '%s'" % (file,line,prodname) + return -1 + + for s in syms: + if not is_identifier(s) and s != '%prec': + print "%s:%d: Illegal name '%s' in rule '%s'" % (file,line,s, prodname) + return -1 + + # See if the rule is already in the rulemap + map = "%s -> %s" % (prodname,syms) + if Prodmap.has_key(map): + m = Prodmap[map] + print "%s:%d: Duplicate rule %s." % (file,line, m) + print "%s:%d: Previous definition at %s:%d" % (file,line, m.file, m.line) + return -1 + + p = Production() + p.name = prodname + p.prod = syms + p.file = file + p.line = line + p.func = f + p.number = len(Productions) + + + Productions.append(p) + Prodmap[map] = p + if not Nonterminals.has_key(prodname): + Nonterminals[prodname] = [ ] + + # Add all terminals to Terminals + i = 0 + while i < len(p.prod): + t = p.prod[i] + if t == '%prec': + try: + precname = p.prod[i+1] + except IndexError: + print "%s:%d: Syntax error. Nothing follows %%prec." % (p.file,p.line) + return -1 + + prec = Precedence.get(precname,None) + if not prec: + print "%s:%d: Nothing known about the precedence of '%s'" % (p.file,p.line,precname) + return -1 + else: + p.prec = prec + del p.prod[i] + del p.prod[i] + continue + + if Terminals.has_key(t): + Terminals[t].append(p.number) + # Is a terminal. We'll assign a precedence to p based on this + if not hasattr(p,"prec"): + p.prec = Precedence.get(t,('right',0)) + else: + if not Nonterminals.has_key(t): + Nonterminals[t] = [ ] + Nonterminals[t].append(p.number) + i += 1 + + if not hasattr(p,"prec"): + p.prec = ('right',0) + + # Set final length of productions + p.len = len(p.prod) + p.prod = tuple(p.prod) + + # Calculate unique syms in the production + p.usyms = [ ] + for s in p.prod: + if s not in p.usyms: + p.usyms.append(s) + + # Add to the global productions list + try: + Prodnames[p.name].append(p) + except KeyError: + Prodnames[p.name] = [ p ] + return 0 + +# Given a raw rule function, this function rips out its doc string +# and adds rules to the grammar + +def add_function(f): + line = f.func_code.co_firstlineno + file = f.func_code.co_filename + error = 0 + + if f.func_code.co_argcount > 1: + print "%s:%d: Rule '%s' has too many arguments." % (file,line,f.__name__) + return -1 + + if f.func_code.co_argcount < 1: + print "%s:%d: Rule '%s' requires an argument." % (file,line,f.__name__) + return -1 + + if f.__doc__: + # Split the doc string into lines + pstrings = f.__doc__.splitlines() + lastp = None + dline = line + for ps in pstrings: + dline += 1 + p = ps.split() + if not p: continue + try: + if p[0] == '|': + # This is a continuation of a previous rule + if not lastp: + print "%s:%d: Misplaced '|'." % (file,dline) + return -1 + prodname = lastp + if len(p) > 1: + syms = p[1:] + else: + syms = [ ] + else: + prodname = p[0] + lastp = prodname + assign = p[1] + if len(p) > 2: + syms = p[2:] + else: + syms = [ ] + if assign != ':' and assign != '::=': + print "%s:%d: Syntax error. Expected ':'" % (file,dline) + return -1 + e = add_production(f,file,dline,prodname,syms) + error += e + except StandardError: + print "%s:%d: Syntax error in rule '%s'" % (file,dline,ps) + error -= 1 + else: + print "%s:%d: No documentation string specified in function '%s'" % (file,line,f.__name__) + return error + + +# Cycle checking code (Michael Dyck) + +def compute_reachable(): + ''' + Find each symbol that can be reached from the start symbol. + Print a warning for any nonterminals that can't be reached. + (Unused terminals have already had their warning.) + ''' + Reachable = { } + for s in Terminals.keys() + Nonterminals.keys(): + Reachable[s] = 0 + + mark_reachable_from( Productions[0].prod[0], Reachable ) + + for s in Nonterminals.keys(): + if not Reachable[s]: + print "yacc: Symbol '%s' is unreachable." % s + +def mark_reachable_from(s, Reachable): + ''' + Mark all symbols that are reachable from symbol s. + ''' + if Reachable[s]: + # We've already reached symbol s. + return + Reachable[s] = 1 + for p in Prodnames.get(s,[]): + for r in p.prod: + mark_reachable_from(r, Reachable) + +# ----------------------------------------------------------------------------- +# compute_terminates() +# +# This function looks at the various parsing rules and tries to detect +# infinite recursion cycles (grammar rules where there is no possible way +# to derive a string of only terminals). +# ----------------------------------------------------------------------------- +def compute_terminates(): + ''' + Raise an error for any symbols that don't terminate. + ''' + Terminates = {} + + # Terminals: + for t in Terminals.keys(): + Terminates[t] = 1 + + Terminates['$'] = 1 + + # Nonterminals: + + # Initialize to false: + for n in Nonterminals.keys(): + Terminates[n] = 0 + + # Then propagate termination until no change: + while 1: + some_change = 0 + for (n,pl) in Prodnames.items(): + # Nonterminal n terminates iff any of its productions terminates. + for p in pl: + # Production p terminates iff all of its rhs symbols terminate. + for s in p.prod: + if not Terminates[s]: + # The symbol s does not terminate, + # so production p does not terminate. + p_terminates = 0 + break + else: + # didn't break from the loop, + # so every symbol s terminates + # so production p terminates. + p_terminates = 1 + + if p_terminates: + # symbol n terminates! + if not Terminates[n]: + Terminates[n] = 1 + some_change = 1 + # Don't need to consider any more productions for this n. + break + + if not some_change: + break + + some_error = 0 + for (s,terminates) in Terminates.items(): + if not terminates: + if not Prodnames.has_key(s) and not Terminals.has_key(s) and s != 'error': + # s is used-but-not-defined, and we've already warned of that, + # so it would be overkill to say that it's also non-terminating. + pass + else: + print "yacc: Infinite recursion detected for symbol '%s'." % s + some_error = 1 + + return some_error + +# ----------------------------------------------------------------------------- +# verify_productions() +# +# This function examines all of the supplied rules to see if they seem valid. +# ----------------------------------------------------------------------------- +def verify_productions(cycle_check=1): + error = 0 + for p in Productions: + if not p: continue + + for s in p.prod: + if not Prodnames.has_key(s) and not Terminals.has_key(s) and s != 'error': + print "%s:%d: Symbol '%s' used, but not defined as a token or a rule." % (p.file,p.line,s) + error = 1 + continue + + unused_tok = 0 + # Now verify all of the tokens + if yaccdebug: + _vf.write("Unused terminals:\n\n") + for s,v in Terminals.items(): + if s != 'error' and not v: + print "yacc: Warning. Token '%s' defined, but not used." % s + if yaccdebug: _vf.write(" %s\n"% s) + unused_tok += 1 + + # Print out all of the productions + if yaccdebug: + _vf.write("\nGrammar\n\n") + for i in range(1,len(Productions)): + _vf.write("Rule %-5d %s\n" % (i, Productions[i])) + + unused_prod = 0 + # Verify the use of all productions + for s,v in Nonterminals.items(): + if not v: + p = Prodnames[s][0] + print "%s:%d: Warning. Rule '%s' defined, but not used." % (p.file,p.line, s) + unused_prod += 1 + + + if unused_tok == 1: + print "yacc: Warning. There is 1 unused token." + if unused_tok > 1: + print "yacc: Warning. There are %d unused tokens." % unused_tok + + if unused_prod == 1: + print "yacc: Warning. There is 1 unused rule." + if unused_prod > 1: + print "yacc: Warning. There are %d unused rules." % unused_prod + + if yaccdebug: + _vf.write("\nTerminals, with rules where they appear\n\n") + ks = Terminals.keys() + ks.sort() + for k in ks: + _vf.write("%-20s : %s\n" % (k, " ".join([str(s) for s in Terminals[k]]))) + _vf.write("\nNonterminals, with rules where they appear\n\n") + ks = Nonterminals.keys() + ks.sort() + for k in ks: + _vf.write("%-20s : %s\n" % (k, " ".join([str(s) for s in Nonterminals[k]]))) + + if (cycle_check): + compute_reachable() + error += compute_terminates() +# error += check_cycles() + return error + +# ----------------------------------------------------------------------------- +# build_lritems() +# +# This function walks the list of productions and builds a complete set of the +# LR items. The LR items are stored in two ways: First, they are uniquely +# numbered and placed in the list _lritems. Second, a linked list of LR items +# is built for each production. For example: +# +# E -> E PLUS E +# +# Creates the list +# +# [E -> . E PLUS E, E -> E . PLUS E, E -> E PLUS . E, E -> E PLUS E . ] +# ----------------------------------------------------------------------------- + +def build_lritems(): + for p in Productions: + lastlri = p + lri = p.lr_item(0) + i = 0 + while 1: + lri = p.lr_item(i) + lastlri.lr_next = lri + if not lri: break + lri.lr_num = len(LRitems) + LRitems.append(lri) + lastlri = lri + i += 1 + + # In order for the rest of the parser generator to work, we need to + # guarantee that no more lritems are generated. Therefore, we nuke + # the p.lr_item method. (Only used in debugging) + # Production.lr_item = None + +# ----------------------------------------------------------------------------- +# add_precedence() +# +# Given a list of precedence rules, add to the precedence table. +# ----------------------------------------------------------------------------- + +def add_precedence(plist): + plevel = 0 + error = 0 + for p in plist: + plevel += 1 + try: + prec = p[0] + terms = p[1:] + if prec != 'left' and prec != 'right' and prec != 'nonassoc': + print "yacc: Invalid precedence '%s'" % prec + return -1 + for t in terms: + if Precedence.has_key(t): + print "yacc: Precedence already specified for terminal '%s'" % t + error += 1 + continue + Precedence[t] = (prec,plevel) + except: + print "yacc: Invalid precedence table." + error += 1 + + return error + +# ----------------------------------------------------------------------------- +# augment_grammar() +# +# Compute the augmented grammar. This is just a rule S' -> start where start +# is the starting symbol. +# ----------------------------------------------------------------------------- + +def augment_grammar(start=None): + if not start: + start = Productions[1].name + Productions[0] = Production(name="S'",prod=[start],number=0,len=1,prec=('right',0),func=None) + Productions[0].usyms = [ start ] + Nonterminals[start].append(0) + + +# ------------------------------------------------------------------------- +# first() +# +# Compute the value of FIRST1(beta) where beta is a tuple of symbols. +# +# During execution of compute_first1, the result may be incomplete. +# Afterward (e.g., when called from compute_follow()), it will be complete. +# ------------------------------------------------------------------------- +def first(beta): + + # We are computing First(x1,x2,x3,...,xn) + result = [ ] + for x in beta: + x_produces_empty = 0 + + # Add all the non-<empty> symbols of First[x] to the result. + for f in First[x]: + if f == '<empty>': + x_produces_empty = 1 + else: + if f not in result: result.append(f) + + if x_produces_empty: + # We have to consider the next x in beta, + # i.e. stay in the loop. + pass + else: + # We don't have to consider any further symbols in beta. + break + else: + # There was no 'break' from the loop, + # so x_produces_empty was true for all x in beta, + # so beta produces empty as well. + result.append('<empty>') + + return result + + +# FOLLOW(x) +# Given a non-terminal. This function computes the set of all symbols +# that might follow it. Dragon book, p. 189. + +def compute_follow(start=None): + # Add '$' to the follow list of the start symbol + for k in Nonterminals.keys(): + Follow[k] = [ ] + + if not start: + start = Productions[1].name + + Follow[start] = [ '$' ] + + while 1: + didadd = 0 + for p in Productions[1:]: + # Here is the production set + for i in range(len(p.prod)): + B = p.prod[i] + if Nonterminals.has_key(B): + # Okay. We got a non-terminal in a production + fst = first(p.prod[i+1:]) + hasempty = 0 + for f in fst: + if f != '<empty>' and f not in Follow[B]: + Follow[B].append(f) + didadd = 1 + if f == '<empty>': + hasempty = 1 + if hasempty or i == (len(p.prod)-1): + # Add elements of follow(a) to follow(b) + for f in Follow[p.name]: + if f not in Follow[B]: + Follow[B].append(f) + didadd = 1 + if not didadd: break + + if 0 and yaccdebug: + _vf.write('\nFollow:\n') + for k in Nonterminals.keys(): + _vf.write("%-20s : %s\n" % (k, " ".join([str(s) for s in Follow[k]]))) + +# ------------------------------------------------------------------------- +# compute_first1() +# +# Compute the value of FIRST1(X) for all symbols +# ------------------------------------------------------------------------- +def compute_first1(): + + # Terminals: + for t in Terminals.keys(): + First[t] = [t] + + First['$'] = ['$'] + First['#'] = ['#'] # what's this for? + + # Nonterminals: + + # Initialize to the empty set: + for n in Nonterminals.keys(): + First[n] = [] + + # Then propagate symbols until no change: + while 1: + some_change = 0 + for n in Nonterminals.keys(): + for p in Prodnames[n]: + for f in first(p.prod): + if f not in First[n]: + First[n].append( f ) + some_change = 1 + if not some_change: + break + + if 0 and yaccdebug: + _vf.write('\nFirst:\n') + for k in Nonterminals.keys(): + _vf.write("%-20s : %s\n" % + (k, " ".join([str(s) for s in First[k]]))) + +# ----------------------------------------------------------------------------- +# === SLR Generation === +# +# The following functions are used to construct SLR (Simple LR) parsing tables +# as described on p.221-229 of the dragon book. +# ----------------------------------------------------------------------------- + +# Global variables for the LR parsing engine +def lr_init_vars(): + global _lr_action, _lr_goto, _lr_method + global _lr_goto_cache + + _lr_action = { } # Action table + _lr_goto = { } # Goto table + _lr_method = "Unknown" # LR method used + _lr_goto_cache = { } + +# Compute the LR(0) closure operation on I, where I is a set of LR(0) items. +# prodlist is a list of productions. + +_add_count = 0 # Counter used to detect cycles + +def lr0_closure(I): + global _add_count + + _add_count += 1 + prodlist = Productions + + # Add everything in I to J + J = I[:] + didadd = 1 + while didadd: + didadd = 0 + for j in J: + for x in j.lrafter: + if x.lr0_added == _add_count: continue + # Add B --> .G to J + J.append(x.lr_next) + x.lr0_added = _add_count + didadd = 1 + + return J + +# Compute the LR(0) goto function goto(I,X) where I is a set +# of LR(0) items and X is a grammar symbol. This function is written +# in a way that guarantees uniqueness of the generated goto sets +# (i.e. the same goto set will never be returned as two different Python +# objects). With uniqueness, we can later do fast set comparisons using +# id(obj) instead of element-wise comparison. + +def lr0_goto(I,x): + # First we look for a previously cached entry + g = _lr_goto_cache.get((id(I),x),None) + if g: return g + + # Now we generate the goto set in a way that guarantees uniqueness + # of the result + + s = _lr_goto_cache.get(x,None) + if not s: + s = { } + _lr_goto_cache[x] = s + + gs = [ ] + for p in I: + n = p.lr_next + if n and n.lrbefore == x: + s1 = s.get(id(n),None) + if not s1: + s1 = { } + s[id(n)] = s1 + gs.append(n) + s = s1 + g = s.get('$',None) + if not g: + if gs: + g = lr0_closure(gs) + s['$'] = g + else: + s['$'] = gs + _lr_goto_cache[(id(I),x)] = g + return g + +# Compute the kernel of a set of LR(0) items +def lr0_kernel(I): + KI = [ ] + for p in I: + if p.name == "S'" or p.lr_index > 0 or p.len == 0: + KI.append(p) + + return KI + +_lr0_cidhash = { } + +# Compute the LR(0) sets of item function +def lr0_items(): + + C = [ lr0_closure([Productions[0].lr_next]) ] + i = 0 + for I in C: + _lr0_cidhash[id(I)] = i + i += 1 + + # Loop over the items in C and each grammar symbols + i = 0 + while i < len(C): + I = C[i] + i += 1 + + # Collect all of the symbols that could possibly be in the goto(I,X) sets + asyms = { } + for ii in I: + for s in ii.usyms: + asyms[s] = None + + for x in asyms.keys(): + g = lr0_goto(I,x) + if not g: continue + if _lr0_cidhash.has_key(id(g)): continue + _lr0_cidhash[id(g)] = len(C) + C.append(g) + + return C + +# ----------------------------------------------------------------------------- +# slr_parse_table() +# +# This function constructs an SLR table. +# ----------------------------------------------------------------------------- +def slr_parse_table(): + global _lr_method + goto = _lr_goto # Goto array + action = _lr_action # Action array + actionp = { } # Action production array (temporary) + + _lr_method = "SLR" + + n_srconflict = 0 + n_rrconflict = 0 + + if yaccdebug: + _vf.write("\n\nParsing method: SLR\n\n") + + # Step 1: Construct C = { I0, I1, ... IN}, collection of LR(0) items + # This determines the number of states + + C = lr0_items() + + # Build the parser table, state by state + st = 0 + for I in C: + # Loop over each production in I + actlist = [ ] # List of actions + + if yaccdebug: + _vf.write("\nstate %d\n\n" % st) + for p in I: + _vf.write(" (%d) %s\n" % (p.number, str(p))) + _vf.write("\n") + + for p in I: + try: + if p.prod[-1] == ".": + if p.name == "S'": + # Start symbol. Accept! + action[st,"$"] = 0 + actionp[st,"$"] = p + else: + # We are at the end of a production. Reduce! + for a in Follow[p.name]: + actlist.append((a,p,"reduce using rule %d (%s)" % (p.number,p))) + r = action.get((st,a),None) + if r is not None: + # Whoa. Have a shift/reduce or reduce/reduce conflict + if r > 0: + # Need to decide on shift or reduce here + # By default we favor shifting. Need to add + # some precedence rules here. + sprec,slevel = Productions[actionp[st,a].number].prec + rprec,rlevel = Precedence.get(a,('right',0)) + if (slevel < rlevel) or ((slevel == rlevel) and (rprec == 'left')): + # We really need to reduce here. + action[st,a] = -p.number + actionp[st,a] = p + if not slevel and not rlevel: + _vfc.write("shift/reduce conflict in state %d resolved as reduce.\n" % st) + _vf.write(" ! shift/reduce conflict for %s resolved as reduce.\n" % a) + n_srconflict += 1 + elif (slevel == rlevel) and (rprec == 'nonassoc'): + action[st,a] = None + else: + # Hmmm. Guess we'll keep the shift + if not slevel and not rlevel: + _vfc.write("shift/reduce conflict in state %d resolved as shift.\n" % st) + _vf.write(" ! shift/reduce conflict for %s resolved as shift.\n" % a) + n_srconflict +=1 + elif r < 0: + # Reduce/reduce conflict. In this case, we favor the rule + # that was defined first in the grammar file + oldp = Productions[-r] + pp = Productions[p.number] + if oldp.line > pp.line: + action[st,a] = -p.number + actionp[st,a] = p + # print "Reduce/reduce conflict in state %d" % st + n_rrconflict += 1 + _vfc.write("reduce/reduce conflict in state %d resolved using rule %d (%s).\n" % (st, actionp[st,a].number, actionp[st,a])) + _vf.write(" ! reduce/reduce conflict for %s resolved using rule %d (%s).\n" % (a,actionp[st,a].number, actionp[st,a])) + else: + print "Unknown conflict in state %d" % st + else: + action[st,a] = -p.number + actionp[st,a] = p + else: + i = p.lr_index + a = p.prod[i+1] # Get symbol right after the "." + if Terminals.has_key(a): + g = lr0_goto(I,a) + j = _lr0_cidhash.get(id(g),-1) + if j >= 0: + # We are in a shift state + actlist.append((a,p,"shift and go to state %d" % j)) + r = action.get((st,a),None) + if r is not None: + # Whoa have a shift/reduce or shift/shift conflict + if r > 0: + if r != j: + print "Shift/shift conflict in state %d" % st + elif r < 0: + # Do a precedence check. + # - if precedence of reduce rule is higher, we reduce. + # - if precedence of reduce is same and left assoc, we reduce. + # - otherwise we shift + rprec,rlevel = Productions[actionp[st,a].number].prec + sprec,slevel = Precedence.get(a,('right',0)) + if (slevel > rlevel) or ((slevel == rlevel) and (rprec != 'left')): + # We decide to shift here... highest precedence to shift + action[st,a] = j + actionp[st,a] = p + if not slevel and not rlevel: + n_srconflict += 1 + _vfc.write("shift/reduce conflict in state %d resolved as shift.\n" % st) + _vf.write(" ! shift/reduce conflict for %s resolved as shift.\n" % a) + elif (slevel == rlevel) and (rprec == 'nonassoc'): + action[st,a] = None + else: + # Hmmm. Guess we'll keep the reduce + if not slevel and not rlevel: + n_srconflict +=1 + _vfc.write("shift/reduce conflict in state %d resolved as reduce.\n" % st) + _vf.write(" ! shift/reduce conflict for %s resolved as reduce.\n" % a) + + else: + print "Unknown conflict in state %d" % st + else: + action[st,a] = j + actionp[st,a] = p + + except StandardError,e: + raise YaccError, "Hosed in slr_parse_table", e + + # Print the actions associated with each terminal + if yaccdebug: + for a,p,m in actlist: + if action.has_key((st,a)): + if p is actionp[st,a]: + _vf.write(" %-15s %s\n" % (a,m)) + _vf.write("\n") + for a,p,m in actlist: + if action.has_key((st,a)): + if p is not actionp[st,a]: + _vf.write(" ! %-15s [ %s ]\n" % (a,m)) + + # Construct the goto table for this state + if yaccdebug: + _vf.write("\n") + nkeys = { } + for ii in I: + for s in ii.usyms: + if Nonterminals.has_key(s): + nkeys[s] = None + for n in nkeys.keys(): + g = lr0_goto(I,n) + j = _lr0_cidhash.get(id(g),-1) + if j >= 0: + goto[st,n] = j + if yaccdebug: + _vf.write(" %-15s shift and go to state %d\n" % (n,j)) + + st += 1 + + if n_srconflict == 1: + print "yacc: %d shift/reduce conflict" % n_srconflict + if n_srconflict > 1: + print "yacc: %d shift/reduce conflicts" % n_srconflict + if n_rrconflict == 1: + print "yacc: %d reduce/reduce conflict" % n_rrconflict + if n_rrconflict > 1: + print "yacc: %d reduce/reduce conflicts" % n_rrconflict + + +# ----------------------------------------------------------------------------- +# ==== LALR(1) Parsing ==== +# **** UNFINISHED! 6/16/01 +# ----------------------------------------------------------------------------- + + +# Compute the lr1_closure of a set I. I is a list of tuples (p,a) where +# p is a LR0 item and a is a terminal + +_lr1_add_count = 0 + +def lr1_closure(I): + global _lr1_add_count + + _lr1_add_count += 1 + + J = I[:] + + # Loop over items (p,a) in I. + ji = 0 + while ji < len(J): + p,a = J[ji] + # p = [ A -> alpha . B beta] + + # For each production B -> gamma + for B in p.lr1_after: + f = tuple(p.lr1_beta + (a,)) + + # For each terminal b in first(Beta a) + for b in first(f): + # Check if (B -> . gamma, b) is in J + # Only way this can happen is if the add count mismatches + pn = B.lr_next + if pn.lr_added.get(b,0) == _lr1_add_count: continue + pn.lr_added[b] = _lr1_add_count + J.append((pn,b)) + ji += 1 + + return J + +def lalr_parse_table(): + + # Compute some lr1 information about all of the productions + for p in LRitems: + try: + after = p.prod[p.lr_index + 1] + p.lr1_after = Prodnames[after] + p.lr1_beta = p.prod[p.lr_index + 2:] + except LookupError: + p.lr1_after = [ ] + p.lr1_beta = [ ] + p.lr_added = { } + + # Compute the LR(0) items + C = lr0_items() + CK = [] + for I in C: + CK.append(lr0_kernel(I)) + + print CK + +# ----------------------------------------------------------------------------- +# ==== LR Utility functions ==== +# ----------------------------------------------------------------------------- + +# ----------------------------------------------------------------------------- +# _lr_write_tables() +# +# This function writes the LR parsing tables to a file +# ----------------------------------------------------------------------------- + +def lr_write_tables(modulename=tab_module): + filename = modulename + ".py" + try: + f = open(filename,"w") + + f.write(""" +# %s +# This file is automatically generated. Do not edit. + +_lr_method = %s + +_lr_signature = %s +""" % (filename, repr(_lr_method), repr(Signature.digest()))) + + # Change smaller to 0 to go back to original tables + smaller = 1 + + # Factor out names to try and make smaller + if smaller: + items = { } + + for k,v in _lr_action.items(): + i = items.get(k[1]) + if not i: + i = ([],[]) + items[k[1]] = i + i[0].append(k[0]) + i[1].append(v) + + f.write("\n_lr_action_items = {") + for k,v in items.items(): + f.write("%r:([" % k) + for i in v[0]: + f.write("%r," % i) + f.write("],[") + for i in v[1]: + f.write("%r," % i) + + f.write("]),") + f.write("}\n") + + f.write(""" +_lr_action = { } +for _k, _v in _lr_action_items.items(): + for _x,_y in zip(_v[0],_v[1]): + _lr_action[(_x,_k)] = _y +del _lr_action_items +""") + + else: + f.write("\n_lr_action = { "); + for k,v in _lr_action.items(): + f.write("(%r,%r):%r," % (k[0],k[1],v)) + f.write("}\n"); + + if smaller: + # Factor out names to try and make smaller + items = { } + + for k,v in _lr_goto.items(): + i = items.get(k[1]) + if not i: + i = ([],[]) + items[k[1]] = i + i[0].append(k[0]) + i[1].append(v) + + f.write("\n_lr_goto_items = {") + for k,v in items.items(): + f.write("%r:([" % k) + for i in v[0]: + f.write("%r," % i) + f.write("],[") + for i in v[1]: + f.write("%r," % i) + + f.write("]),") + f.write("}\n") + + f.write(""" +_lr_goto = { } +for _k, _v in _lr_goto_items.items(): + for _x,_y in zip(_v[0],_v[1]): + _lr_goto[(_x,_k)] = _y +del _lr_goto_items +""") + else: + f.write("\n_lr_goto = { "); + for k,v in _lr_goto.items(): + f.write("(%r,%r):%r," % (k[0],k[1],v)) + f.write("}\n"); + + # Write production table + f.write("_lr_productions = [\n") + for p in Productions: + if p: + if (p.func): + f.write(" (%r,%d,%r,%r,%d),\n" % (p.name, p.len, p.func.__name__,p.file,p.line)) + else: + f.write(" (%r,%d,None,None,None),\n" % (p.name, p.len)) + else: + f.write(" None,\n") + f.write("]\n") + f.close() + + except IOError,e: + print "Unable to create '%s'" % filename + print e + return + +def lr_read_tables(module=tab_module,optimize=0): + global _lr_action, _lr_goto, _lr_productions, _lr_method + try: + exec "import %s as parsetab" % module + + if (optimize) or (Signature.digest() == parsetab._lr_signature): + _lr_action = parsetab._lr_action + _lr_goto = parsetab._lr_goto + _lr_productions = parsetab._lr_productions + _lr_method = parsetab._lr_method + return 1 + else: + return 0 + + except (ImportError,AttributeError): + return 0 + +# ----------------------------------------------------------------------------- +# yacc(module) +# +# Build the parser module +# ----------------------------------------------------------------------------- + +def yacc(method=default_lr, debug=yaccdebug, module=None, tabmodule=tab_module, start=None, check_recursion=1, optimize=0): + global yaccdebug + yaccdebug = debug + + initialize_vars() + files = { } + error = 0 + + # Add starting symbol to signature + if start: + Signature.update(start) + + # Try to figure out what module we are working with + if module: + # User supplied a module object. + if not isinstance(module, types.ModuleType): + raise ValueError,"Expected a module" + + ldict = module.__dict__ + + else: + # No module given. We might be able to get information from the caller. + # Throw an exception and unwind the traceback to get the globals + + try: + raise RuntimeError + except RuntimeError: + e,b,t = sys.exc_info() + f = t.tb_frame + f = f.f_back # Walk out to our calling function + ldict = f.f_globals # Grab its globals dictionary + + # If running in optimized mode. We're going to + + if (optimize and lr_read_tables(tabmodule,1)): + # Read parse table + del Productions[:] + for p in _lr_productions: + if not p: + Productions.append(None) + else: + m = MiniProduction() + m.name = p[0] + m.len = p[1] + m.file = p[3] + m.line = p[4] + if p[2]: + m.func = ldict[p[2]] + Productions.append(m) + + else: + # Get the tokens map + tokens = ldict.get("tokens",None) + + if not tokens: + raise YaccError,"module does not define a list 'tokens'" + if not (isinstance(tokens,types.ListType) or isinstance(tokens,types.TupleType)): + raise YaccError,"tokens must be a list or tuple." + + # Check to see if a requires dictionary is defined. + requires = ldict.get("require",None) + if requires: + if not (isinstance(requires,types.DictType)): + raise YaccError,"require must be a dictionary." + + for r,v in requires.items(): + try: + if not (isinstance(v,types.ListType)): + raise TypeError + v1 = [x.split(".") for x in v] + Requires[r] = v1 + except StandardError: + print "Invalid specification for rule '%s' in require. Expected a list of strings" % r + + + # Build the dictionary of terminals. We a record a 0 in the + # dictionary to track whether or not a terminal is actually + # used in the grammar + + if 'error' in tokens: + print "yacc: Illegal token 'error'. Is a reserved word." + raise YaccError,"Illegal token name" + + for n in tokens: + if Terminals.has_key(n): + print "yacc: Warning. Token '%s' multiply defined." % n + Terminals[n] = [ ] + + Terminals['error'] = [ ] + + # Get the precedence map (if any) + prec = ldict.get("precedence",None) + if prec: + if not (isinstance(prec,types.ListType) or isinstance(prec,types.TupleType)): + raise YaccError,"precedence must be a list or tuple." + add_precedence(prec) + Signature.update(repr(prec)) + + for n in tokens: + if not Precedence.has_key(n): + Precedence[n] = ('right',0) # Default, right associative, 0 precedence + + # Look for error handler + ef = ldict.get('p_error',None) + if ef: + if not isinstance(ef,types.FunctionType): + raise YaccError,"'p_error' defined, but is not a function." + eline = ef.func_code.co_firstlineno + efile = ef.func_code.co_filename + files[efile] = None + + if (ef.func_code.co_argcount != 1): + raise YaccError,"%s:%d: p_error() requires 1 argument." % (efile,eline) + global Errorfunc + Errorfunc = ef + else: + print "yacc: Warning. no p_error() function is defined." + + # Get the list of built-in functions with p_ prefix + symbols = [ldict[f] for f in ldict.keys() + if (isinstance(ldict[f],types.FunctionType) and ldict[f].__name__[:2] == 'p_' + and ldict[f].__name__ != 'p_error')] + + # Check for non-empty symbols + if len(symbols) == 0: + raise YaccError,"no rules of the form p_rulename are defined." + + # Sort the symbols by line number + symbols.sort(lambda x,y: cmp(x.func_code.co_firstlineno,y.func_code.co_firstlineno)) + + # Add all of the symbols to the grammar + for f in symbols: + if (add_function(f)) < 0: + error += 1 + else: + files[f.func_code.co_filename] = None + + # Make a signature of the docstrings + for f in symbols: + if f.__doc__: + Signature.update(f.__doc__) + + lr_init_vars() + + if error: + raise YaccError,"Unable to construct parser." + + if not lr_read_tables(tabmodule): + + # Validate files + for filename in files.keys(): + if not validate_file(filename): + error = 1 + + # Validate dictionary + validate_dict(ldict) + + if start and not Prodnames.has_key(start): + raise YaccError,"Bad starting symbol '%s'" % start + + augment_grammar(start) + error = verify_productions(cycle_check=check_recursion) + otherfunc = [ldict[f] for f in ldict.keys() + if (isinstance(ldict[f],types.FunctionType) and ldict[f].__name__[:2] != 'p_')] + + if error: + raise YaccError,"Unable to construct parser." + + build_lritems() + compute_first1() + compute_follow(start) + + if method == 'SLR': + slr_parse_table() + elif method == 'LALR1': + lalr_parse_table() + return + else: + raise YaccError, "Unknown parsing method '%s'" % method + + lr_write_tables(tabmodule) + + if yaccdebug: + try: + f = open(debug_file,"w") + f.write(_vfc.getvalue()) + f.write("\n\n") + f.write(_vf.getvalue()) + f.close() + except IOError,e: + print "yacc: can't create '%s'" % debug_file,e + + # Made it here. Create a parser object and set up its internal state. + # Set global parse() method to bound method of parser object. + + p = Parser("xyzzy") + p.productions = Productions + p.errorfunc = Errorfunc + p.action = _lr_action + p.goto = _lr_goto + p.method = _lr_method + p.require = Requires + + global parse + parse = p.parse + + # Clean up all of the globals we created + if (not optimize): + yacc_cleanup() + return p + +# yacc_cleanup function. Delete all of the global variables +# used during table construction + +def yacc_cleanup(): + global _lr_action, _lr_goto, _lr_method, _lr_goto_cache + del _lr_action, _lr_goto, _lr_method, _lr_goto_cache + + global Productions, Prodnames, Prodmap, Terminals + global Nonterminals, First, Follow, Precedence, LRitems + global Errorfunc, Signature, Requires + + del Productions, Prodnames, Prodmap, Terminals + del Nonterminals, First, Follow, Precedence, LRitems + del Errorfunc, Signature, Requires + + global _vf, _vfc + del _vf, _vfc + + +# Stub that raises an error if parsing is attempted without first calling yacc() +def parse(*args,**kwargs): + raise YaccError, "yacc: No parser built with yacc()" + diff --git a/kern/linux/events.cc b/kern/linux/events.cc deleted file mode 100644 index 9f50eef04..000000000 --- a/kern/linux/events.cc +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "arch/arguments.hh" -#include "base/trace.hh" -#include "cpu/exec_context.hh" -#include "kern/linux/events.hh" -#include "kern/linux/printk.hh" -#include "kern/system_events.hh" -#include "sim/system.hh" - - -namespace Linux { - -void -DebugPrintkEvent::process(ExecContext *xc) -{ - if (DTRACE(DebugPrintf)) { - if (!raw) { - StringWrap name(xc->getSystemPtr()->name() + ".dprintk"); - DPRINTFN(""); - } - - AlphaArguments args(xc); - Printk(args); - SkipFuncEvent::process(xc); - } -} - -} // namespace linux diff --git a/kern/linux/linux.hh b/kern/linux/linux.hh deleted file mode 100644 index 0dbccf546..000000000 --- a/kern/linux/linux.hh +++ /dev/null @@ -1,341 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __LINUX_HH__ -#define __LINUX_HH__ -#include "config/full_system.hh" - -#if FULL_SYSTEM - -class Linux {}; - -#else //!FULL_SYSTEM - -#include <dirent.h> -#include <errno.h> -#include <fcntl.h> // for host open() flags -#include <string.h> // for memset() -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> - -#include "sim/syscall_emul.hh" - -/// -/// This class encapsulates the types, structures, constants, -/// functions, and syscall-number mappings specific to the Alpha Linux -/// syscall interface. -/// -class Linux { - - public: - - //@{ - /// Basic Linux types. - typedef uint64_t size_t; - typedef uint64_t off_t; - typedef int64_t time_t; - typedef uint32_t uid_t; - typedef uint32_t gid_t; - //@} - -#if BSD_HOST - typedef struct stat hst_stat; - typedef struct stat hst_stat64; -#else - typedef struct stat hst_stat ; - typedef struct stat64 hst_stat64; -#endif - - - //@{ - /// open(2) flag values. - static const int TGT_O_RDONLY = 00000000; //!< O_RDONLY - static const int TGT_O_WRONLY = 00000001; //!< O_WRONLY - static const int TGT_O_RDWR = 00000002; //!< O_RDWR - static const int TGT_O_NONBLOCK = 00000004; //!< O_NONBLOCK - static const int TGT_O_APPEND = 00000010; //!< O_APPEND - static const int TGT_O_CREAT = 00001000; //!< O_CREAT - static const int TGT_O_TRUNC = 00002000; //!< O_TRUNC - static const int TGT_O_EXCL = 00004000; //!< O_EXCL - static const int TGT_O_NOCTTY = 00010000; //!< O_NOCTTY - static const int TGT_O_SYNC = 00040000; //!< O_SYNC - static const int TGT_O_DRD = 00100000; //!< O_DRD - static const int TGT_O_DIRECTIO = 00200000; //!< O_DIRECTIO - static const int TGT_O_CACHE = 00400000; //!< O_CACHE - static const int TGT_O_DSYNC = 02000000; //!< O_DSYNC - static const int TGT_O_RSYNC = 04000000; //!< O_RSYNC - //@} - - /// This table maps the target open() flags to the corresponding - /// host open() flags. - static OpenFlagTransTable openFlagTable[]; - - /// Number of entries in openFlagTable[]. - static const int NUM_OPEN_FLAGS; - - /// Stat buffer. Note that we can't call it 'stat' since that - /// gets #defined to something else on some systems. - struct tgt_stat { - uint32_t st_dev; //!< device - uint32_t st_ino; //!< inode - uint32_t st_mode; //!< mode - uint32_t st_nlink; //!< link count - uint32_t st_uid; //!< owner's user ID - uint32_t st_gid; //!< owner's group ID - uint32_t st_rdev; //!< device number - int32_t _pad1; //!< for alignment - int64_t st_size; //!< file size in bytes - uint64_t st_atimeX; //!< time of last access - uint64_t st_mtimeX; //!< time of last modification - uint64_t st_ctimeX; //!< time of last status change - uint32_t st_blksize; //!< optimal I/O block size - int32_t st_blocks; //!< number of blocks allocated - uint32_t st_flags; //!< flags - uint32_t st_gen; //!< unknown - }; - - // same for stat64 - struct tgt_stat64 { - uint64_t st_dev; - uint64_t st_ino; - uint64_t st_rdev; - int64_t st_size; - uint64_t st_blocks; - - uint32_t st_mode; - uint32_t st_uid; - uint32_t st_gid; - uint32_t st_blksize; - uint32_t st_nlink; - uint32_t __pad0; - - uint64_t tgt_st_atime; - uint64_t st_atime_nsec; - uint64_t tgt_st_mtime; - uint64_t st_mtime_nsec; - uint64_t tgt_st_ctime; - uint64_t st_ctime_nsec; - int64_t ___unused[3]; - }; - - /// Length of strings in struct utsname (plus 1 for null char). - static const int _SYS_NMLN = 65; - - /// Interface struct for uname(). - struct utsname { - char sysname[_SYS_NMLN]; //!< System name. - char nodename[_SYS_NMLN]; //!< Node name. - char release[_SYS_NMLN]; //!< OS release. - char version[_SYS_NMLN]; //!< OS version. - char machine[_SYS_NMLN]; //!< Machine type. - }; - - - //@{ - /// ioctl() command codes. - static const unsigned TIOCGETP = 0x40067408; - static const unsigned TIOCSETP = 0x80067409; - static const unsigned TIOCSETN = 0x8006740a; - static const unsigned TIOCSETC = 0x80067411; - static const unsigned TIOCGETC = 0x40067412; - static const unsigned FIONREAD = 0x4004667f; - static const unsigned TIOCISATTY = 0x2000745e; - static const unsigned TIOCGETS = 0x402c7413; - static const unsigned TIOCGETA = 0x40127417; - //@} - - /// Resource enumeration for getrlimit(). - enum rlimit_resources { - TGT_RLIMIT_CPU = 0, - TGT_RLIMIT_FSIZE = 1, - TGT_RLIMIT_DATA = 2, - TGT_RLIMIT_STACK = 3, - TGT_RLIMIT_CORE = 4, - TGT_RLIMIT_RSS = 5, - TGT_RLIMIT_NOFILE = 6, - TGT_RLIMIT_AS = 7, - TGT_RLIMIT_VMEM = 7, - TGT_RLIMIT_NPROC = 8, - TGT_RLIMIT_MEMLOCK = 9, - TGT_RLIMIT_LOCKS = 10 - }; - - /// Limit struct for getrlimit/setrlimit. - struct rlimit { - uint64_t rlim_cur; //!< soft limit - uint64_t rlim_max; //!< hard limit - }; - - - /// For mmap(). - static const unsigned TGT_MAP_ANONYMOUS = 0x10; - - /// For gettimeofday(). - struct timeval { - int64_t tv_sec; //!< seconds - int64_t tv_usec; //!< microseconds - }; - - // For writev/readv - struct tgt_iovec { - uint64_t iov_base; // void * - uint64_t iov_len; - }; - - //@{ - /// For getrusage(). - static const int TGT_RUSAGE_SELF = 0; - static const int TGT_RUSAGE_CHILDREN = -1; - static const int TGT_RUSAGE_BOTH = -2; - //@} - - /// For getrusage(). - struct rusage { - struct timeval ru_utime; //!< user time used - struct timeval ru_stime; //!< system time used - int64_t ru_maxrss; //!< max rss - int64_t ru_ixrss; //!< integral shared memory size - int64_t ru_idrss; //!< integral unshared data " - int64_t ru_isrss; //!< integral unshared stack " - int64_t ru_minflt; //!< page reclaims - total vmfaults - int64_t ru_majflt; //!< page faults - int64_t ru_nswap; //!< swaps - int64_t ru_inblock; //!< block input operations - int64_t ru_oublock; //!< block output operations - int64_t ru_msgsnd; //!< messages sent - int64_t ru_msgrcv; //!< messages received - int64_t ru_nsignals; //!< signals received - int64_t ru_nvcsw; //!< voluntary context switches - int64_t ru_nivcsw; //!< involuntary " - }; - - /// Helper function to convert a host stat buffer to a target stat - /// buffer. Also copies the target buffer out to the simulated - /// memory space. Used by stat(), fstat(), and lstat(). -#if !BSD_HOST - static void - copyOutStatBuf(FunctionalMemory *mem, Addr addr, hst_stat *host) - { - TypedBufferArg<Linux::tgt_stat> tgt(addr); - - tgt->st_dev = htog(host->st_dev); - tgt->st_ino = htog(host->st_ino); - tgt->st_mode = htog(host->st_mode); - tgt->st_nlink = htog(host->st_nlink); - tgt->st_uid = htog(host->st_uid); - tgt->st_gid = htog(host->st_gid); - tgt->st_rdev = htog(host->st_rdev); - tgt->st_size = htog(host->st_size); - tgt->st_atimeX = htog(host->st_atime); - tgt->st_mtimeX = htog(host->st_mtime); - tgt->st_ctimeX = htog(host->st_ctime); - tgt->st_blksize = htog(host->st_blksize); - tgt->st_blocks = htog(host->st_blocks); - - tgt.copyOut(mem); - } -#else - // Third version for bsd systems which no longer have any support for - // the old stat() call and stat() is actually a stat64() - static void - copyOutStatBuf(FunctionalMemory *mem, Addr addr, hst_stat64 *host) - { - TypedBufferArg<Linux::tgt_stat> tgt(addr); - - tgt->st_dev = htog(host->st_dev); - tgt->st_ino = htog(host->st_ino); - tgt->st_mode = htog(host->st_mode); - tgt->st_nlink = htog(host->st_nlink); - tgt->st_uid = htog(host->st_uid); - tgt->st_gid = htog(host->st_gid); - tgt->st_rdev = htog(host->st_rdev); - tgt->st_size = htog(host->st_size); - tgt->st_atimeX = htog(host->st_atime); - tgt->st_mtimeX = htog(host->st_mtime); - tgt->st_ctimeX = htog(host->st_ctime); - tgt->st_blksize = htog(host->st_blksize); - tgt->st_blocks = htog(host->st_blocks); - - tgt.copyOut(mem); - } -#endif - - - // Same for stat64 - static void - copyOutStat64Buf(FunctionalMemory *mem, int fd, Addr addr, hst_stat64 *host) - { - TypedBufferArg<Linux::tgt_stat64> tgt(addr); - - // fd == 1 checks are because libc does some checks - // that the stdout is interactive vs. a file - // this makes it work on non-linux systems - if (fd == 1) - tgt->st_dev = htog((uint64_t)0xA); - else - tgt->st_dev = htog((uint64_t)host->st_dev); - // XXX What about STAT64_HAS_BROKEN_ST_INO ??? - tgt->st_ino = htog((uint64_t)host->st_ino); - if (fd == 1) - tgt->st_rdev = htog((uint64_t)0x880d); - else - tgt->st_rdev = htog((uint64_t)host->st_rdev); - tgt->st_size = htog((int64_t)host->st_size); - tgt->st_blocks = htog((uint64_t)host->st_blocks); - - if (fd == 1) - tgt->st_mode = htog((uint32_t)0x2190); - else - tgt->st_mode = htog((uint32_t)host->st_mode); - tgt->st_uid = htog((uint32_t)host->st_uid); - tgt->st_gid = htog((uint32_t)host->st_gid); - tgt->st_blksize = htog((uint32_t)host->st_blksize); - tgt->st_nlink = htog((uint32_t)host->st_nlink); - tgt->tgt_st_atime = htog((uint64_t)host->st_atime); - tgt->tgt_st_mtime = htog((uint64_t)host->st_mtime); - tgt->tgt_st_ctime = htog((uint64_t)host->st_ctime); -#if defined(STAT_HAVE_NSEC) - tgt->st_atime_nsec = htog(host->st_atime_nsec); - tgt->st_mtime_nsec = htog(host->st_mtime_nsec); - tgt->st_ctime_nsec = htog(host->st_ctime_nsec); -#else - tgt->st_atime_nsec = 0; - tgt->st_mtime_nsec = 0; - tgt->st_ctime_nsec = 0; -#endif - - tgt.copyOut(mem); - } - -}; // class Linux - - -#endif // FULL_SYSTEM - -#endif // __LINUX_HH__ diff --git a/kern/linux/printk.cc b/kern/linux/printk.cc deleted file mode 100644 index f5313759b..000000000 --- a/kern/linux/printk.cc +++ /dev/null @@ -1,261 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <sys/types.h> -#include <algorithm> - -#include "base/trace.hh" -#include "arch/arguments.hh" - -using namespace std; - - -void -Printk(AlphaArguments args) -{ - char *p = (char *)args++; - - ios::fmtflags saved_flags = DebugOut().flags(); - char old_fill = DebugOut().fill(); - int old_precision = DebugOut().precision(); - - while (*p) { - switch (*p) { - case '%': { - bool more = true; - bool islong = false; - bool leftjustify = false; - bool format = false; - bool zero = false; - int width = 0; - while (more && *++p) { - switch (*p) { - case 'l': - case 'L': - islong = true; - break; - case '-': - leftjustify = true; - break; - case '#': - format = true; - break; - case '0': - if (width) - width *= 10; - else - zero = true; - break; - default: - if (*p >= '1' && *p <= '9') - width = 10 * width + *p - '0'; - else - more = false; - break; - } - } - - bool hexnum = false; - bool octal = false; - bool sign = false; - switch (*p) { - case 'X': - case 'x': - hexnum = true; - break; - case 'O': - case 'o': - octal = true; - break; - case 'D': - case 'd': - sign = true; - break; - case 'P': - format = true; - case 'p': - hexnum = true; - break; - } - - switch (*p) { - case 'D': - case 'd': - case 'U': - case 'u': - case 'X': - case 'x': - case 'O': - case 'o': - case 'P': - case 'p': { - if (hexnum) - DebugOut() << hex; - - if (octal) - DebugOut() << oct; - - if (format) { - if (!zero) - DebugOut().setf(ios::showbase); - else { - if (hexnum) { - DebugOut() << "0x"; - width -= 2; - } else if (octal) { - DebugOut() << "0"; - width -= 1; - } - } - } - - if (zero) - DebugOut().fill('0'); - - if (width > 0) - DebugOut().width(width); - - if (leftjustify && !zero) - DebugOut().setf(ios::left); - - if (sign) { - if (islong) - DebugOut() << (int64_t)args; - else - DebugOut() << (int32_t)args; - } else { - if (islong) - DebugOut() << (uint64_t)args; - else - DebugOut() << (uint32_t)args; - } - - if (zero) - DebugOut().fill(' '); - - if (width > 0) - DebugOut().width(0); - - DebugOut() << dec; - - ++args; - } - break; - - case 's': { - char *s = (char *)args; - if (!s) - s = "<NULL>"; - - if (width > 0) - DebugOut().width(width); - if (leftjustify) - DebugOut().setf(ios::left); - - DebugOut() << s; - ++args; - } - break; - case 'C': - case 'c': { - uint64_t mask = (*p == 'C') ? 0xffL : 0x7fL; - uint64_t num; - int width; - - if (islong) { - num = (uint64_t)args; - width = sizeof(uint64_t); - } else { - num = (uint32_t)args; - width = sizeof(uint32_t); - } - - while (width-- > 0) { - char c = (char)(num & mask); - if (c) - DebugOut() << c; - num >>= 8; - } - - ++args; - } - break; - case 'b': { - uint64_t n = (uint64_t)args++; - char *s = (char *)args++; - DebugOut() << s << ": " << n; - } - break; - case 'n': - case 'N': { - args += 2; -#if 0 - uint64_t n = (uint64_t)args++; - struct reg_values *rv = (struct reg_values *)args++; -#endif - } - break; - case 'r': - case 'R': { - args += 2; -#if 0 - uint64_t n = (uint64_t)args++; - struct reg_desc *rd = (struct reg_desc *)args++; -#endif - } - break; - case '%': - DebugOut() << '%'; - break; - } - ++p; - } - break; - case '\n': - DebugOut() << endl; - ++p; - break; - case '\r': - ++p; - if (*p != '\n') - DebugOut() << endl; - break; - - default: { - size_t len = strcspn(p, "%\n\r\0"); - DebugOut().write(p, len); - p += len; - } - } - } - - DebugOut().flags(saved_flags); - DebugOut().fill(old_fill); - DebugOut().precision(old_precision); -} - diff --git a/kern/linux/printk.hh b/kern/linux/printk.hh deleted file mode 100644 index 45eab6b88..000000000 --- a/kern/linux/printk.hh +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __PRINTK_HH__ -#define __PRINTK_HH__ - -class AlphaArguments; - -void Printk(AlphaArguments args); - -#endif // __PRINTK_HH__ diff --git a/kern/system_events.cc b/kern/system_events.cc deleted file mode 100644 index 221eb228d..000000000 --- a/kern/system_events.cc +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "encumbered/cpu/full/cpu.hh" -#include "kern/kernel_stats.hh" - -using namespace TheISA; - -void -SkipFuncEvent::process(ExecContext *xc) -{ - Addr newpc = xc->readIntReg(ReturnAddressReg); - - DPRINTF(PCEvent, "skipping %s: pc=%x, newpc=%x\n", description, - xc->readPC(), newpc); - - xc->setPC(newpc); - xc->setNextPC(xc->readPC() + sizeof(TheISA::MachInst)); - - BranchPred *bp = xc->getCpuPtr()->getBranchPred(); - if (bp != NULL) { - bp->popRAS(xc->getThreadNum()); - } -} - - -FnEvent::FnEvent(PCEventQueue *q, const std::string &desc, Addr addr, - Stats::MainBin *bin) - : PCEvent(q, desc, addr), _name(desc), mybin(bin) -{ -} - -void -FnEvent::process(ExecContext *xc) -{ - if (xc->misspeculating()) - return; - - xc->getSystemPtr()->kernelBinning->call(xc, mybin); -} - -void -IdleStartEvent::process(ExecContext *xc) -{ - if (xc->getKernelStats()) - xc->getKernelStats()->setIdleProcess( - xc->readMiscReg(AlphaISA::IPR_PALtemp23), xc); - remove(); -} - -void -InterruptStartEvent::process(ExecContext *xc) -{ - if (xc->getKernelStats()) - xc->getKernelStats()->mode(Kernel::interrupt, xc); -} - -void -InterruptEndEvent::process(ExecContext *xc) -{ - // We go back to kernel, if we are user, inside the rti - // pal code we will get switched to user because of the ICM write - if (xc->getKernelStats()) - xc->getKernelStats()->mode(Kernel::kernel, xc); -} diff --git a/kern/tru64/dump_mbuf.hh b/kern/tru64/dump_mbuf.hh deleted file mode 100644 index 0ff5da3d7..000000000 --- a/kern/tru64/dump_mbuf.hh +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __DUMP_MBUF_HH__ -#define __DUMP_MBUF_HH__ - -class AlphaArguments; - -namespace tru64 { - void DumpMbuf(AlphaArguments args); -} - -#endif // __DUMP_MBUF_HH__ diff --git a/kern/tru64/printf.cc b/kern/tru64/printf.cc deleted file mode 100644 index 77ac17c3a..000000000 --- a/kern/tru64/printf.cc +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <sys/types.h> -#include <algorithm> - -#include "base/cprintf.hh" -#include "base/trace.hh" -#include "sim/host.hh" -#include "arch/arguments.hh" -#include "arch/vtophys.hh" - -using namespace std; - -namespace tru64 { - -void -Printf(AlphaArguments args) -{ - char *p = (char *)args++; - - ios::fmtflags saved_flags = DebugOut().flags(); - char old_fill = DebugOut().fill(); - int old_precision = DebugOut().precision(); - - while (*p) { - switch (*p) { - case '%': { - bool more = true; - bool islong = false; - bool leftjustify = false; - bool format = false; - bool zero = false; - int width = 0; - while (more && *++p) { - switch (*p) { - case 'l': - case 'L': - islong = true; - break; - case '-': - leftjustify = true; - break; - case '#': - format = true; - break; - case '0': - if (width) - width *= 10; - else - zero = true; - break; - default: - if (*p >= '1' && *p <= '9') - width = 10 * width + *p - '0'; - else - more = false; - break; - } - } - - bool hexnum = false; - bool octal = false; - bool sign = false; - switch (*p) { - case 'X': - case 'x': - hexnum = true; - break; - case 'O': - case 'o': - octal = true; - break; - case 'D': - case 'd': - sign = true; - break; - case 'P': - format = true; - case 'p': - hexnum = true; - break; - } - - switch (*p) { - case 'D': - case 'd': - case 'U': - case 'u': - case 'X': - case 'x': - case 'O': - case 'o': - case 'P': - case 'p': { - if (hexnum) - DebugOut() << hex; - - if (octal) - DebugOut() << oct; - - if (format) { - if (!zero) - DebugOut().setf(ios::showbase); - else { - if (hexnum) { - DebugOut() << "0x"; - width -= 2; - } else if (octal) { - DebugOut() << "0"; - width -= 1; - } - } - } - - if (zero) - DebugOut().fill('0'); - - if (width > 0) - DebugOut().width(width); - - if (leftjustify && !zero) - DebugOut().setf(ios::left); - - if (sign) { - if (islong) - DebugOut() << (int64_t)args; - else - DebugOut() << (int32_t)args; - } else { - if (islong) - DebugOut() << (uint64_t)args; - else - DebugOut() << (uint32_t)args; - } - - if (zero) - DebugOut().fill(' '); - - if (width > 0) - DebugOut().width(0); - - DebugOut() << dec; - - ++args; - } - break; - - case 's': { - char *s = (char *)args; - if (!s) - s = "<NULL>"; - - if (width > 0) - DebugOut().width(width); - if (leftjustify) - DebugOut().setf(ios::left); - - DebugOut() << s; - ++args; - } - break; - case 'C': - case 'c': { - uint64_t mask = (*p == 'C') ? 0xffL : 0x7fL; - uint64_t num; - int width; - - if (islong) { - num = (uint64_t)args; - width = sizeof(uint64_t); - } else { - num = (uint32_t)args; - width = sizeof(uint32_t); - } - - while (width-- > 0) { - char c = (char)(num & mask); - if (c) - DebugOut() << c; - num >>= 8; - } - - ++args; - } - break; - case 'b': { - uint64_t n = (uint64_t)args++; - char *s = (char *)args++; - DebugOut() << s << ": " << n; - } - break; - case 'n': - case 'N': { - args += 2; -#if 0 - uint64_t n = (uint64_t)args++; - struct reg_values *rv = (struct reg_values *)args++; -#endif - } - break; - case 'r': - case 'R': { - args += 2; -#if 0 - uint64_t n = (uint64_t)args++; - struct reg_desc *rd = (struct reg_desc *)args++; -#endif - } - break; - case '%': - DebugOut() << '%'; - break; - } - ++p; - } - break; - case '\n': - DebugOut() << endl; - ++p; - break; - case '\r': - ++p; - if (*p != '\n') - DebugOut() << endl; - break; - - default: { - size_t len = strcspn(p, "%\n\r\0"); - DebugOut().write(p, len); - p += len; - } - } - } - - DebugOut().flags(saved_flags); - DebugOut().fill(old_fill); - DebugOut().precision(old_precision); -} - -} // namespace Tru64 diff --git a/kern/tru64/printf.hh b/kern/tru64/printf.hh deleted file mode 100644 index a48b4482c..000000000 --- a/kern/tru64/printf.hh +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __PRINTF_HH__ -#define __PRINTF_HH__ - -class AlphaArguments; - -namespace tru64 { - void Printf(AlphaArguments args); -} - -#endif // __PRINTF_HH__ diff --git a/kern/tru64/tru64.hh b/kern/tru64/tru64.hh deleted file mode 100644 index b8adab8a8..000000000 --- a/kern/tru64/tru64.hh +++ /dev/null @@ -1,1324 +0,0 @@ -/* - * Copyright (c) 2001-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __TRU64_HH__ -#define __TRU64_HH__ -#include "config/full_system.hh" - -#if FULL_SYSTEM - -class Tru64 {}; - -#else //!FULL_SYSTEM - -#include <sys/types.h> -#include <sys/stat.h> -#if defined(__OpenBSD__) || defined(__APPLE__) || defined(__FreeBSD__) -#include <sys/param.h> -#include <sys/mount.h> -#else -#include <sys/statfs.h> -#endif - -#include <dirent.h> -#include <errno.h> -#include <fcntl.h> -#include <string.h> // for memset() -#include <unistd.h> - -#include "cpu/base.hh" -#include "sim/root.hh" -#include "sim/syscall_emul.hh" - -using namespace std; - -typedef struct stat global_stat; -typedef struct statfs global_statfs; -typedef struct dirent global_dirent; - -/// -/// This class encapsulates the types, structures, constants, -/// functions, and syscall-number mappings specific to the Alpha Tru64 -/// syscall interface. -/// -class Tru64 { - - public: - - //@{ - /// Basic Tru64 types. - typedef uint64_t size_t; - typedef uint64_t off_t; - typedef uint16_t nlink_t; - typedef int32_t dev_t; - typedef uint32_t uid_t; - typedef uint32_t gid_t; - typedef uint32_t time_t; - typedef uint32_t mode_t; - typedef uint32_t ino_t; - typedef struct { int val[2]; } quad; - typedef quad fsid_t; - //@} - - //@{ - /// open(2) flag values. - static const int TGT_O_RDONLY = 00000000; - static const int TGT_O_WRONLY = 00000001; - static const int TGT_O_RDWR = 00000002; - static const int TGT_O_NONBLOCK = 00000004; - static const int TGT_O_APPEND = 00000010; - static const int TGT_O_CREAT = 00001000; - static const int TGT_O_TRUNC = 00002000; - static const int TGT_O_EXCL = 00004000; - static const int TGT_O_NOCTTY = 00010000; - static const int TGT_O_SYNC = 00040000; - static const int TGT_O_DRD = 00100000; - static const int TGT_O_DIRECTIO = 00200000; - static const int TGT_O_CACHE = 00400000; - static const int TGT_O_DSYNC = 02000000; - static const int TGT_O_RSYNC = 04000000; - //@} - - /// This table maps the target open() flags to the corresponding - /// host open() flags. - static OpenFlagTransTable openFlagTable[]; - - /// Number of entries in openFlagTable[]. - static const int NUM_OPEN_FLAGS; - - /// Stat buffer. Note that Tru64 v5.0+ use a new "F64" stat - /// structure, and a new set of syscall numbers for stat calls. - /// On some hosts (notably Linux) define st_atime, st_mtime, and - /// st_ctime as macros, so we append an X to get around this. - struct F64_stat { - dev_t st_dev; //!< st_dev - int32_t st_retired1; //!< st_retired1 - mode_t st_mode; //!< st_mode - nlink_t st_nlink; //!< st_nlink - uint16_t st_nlink_reserved; //!< st_nlink_reserved - uid_t st_uid; //!< st_uid - gid_t st_gid; //!< st_gid - dev_t st_rdev; //!< st_rdev - dev_t st_ldev; //!< st_ldev - off_t st_size; //!< st_size - time_t st_retired2; //!< st_retired2 - int32_t st_uatime; //!< st_uatime - time_t st_retired3; //!< st_retired3 - int32_t st_umtime; //!< st_umtime - time_t st_retired4; //!< st_retired4 - int32_t st_uctime; //!< st_uctime - int32_t st_retired5; //!< st_retired5 - int32_t st_retired6; //!< st_retired6 - uint32_t st_flags; //!< st_flags - uint32_t st_gen; //!< st_gen - uint64_t st_spare[4]; //!< st_spare[4] - ino_t st_ino; //!< st_ino - int32_t st_ino_reserved; //!< st_ino_reserved - time_t st_atimeX; //!< st_atime - int32_t st_atime_reserved; //!< st_atime_reserved - time_t st_mtimeX; //!< st_mtime - int32_t st_mtime_reserved; //!< st_mtime_reserved - time_t st_ctimeX; //!< st_ctime - int32_t st_ctime_reserved; //!< st_ctime_reserved - uint64_t st_blksize; //!< st_blksize - uint64_t st_blocks; //!< st_blocks - }; - - - /// Old Tru64 v4.x stat struct. - /// Tru64 maintains backwards compatibility with v4.x by - /// implementing another set of stat functions using the old - /// structure definition and binding them to the old syscall - /// numbers. - - struct pre_F64_stat { - dev_t st_dev; - ino_t st_ino; - mode_t st_mode; - nlink_t st_nlink; - uid_t st_uid __attribute__ ((aligned(sizeof(uid_t)))); - gid_t st_gid; - dev_t st_rdev; - off_t st_size __attribute__ ((aligned(sizeof(off_t)))); - time_t st_atimeX; - int32_t st_uatime; - time_t st_mtimeX; - int32_t st_umtime; - time_t st_ctimeX; - int32_t st_uctime; - uint32_t st_blksize; - int32_t st_blocks; - uint32_t st_flags; - uint32_t st_gen; - }; - - /// For statfs(). - struct F64_statfs { - int16_t f_type; - int16_t f_flags; - int32_t f_retired1; - int32_t f_retired2; - int32_t f_retired3; - int32_t f_retired4; - int32_t f_retired5; - int32_t f_retired6; - int32_t f_retired7; - fsid_t f_fsid; - int32_t f_spare[9]; - char f_retired8[90]; - char f_retired9[90]; - uint64_t dummy[10]; // was union mount_info mount_info; - uint64_t f_flags2; - int64_t f_spare2[14]; - int64_t f_fsize; - int64_t f_bsize; - int64_t f_blocks; - int64_t f_bfree; - int64_t f_bavail; - int64_t f_files; - int64_t f_ffree; - char f_mntonname[1024]; - char f_mntfromname[1024]; - }; - - /// For old Tru64 v4.x statfs() - struct pre_F64_statfs { - int16_t f_type; - int16_t f_flags; - int32_t f_fsize; - int32_t f_bsize; - int32_t f_blocks; - int32_t f_bfree; - int32_t f_bavail; - int32_t f_files; - int32_t f_ffree; - fsid_t f_fsid; - int32_t f_spare[9]; - char f_mntonname[90]; - char f_mntfromname[90]; - uint64_t dummy[10]; // was union mount_info mount_info; - }; - - /// For getdirentries(). - struct dirent - { - ino_t d_ino; //!< file number of entry - uint16_t d_reclen; //!< length of this record - uint16_t d_namlen; //!< length of string in d_name - char d_name[256]; //!< dummy name length - }; - - - /// Length of strings in struct utsname (plus 1 for null char). - static const int _SYS_NMLN = 32; - - /// Interface struct for uname(). - struct utsname { - char sysname[_SYS_NMLN]; //!< System name. - char nodename[_SYS_NMLN]; //!< Node name. - char release[_SYS_NMLN]; //!< OS release. - char version[_SYS_NMLN]; //!< OS version. - char machine[_SYS_NMLN]; //!< Machine type. - }; - - //@{ - /// ioctl() command codes. - static const unsigned TIOCGETP = 0x40067408; - static const unsigned TIOCSETP = 0x80067409; - static const unsigned TIOCSETN = 0x8006740a; - static const unsigned TIOCSETC = 0x80067411; - static const unsigned TIOCGETC = 0x40067412; - static const unsigned FIONREAD = 0x4004667f; - static const unsigned TIOCISATTY = 0x2000745e; - // TIOCGETS not defined in tru64, so I made up a number - static const unsigned TIOCGETS = 0x40000000; - static const unsigned TIOCGETA = 0x402c7413; - //@} - - /// Resource enumeration for getrlimit(). - enum rlimit_resources { - TGT_RLIMIT_CPU = 0, - TGT_RLIMIT_FSIZE = 1, - TGT_RLIMIT_DATA = 2, - TGT_RLIMIT_STACK = 3, - TGT_RLIMIT_CORE = 4, - TGT_RLIMIT_RSS = 5, - TGT_RLIMIT_NOFILE = 6, - TGT_RLIMIT_AS = 7, - TGT_RLIMIT_VMEM = 7 - }; - - /// Limit struct for getrlimit/setrlimit. - struct rlimit { - uint64_t rlim_cur; //!< soft limit - uint64_t rlim_max; //!< hard limit - }; - - - /// For mmap(). - static const unsigned TGT_MAP_ANONYMOUS = 0x10; - - - //@{ - /// For getsysinfo(). - static const unsigned GSI_PLATFORM_NAME = 103; //!< platform name as string - static const unsigned GSI_CPU_INFO = 59; //!< CPU information - static const unsigned GSI_PROC_TYPE = 60; //!< get proc_type - static const unsigned GSI_MAX_CPU = 30; //!< max # cpu's on this machine - static const unsigned GSI_CPUS_IN_BOX = 55; //!< number of CPUs in system - static const unsigned GSI_PHYSMEM = 19; //!< Physical memory in KB - static const unsigned GSI_CLK_TCK = 42; //!< clock freq in Hz - //@} - - /// For getsysinfo() GSI_CPU_INFO option. - struct cpu_info { - uint32_t current_cpu; //!< current_cpu - uint32_t cpus_in_box; //!< cpus_in_box - uint32_t cpu_type; //!< cpu_type - uint32_t ncpus; //!< ncpus - uint64_t cpus_present; //!< cpus_present - uint64_t cpus_running; //!< cpus_running - uint64_t cpu_binding; //!< cpu_binding - uint64_t cpu_ex_binding; //!< cpu_ex_binding - uint32_t mhz; //!< mhz - uint32_t unused[3]; //!< future expansion - }; - - //@{ - /// For setsysinfo(). - static const unsigned SSI_IEEE_FP_CONTROL = 14; //!< ieee_set_fp_control() - //@} - - /// For gettimeofday. - struct timeval { - uint32_t tv_sec; //!< seconds - uint32_t tv_usec; //!< microseconds - }; - - //@{ - /// For getrusage(). - static const int TGT_RUSAGE_THREAD = 1; - static const int TGT_RUSAGE_SELF = 0; - static const int TGT_RUSAGE_CHILDREN = -1; - //@} - - /// For getrusage(). - struct rusage { - struct timeval ru_utime; //!< user time used - struct timeval ru_stime; //!< system time used - uint64_t ru_maxrss; //!< ru_maxrss - uint64_t ru_ixrss; //!< integral shared memory size - uint64_t ru_idrss; //!< integral unshared data " - uint64_t ru_isrss; //!< integral unshared stack " - uint64_t ru_minflt; //!< page reclaims - total vmfaults - uint64_t ru_majflt; //!< page faults - uint64_t ru_nswap; //!< swaps - uint64_t ru_inblock; //!< block input operations - uint64_t ru_oublock; //!< block output operations - uint64_t ru_msgsnd; //!< messages sent - uint64_t ru_msgrcv; //!< messages received - uint64_t ru_nsignals; //!< signals received - uint64_t ru_nvcsw; //!< voluntary context switches - uint64_t ru_nivcsw; //!< involuntary " - }; - - /// For sigreturn(). - struct sigcontext { - int64_t sc_onstack; //!< sigstack state to restore - int64_t sc_mask; //!< signal mask to restore - int64_t sc_pc; //!< pc at time of signal - int64_t sc_ps; //!< psl to retore - int64_t sc_regs[32]; //!< processor regs 0 to 31 - int64_t sc_ownedfp; //!< fp has been used - int64_t sc_fpregs[32]; //!< fp regs 0 to 31 - uint64_t sc_fpcr; //!< floating point control reg - uint64_t sc_fp_control; //!< software fpcr - int64_t sc_reserved1; //!< reserved for kernel - uint32_t sc_kreserved1; //!< reserved for kernel - uint32_t sc_kreserved2; //!< reserved for kernel - size_t sc_ssize; //!< stack size - caddr_t sc_sbase; //!< stack start - uint64_t sc_traparg_a0; //!< a0 argument to trap on exc - uint64_t sc_traparg_a1; //!< a1 argument to trap on exc - uint64_t sc_traparg_a2; //!< a2 argument to trap on exc - uint64_t sc_fp_trap_pc; //!< imprecise pc - uint64_t sc_fp_trigger_sum; //!< Exception summary at trigg - uint64_t sc_fp_trigger_inst; //!< Instruction at trigger pc - }; - - - /// For table(). - static const int TBL_SYSINFO = 12; - - /// For table(). - struct tbl_sysinfo { - uint64_t si_user; //!< User time - uint64_t si_nice; //!< Nice time - uint64_t si_sys; //!< System time - uint64_t si_idle; //!< Idle time - uint64_t si_hz; //!< hz - uint64_t si_phz; //!< phz - uint64_t si_boottime; //!< Boot time in seconds - uint64_t wait; //!< Wait time - uint32_t si_max_procs; //!< rpb->rpb_numprocs - uint32_t pad; //!< padding - }; - - - /// For stack_create. - struct vm_stack { - // was void * - Addr address; //!< address hint - size_t rsize; //!< red zone size - size_t ysize; //!< yellow zone size - size_t gsize; //!< green zone size - size_t swap; //!< amount of swap to reserve - size_t incr; //!< growth increment - uint64_t align; //!< address alignment - uint64_t flags; //!< MAP_FIXED etc. - // was struct memalloc_attr * - Addr attr; //!< allocation policy - uint64_t reserved; //!< reserved - }; - - /// Return values for nxm calls. - enum { - KERN_NOT_RECEIVER = 7, - KERN_NOT_IN_SET = 12 - }; - - /// For nxm_task_init. - static const int NXM_TASK_INIT_VP = 2; //!< initial thread is VP - - /// Task attribute structure. - struct nxm_task_attr { - int64_t nxm_callback; //!< nxm_callback - unsigned int nxm_version; //!< nxm_version - unsigned short nxm_uniq_offset; //!< nxm_uniq_offset - unsigned short flags; //!< flags - int nxm_quantum; //!< nxm_quantum - int pad1; //!< pad1 - int64_t pad2; //!< pad2 - }; - - /// Signal set. - typedef uint64_t sigset_t; - - /// Thread state shared between user & kernel. - struct ushared_state { - sigset_t sigmask; //!< thread signal mask - sigset_t sig; //!< thread pending mask - // struct nxm_pth_state * - Addr pth_id; //!< out-of-line state - int flags; //!< shared flags -#define US_SIGSTACK 0x1 // thread called sigaltstack -#define US_ONSTACK 0x2 // thread is running on altstack -#define US_PROFILE 0x4 // thread called profil -#define US_SYSCALL 0x8 // thread in syscall -#define US_TRAP 0x10 // thread has trapped -#define US_YELLOW 0x20 // thread has mellowed yellow -#define US_YZONE 0x40 // thread has zoned out -#define US_FP_OWNED 0x80 // thread used floating point - - int cancel_state; //!< thread's cancelation state -#define US_CANCEL 0x1 // cancel pending -#define US_NOCANCEL 0X2 // synch cancel disabled -#define US_SYS_NOCANCEL 0x4 // syscall cancel disabled -#define US_ASYNC_NOCANCEL 0x8 // asynch cancel disabled -#define US_CANCEL_BITS (US_NOCANCEL|US_SYS_NOCANCEL|US_ASYNC_NOCANCEL) -#define US_CANCEL_MASK (US_CANCEL|US_NOCANCEL|US_SYS_NOCANCEL| \ - US_ASYNC_NOCANCEL) - - // These are semi-shared. They are always visible to - // the kernel but are never context-switched by the library. - - int nxm_ssig; //!< scheduler's synchronous signals - int reserved1; //!< reserved1 - int64_t nxm_active; //!< scheduler active - int64_t reserved2; //!< reserved2 - }; - - struct nxm_sched_state { - struct ushared_state nxm_u; //!< state own by user thread - unsigned int nxm_bits; //!< scheduler state / slot - int nxm_quantum; //!< quantum count-down value - int nxm_set_quantum; //!< quantum reset value - int nxm_sysevent; //!< syscall state - // struct nxm_upcall * - Addr nxm_uc_ret; //!< stack ptr of null thread - // void * - Addr nxm_tid; //!< scheduler's thread id - int64_t nxm_va; //!< page fault address - // struct nxm_pth_state * - Addr nxm_pthid; //!< id of null thread - uint64_t nxm_bound_pcs_count; //!< bound PCS thread count - int64_t pad[2]; //!< pad - }; - - /// nxm_shared. - struct nxm_shared { - int64_t nxm_callback; //!< address of upcall routine - unsigned int nxm_version; //!< version number - unsigned short nxm_uniq_offset; //!< correction factor for TEB - unsigned short pad1; //!< pad1 - int64_t space[2]; //!< future growth - struct nxm_sched_state nxm_ss[1]; //!< array of shared areas - }; - - /// nxm_slot_state_t. - enum nxm_slot_state_t { - NXM_SLOT_AVAIL, - NXM_SLOT_BOUND, - NXM_SLOT_UNBOUND, - NXM_SLOT_EMPTY - }; - - /// nxm_config_info - struct nxm_config_info { - int nxm_nslots_per_rad; //!< max number of VP slots per RAD - int nxm_nrads; //!< max number of RADs - // nxm_slot_state_t * - Addr nxm_slot_state; //!< per-VP slot state - // struct nxm_shared * - Addr nxm_rad[1]; //!< per-RAD shared areas - }; - - /// For nxm_thread_create. - enum nxm_thread_type { - NXM_TYPE_SCS = 0, - NXM_TYPE_VP = 1, - NXM_TYPE_MANAGER = 2 - }; - - /// Thread attributes. - struct nxm_thread_attr { - int version; //!< version - int type; //!< type - int cancel_flags; //!< cancel_flags - int priority; //!< priority - int policy; //!< policy - int signal_type; //!< signal_type - // void * - Addr pthid; //!< pthid - sigset_t sigmask; //!< sigmask - /// Initial register values. - struct { - uint64_t pc; //!< pc - uint64_t sp; //!< sp - uint64_t a0; //!< a0 - } registers; - uint64_t pad2[2]; //!< pad2 - }; - - /// Helper function to convert a host stat buffer to a target stat - /// buffer. Also copies the target buffer out to the simulated - /// memory space. Used by stat(), fstat(), and lstat(). - template <class T> - static void - copyOutStatBuf(FunctionalMemory *mem, Addr addr, global_stat *host) - { - TypedBufferArg<T> tgt(addr); - - tgt->st_dev = htog(host->st_dev); - tgt->st_ino = htog(host->st_ino); - tgt->st_mode = htog(host->st_mode); - tgt->st_nlink = htog(host->st_nlink); - tgt->st_uid = htog(host->st_uid); - tgt->st_gid = htog(host->st_gid); - tgt->st_rdev = htog(host->st_rdev); - tgt->st_size = htog(host->st_size); - tgt->st_atimeX = htog(host->st_atime); - tgt->st_mtimeX = htog(host->st_mtime); - tgt->st_ctimeX = htog(host->st_ctime); - tgt->st_blksize = htog(host->st_blksize); - tgt->st_blocks = htog(host->st_blocks); - - tgt.copyOut(mem); - } - - /// Helper function to convert a host statfs buffer to a target statfs - /// buffer. Also copies the target buffer out to the simulated - /// memory space. Used by statfs() and fstatfs(). - template <class T> - static void - copyOutStatfsBuf(FunctionalMemory *mem, Addr addr, global_statfs *host) - { - TypedBufferArg<T> tgt(addr); - -#if defined(__OpenBSD__) || defined(__APPLE__) || defined(__FreeBSD__) - tgt->f_type = 0; -#else - tgt->f_type = htog(host->f_type); -#endif - tgt->f_bsize = htog(host->f_bsize); - tgt->f_blocks = htog(host->f_blocks); - tgt->f_bfree = htog(host->f_bfree); - tgt->f_bavail = htog(host->f_bavail); - tgt->f_files = htog(host->f_files); - tgt->f_ffree = htog(host->f_ffree); - - // Is this as string normally? - memcpy(&tgt->f_fsid, &host->f_fsid, sizeof(host->f_fsid)); - - tgt.copyOut(mem); - } - - class F64 { - public: - static void copyOutStatBuf(FunctionalMemory *mem, Addr addr, - global_stat *host) - { - Tru64::copyOutStatBuf<Tru64::F64_stat>(mem, addr, host); - } - - static void copyOutStatfsBuf(FunctionalMemory *mem, Addr addr, - global_statfs *host) - { - Tru64::copyOutStatfsBuf<Tru64::F64_statfs>(mem, addr, host); - } - }; - - class PreF64 { - public: - static void copyOutStatBuf(FunctionalMemory *mem, Addr addr, - global_stat *host) - { - Tru64::copyOutStatBuf<Tru64::pre_F64_stat>(mem, addr, host); - } - - static void copyOutStatfsBuf(FunctionalMemory *mem, Addr addr, - global_statfs *host) - { - Tru64::copyOutStatfsBuf<Tru64::pre_F64_statfs>(mem, addr, host); - } - }; - - /// Helper function to convert a host stat buffer to an old pre-F64 - /// (4.x) target stat buffer. Also copies the target buffer out to - /// the simulated memory space. Used by pre_F64_stat(), - /// pre_F64_fstat(), and pre_F64_lstat(). - static void - copyOutPreF64StatBuf(FunctionalMemory *mem, Addr addr, struct stat *host) - { - TypedBufferArg<Tru64::pre_F64_stat> tgt(addr); - - tgt->st_dev = htog(host->st_dev); - tgt->st_ino = htog(host->st_ino); - tgt->st_mode = htog(host->st_mode); - tgt->st_nlink = htog(host->st_nlink); - tgt->st_uid = htog(host->st_uid); - tgt->st_gid = htog(host->st_gid); - tgt->st_rdev = htog(host->st_rdev); - tgt->st_size = htog(host->st_size); - tgt->st_atimeX = htog(host->st_atime); - tgt->st_mtimeX = htog(host->st_mtime); - tgt->st_ctimeX = htog(host->st_ctime); - tgt->st_blksize = htog(host->st_blksize); - tgt->st_blocks = htog(host->st_blocks); - - tgt.copyOut(mem); - } - - - /// The target system's hostname. - static const char *hostname; - - - /// Target getdirentries() handler. - static SyscallReturn - getdirentriesFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) - { -#ifdef __CYGWIN__ - panic("getdirent not implemented on cygwin!"); -#else - int fd = process->sim_fd(xc->getSyscallArg(0)); - Addr tgt_buf = xc->getSyscallArg(1); - int tgt_nbytes = xc->getSyscallArg(2); - Addr tgt_basep = xc->getSyscallArg(3); - - char * const host_buf = new char[tgt_nbytes]; - - // just pass basep through uninterpreted. - TypedBufferArg<int64_t> basep(tgt_basep); - basep.copyIn(xc->getMemPtr()); - long host_basep = (off_t)htog((int64_t)*basep); - int host_result = getdirentries(fd, host_buf, tgt_nbytes, &host_basep); - - // check for error - if (host_result < 0) { - delete [] host_buf; - return -errno; - } - - // no error: copy results back to target space - Addr tgt_buf_ptr = tgt_buf; - char *host_buf_ptr = host_buf; - char *host_buf_end = host_buf + host_result; - while (host_buf_ptr < host_buf_end) { - global_dirent *host_dp = (global_dirent *)host_buf_ptr; - int namelen = strlen(host_dp->d_name); - - // Actual size includes padded string rounded up for alignment. - // Subtract 256 for dummy char array in Tru64::dirent definition. - // Add 1 to namelen for terminating null char. - int tgt_bufsize = sizeof(Tru64::dirent) - 256 + roundUp(namelen+1, 8); - TypedBufferArg<Tru64::dirent> tgt_dp(tgt_buf_ptr, tgt_bufsize); - tgt_dp->d_ino = host_dp->d_ino; - tgt_dp->d_reclen = tgt_bufsize; - tgt_dp->d_namlen = namelen; - strcpy(tgt_dp->d_name, host_dp->d_name); - tgt_dp.copyOut(xc->getMemPtr()); - - tgt_buf_ptr += tgt_bufsize; - host_buf_ptr += host_dp->d_reclen; - } - - delete [] host_buf; - - *basep = htog((int64_t)host_basep); - basep.copyOut(xc->getMemPtr()); - - return tgt_buf_ptr - tgt_buf; -#endif - } - - /// Target sigreturn() handler. - static SyscallReturn - sigreturnFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) - { - using TheISA::RegFile; - TypedBufferArg<Tru64::sigcontext> sc(xc->getSyscallArg(0)); - - sc.copyIn(xc->getMemPtr()); - - // Restore state from sigcontext structure. - // Note that we'll advance PC <- NPC before the end of the cycle, - // so we need to restore the desired PC into NPC. - // The current regs->pc will get clobbered. - xc->setNextPC(htog(sc->sc_pc)); - - for (int i = 0; i < 31; ++i) { - xc->setIntReg(i, htog(sc->sc_regs[i])); - xc->setFloatRegInt(i, htog(sc->sc_fpregs[i])); - } - - xc->setMiscReg(TheISA::Fpcr_DepTag, htog(sc->sc_fpcr)); - - return 0; - } - - /// Target table() handler. - static SyscallReturn - tableFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) - { - int id = xc->getSyscallArg(0); // table ID - int index = xc->getSyscallArg(1); // index into table - // arg 2 is buffer pointer; type depends on table ID - int nel = xc->getSyscallArg(3); // number of elements - int lel = xc->getSyscallArg(4); // expected element size - - switch (id) { - case Tru64::TBL_SYSINFO: { - if (index != 0 || nel != 1 || lel != sizeof(Tru64::tbl_sysinfo)) - return -EINVAL; - TypedBufferArg<Tru64::tbl_sysinfo> elp(xc->getSyscallArg(2)); - - const int clk_hz = one_million; - elp->si_user = htog(curTick / (Clock::Frequency / clk_hz)); - elp->si_nice = htog(0); - elp->si_sys = htog(0); - elp->si_idle = htog(0); - elp->wait = htog(0); - elp->si_hz = htog(clk_hz); - elp->si_phz = htog(clk_hz); - elp->si_boottime = htog(seconds_since_epoch); // seconds since epoch? - elp->si_max_procs = htog(process->numCpus()); - elp.copyOut(xc->getMemPtr()); - return 0; - } - - default: - cerr << "table(): id " << id << " unknown." << endl; - return -EINVAL; - } - } - - // - // Mach syscalls -- identified by negated syscall numbers - // - - /// Create a stack region for a thread. - static SyscallReturn - stack_createFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) - { - TypedBufferArg<Tru64::vm_stack> argp(xc->getSyscallArg(0)); - - argp.copyIn(xc->getMemPtr()); - - // if the user chose an address, just let them have it. Otherwise - // pick one for them. - if (htog(argp->address) == 0) { - argp->address = htog(process->next_thread_stack_base); - int stack_size = (htog(argp->rsize) + htog(argp->ysize) + - htog(argp->gsize)); - process->next_thread_stack_base -= stack_size; - argp.copyOut(xc->getMemPtr()); - } - - return 0; - } - - /// NXM library version stamp. - static - const int NXM_LIB_VERSION = 301003; - - /// This call sets up the interface between the user and kernel - /// schedulers by creating a shared-memory region. The shared memory - /// region has several structs, some global, some per-RAD, some per-VP. - static SyscallReturn - nxm_task_initFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) - { - TypedBufferArg<Tru64::nxm_task_attr> attrp(xc->getSyscallArg(0)); - TypedBufferArg<Addr> configptr_ptr(xc->getSyscallArg(1)); - - attrp.copyIn(xc->getMemPtr()); - - if (gtoh(attrp->nxm_version) != NXM_LIB_VERSION) { - cerr << "nxm_task_init: thread library version mismatch! " - << "got " << attrp->nxm_version - << ", expected " << NXM_LIB_VERSION << endl; - abort(); - } - - if (gtoh(attrp->flags) != Tru64::NXM_TASK_INIT_VP) { - cerr << "nxm_task_init: bad flag value " << attrp->flags - << " (expected " << Tru64::NXM_TASK_INIT_VP << ")" << endl; - abort(); - } - - const Addr base_addr = 0x12000; // was 0x3f0000000LL; - Addr cur_addr = base_addr; // next addresses to use - // first comes the config_info struct - Addr config_addr = cur_addr; - cur_addr += sizeof(Tru64::nxm_config_info); - // next comes the per-cpu state vector - Addr slot_state_addr = cur_addr; - int slot_state_size = - process->numCpus() * sizeof(Tru64::nxm_slot_state_t); - cur_addr += slot_state_size; - // now the per-RAD state struct (we only support one RAD) - cur_addr = 0x14000; // bump up addr for alignment - Addr rad_state_addr = cur_addr; - int rad_state_size = - (sizeof(Tru64::nxm_shared) - + (process->numCpus()-1) * sizeof(Tru64::nxm_sched_state)); - cur_addr += rad_state_size; - - // now initialize a config_info struct and copy it out to user space - TypedBufferArg<Tru64::nxm_config_info> config(config_addr); - - config->nxm_nslots_per_rad = htog(process->numCpus()); - config->nxm_nrads = htog(1); // only one RAD in our system! - config->nxm_slot_state = htog(slot_state_addr); - config->nxm_rad[0] = htog(rad_state_addr); - - config.copyOut(xc->getMemPtr()); - - // initialize the slot_state array and copy it out - TypedBufferArg<Tru64::nxm_slot_state_t> slot_state(slot_state_addr, - slot_state_size); - for (int i = 0; i < process->numCpus(); ++i) { - // CPU 0 is bound to the calling process; all others are available - // XXX this code should have an endian conversion, but I don't think - // it works anyway - slot_state[i] = - (i == 0) ? Tru64::NXM_SLOT_BOUND : Tru64::NXM_SLOT_AVAIL; - } - - slot_state.copyOut(xc->getMemPtr()); - - // same for the per-RAD "shared" struct. Note that we need to - // allocate extra bytes for the per-VP array which is embedded at - // the end. - TypedBufferArg<Tru64::nxm_shared> rad_state(rad_state_addr, - rad_state_size); - - rad_state->nxm_callback = attrp->nxm_callback; - rad_state->nxm_version = attrp->nxm_version; - rad_state->nxm_uniq_offset = attrp->nxm_uniq_offset; - for (int i = 0; i < process->numCpus(); ++i) { - Tru64::nxm_sched_state *ssp = &rad_state->nxm_ss[i]; - ssp->nxm_u.sigmask = htog(0); - ssp->nxm_u.sig = htog(0); - ssp->nxm_u.flags = htog(0); - ssp->nxm_u.cancel_state = htog(0); - ssp->nxm_u.nxm_ssig = 0; - ssp->nxm_bits = htog(0); - ssp->nxm_quantum = attrp->nxm_quantum; - ssp->nxm_set_quantum = attrp->nxm_quantum; - ssp->nxm_sysevent = htog(0); - - if (i == 0) { - uint64_t uniq = xc->readMiscReg(TheISA::Uniq_DepTag); - ssp->nxm_u.pth_id = htog(uniq + gtoh(attrp->nxm_uniq_offset)); - ssp->nxm_u.nxm_active = htog(uniq | 1); - } - else { - ssp->nxm_u.pth_id = htog(0); - ssp->nxm_u.nxm_active = htog(0); - } - } - - rad_state.copyOut(xc->getMemPtr()); - - // - // copy pointer to shared config area out to user - // - *configptr_ptr = htog(config_addr); - configptr_ptr.copyOut(xc->getMemPtr()); - - // Register this as a valid address range with the process - process->nxm_start = base_addr; - process->nxm_end = cur_addr; - - return 0; - } - - /// Initialize execution context. - static void - init_exec_context(ExecContext *ec, - Tru64::nxm_thread_attr *attrp, uint64_t uniq_val) - { - ec->clearArchRegs(); - - ec->setIntReg(TheISA::ArgumentReg0, gtoh(attrp->registers.a0)); - ec->setIntReg(27/*t12*/, gtoh(attrp->registers.pc)); - ec->setIntReg(TheISA::StackPointerReg, gtoh(attrp->registers.sp)); - ec->setMiscReg(TheISA::Uniq_DepTag, uniq_val); - - ec->setPC(gtoh(attrp->registers.pc)); - ec->setNextPC(gtoh(attrp->registers.pc) + sizeof(TheISA::MachInst)); - - ec->activate(); - } - - /// Create thread. - static SyscallReturn - nxm_thread_createFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) - { - TypedBufferArg<Tru64::nxm_thread_attr> attrp(xc->getSyscallArg(0)); - TypedBufferArg<uint64_t> kidp(xc->getSyscallArg(1)); - int thread_index = xc->getSyscallArg(2); - - // get attribute args - attrp.copyIn(xc->getMemPtr()); - - if (gtoh(attrp->version) != NXM_LIB_VERSION) { - cerr << "nxm_thread_create: thread library version mismatch! " - << "got " << attrp->version - << ", expected " << NXM_LIB_VERSION << endl; - abort(); - } - - if (thread_index < 0 | thread_index > process->numCpus()) { - cerr << "nxm_thread_create: bad thread index " << thread_index - << endl; - abort(); - } - - // On a real machine, the per-RAD shared structure is in - // shared memory, so both the user and kernel can get at it. - // We don't have that luxury, so we just copy it in and then - // back out again. - int rad_state_size = - (sizeof(Tru64::nxm_shared) + - (process->numCpus()-1) * sizeof(Tru64::nxm_sched_state)); - - TypedBufferArg<Tru64::nxm_shared> rad_state(0x14000, - rad_state_size); - rad_state.copyIn(xc->getMemPtr()); - - uint64_t uniq_val = gtoh(attrp->pthid) - gtoh(rad_state->nxm_uniq_offset); - - if (gtoh(attrp->type) == Tru64::NXM_TYPE_MANAGER) { - // DEC pthreads seems to always create one of these (in - // addition to N application threads), but we don't use it, - // so don't bother creating it. - - // This is supposed to be a port number. Make something up. - *kidp = htog(99); - kidp.copyOut(xc->getMemPtr()); - - return 0; - } else if (gtoh(attrp->type) == Tru64::NXM_TYPE_VP) { - // A real "virtual processor" kernel thread. Need to fork - // this thread on another CPU. - Tru64::nxm_sched_state *ssp = &rad_state->nxm_ss[thread_index]; - - if (gtoh(ssp->nxm_u.nxm_active) != 0) - return (int) Tru64::KERN_NOT_RECEIVER; - - ssp->nxm_u.pth_id = attrp->pthid; - ssp->nxm_u.nxm_active = htog(uniq_val | 1); - - rad_state.copyOut(xc->getMemPtr()); - - Addr slot_state_addr = 0x12000 + sizeof(Tru64::nxm_config_info); - int slot_state_size = - process->numCpus() * sizeof(Tru64::nxm_slot_state_t); - - TypedBufferArg<Tru64::nxm_slot_state_t> - slot_state(slot_state_addr, - slot_state_size); - - slot_state.copyIn(xc->getMemPtr()); - - if (slot_state[thread_index] != Tru64::NXM_SLOT_AVAIL) { - cerr << "nxm_thread_createFunc: requested VP slot " - << thread_index << " not available!" << endl; - fatal(""); - } - - // XXX This should have an endian conversion but I think this code - // doesn't work anyway - slot_state[thread_index] = Tru64::NXM_SLOT_BOUND; - - slot_state.copyOut(xc->getMemPtr()); - - // Find a free simulator execution context. - for (int i = 0; i < process->numCpus(); ++i) { - ExecContext *xc = process->execContexts[i]; - - if (xc->status() == ExecContext::Suspended) { - // inactive context... grab it - init_exec_context(xc, attrp, uniq_val); - - // This is supposed to be a port number, but we'll try - // and get away with just sticking the thread index - // here. - *kidp = htog(thread_index); - kidp.copyOut(xc->getMemPtr()); - - return 0; - } - } - - // fell out of loop... no available inactive context - cerr << "nxm_thread_create: no idle contexts available." << endl; - abort(); - } else { - cerr << "nxm_thread_create: can't handle thread type " - << attrp->type << endl; - abort(); - } - - return 0; - } - - /// Thread idle call (like yield()). - static SyscallReturn - nxm_idleFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) - { - return 0; - } - - /// Block thread. - static SyscallReturn - nxm_thread_blockFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) - { - uint64_t tid = xc->getSyscallArg(0); - uint64_t secs = xc->getSyscallArg(1); - uint64_t flags = xc->getSyscallArg(2); - uint64_t action = xc->getSyscallArg(3); - uint64_t usecs = xc->getSyscallArg(4); - - cout << xc->getCpuPtr()->name() << ": nxm_thread_block " << tid << " " - << secs << " " << flags << " " << action << " " << usecs << endl; - - return 0; - } - - /// block. - static SyscallReturn - nxm_blockFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) - { - Addr uaddr = xc->getSyscallArg(0); - uint64_t val = xc->getSyscallArg(1); - uint64_t secs = xc->getSyscallArg(2); - uint64_t usecs = xc->getSyscallArg(3); - uint64_t flags = xc->getSyscallArg(4); - - BaseCPU *cpu = xc->getCpuPtr(); - - cout << cpu->name() << ": nxm_block " - << hex << uaddr << dec << " " << val - << " " << secs << " " << usecs - << " " << flags << endl; - - return 0; - } - - /// Unblock thread. - static SyscallReturn - nxm_unblockFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) - { - Addr uaddr = xc->getSyscallArg(0); - - cout << xc->getCpuPtr()->name() << ": nxm_unblock " - << hex << uaddr << dec << endl; - - return 0; - } - - /// Switch thread priority. - static SyscallReturn - swtch_priFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) - { - // Attempts to switch to another runnable thread (if there is - // one). Returns false if there are no other threads to run - // (i.e., the thread can reasonably spin-wait) or true if there - // are other threads. - // - // Since we assume at most one "kernel" thread per CPU, it's - // always safe to return false here. - return 0; //false; - } - - - /// Activate exec context waiting on a channel. Just activate one - /// by default. - static int - activate_waiting_context(Addr uaddr, Process *process, - bool activate_all = false) - { - int num_activated = 0; - - list<Process::WaitRec>::iterator i = process->waitList.begin(); - list<Process::WaitRec>::iterator end = process->waitList.end(); - - while (i != end && (num_activated == 0 || activate_all)) { - if (i->waitChan == uaddr) { - // found waiting process: make it active - ExecContext *newCtx = i->waitingContext; - assert(newCtx->status() == ExecContext::Suspended); - newCtx->activate(); - - // get rid of this record - i = process->waitList.erase(i); - - ++num_activated; - } else { - ++i; - } - } - - return num_activated; - } - - /// M5 hacked-up lock acquire. - static void - m5_lock_mutex(Addr uaddr, Process *process, ExecContext *xc) - { - TypedBufferArg<uint64_t> lockp(uaddr); - - lockp.copyIn(xc->getMemPtr()); - - if (gtoh(*lockp) == 0) { - // lock is free: grab it - *lockp = htog(1); - lockp.copyOut(xc->getMemPtr()); - } else { - // lock is busy: disable until free - process->waitList.push_back(Process::WaitRec(uaddr, xc)); - xc->suspend(); - } - } - - /// M5 unlock call. - static void - m5_unlock_mutex(Addr uaddr, Process *process, ExecContext *xc) - { - TypedBufferArg<uint64_t> lockp(uaddr); - - lockp.copyIn(xc->getMemPtr()); - assert(*lockp != 0); - - // Check for a process waiting on the lock. - int num_waiting = activate_waiting_context(uaddr, process); - - // clear lock field if no waiting context is taking over the lock - if (num_waiting == 0) { - *lockp = 0; - lockp.copyOut(xc->getMemPtr()); - } - } - - /// Lock acquire syscall handler. - static SyscallReturn - m5_mutex_lockFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) - { - Addr uaddr = xc->getSyscallArg(0); - - m5_lock_mutex(uaddr, process, xc); - - // Return 0 since we will always return to the user with the lock - // acquired. We will just keep the context inactive until that is - // true. - return 0; - } - - /// Try lock (non-blocking). - static SyscallReturn - m5_mutex_trylockFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) - { - Addr uaddr = xc->getSyscallArg(0); - TypedBufferArg<uint64_t> lockp(uaddr); - - lockp.copyIn(xc->getMemPtr()); - - if (gtoh(*lockp) == 0) { - // lock is free: grab it - *lockp = htog(1); - lockp.copyOut(xc->getMemPtr()); - return 0; - } else { - return 1; - } - } - - /// Unlock syscall handler. - static SyscallReturn - m5_mutex_unlockFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) - { - Addr uaddr = xc->getSyscallArg(0); - - m5_unlock_mutex(uaddr, process, xc); - - return 0; - } - - /// Signal ocndition. - static SyscallReturn - m5_cond_signalFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) - { - Addr cond_addr = xc->getSyscallArg(0); - - // Wake up one process waiting on the condition variable. - activate_waiting_context(cond_addr, process); - - return 0; - } - - /// Wake up all processes waiting on the condition variable. - static SyscallReturn - m5_cond_broadcastFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) - { - Addr cond_addr = xc->getSyscallArg(0); - - activate_waiting_context(cond_addr, process, true); - - return 0; - } - - /// Wait on a condition. - static SyscallReturn - m5_cond_waitFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) - { - Addr cond_addr = xc->getSyscallArg(0); - Addr lock_addr = xc->getSyscallArg(1); - TypedBufferArg<uint64_t> condp(cond_addr); - TypedBufferArg<uint64_t> lockp(lock_addr); - - // user is supposed to acquire lock before entering - lockp.copyIn(xc->getMemPtr()); - assert(gtoh(*lockp) != 0); - - m5_unlock_mutex(lock_addr, process, xc); - - process->waitList.push_back(Process::WaitRec(cond_addr, xc)); - xc->suspend(); - - return 0; - } - - /// Thread exit. - static SyscallReturn - m5_thread_exitFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) - { - assert(xc->status() == ExecContext::Active); - xc->deallocate(); - - return 0; - } - - /// Indirect syscall invocation (call #0). - static SyscallReturn - indirectSyscallFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) - { - int new_callnum = xc->getSyscallArg(0); - LiveProcess *lp = dynamic_cast<LiveProcess*>(process); - assert(lp); - - for (int i = 0; i < 5; ++i) - xc->setSyscallArg(i, xc->getSyscallArg(i+1)); - - - SyscallDesc *new_desc = lp->getDesc(new_callnum); - if (desc == NULL) - fatal("Syscall %d out of range", callnum); - - new_desc->doSyscall(new_callnum, process, xc); - - return 0; - } - -}; // class Tru64 - - -#endif // FULL_SYSTEM - -#endif // __TRU64_HH__ diff --git a/kern/tru64/tru64_events.cc b/kern/tru64/tru64_events.cc deleted file mode 100644 index 8f2be6d9b..000000000 --- a/kern/tru64/tru64_events.cc +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "cpu/exec_context.hh" -#include "cpu/base.hh" -#include "kern/system_events.hh" -#include "kern/tru64/tru64_events.hh" -#include "kern/tru64/dump_mbuf.hh" -#include "kern/tru64/printf.hh" -#include "mem/functional/memory_control.hh" -#include "arch/arguments.hh" -#include "arch/isa_traits.hh" -#include "sim/system.hh" - -using namespace TheISA; - -//void SkipFuncEvent::process(ExecContext *xc); - -void -BadAddrEvent::process(ExecContext *xc) -{ - // The following gross hack is the equivalent function to the - // annotation for vmunix::badaddr in: - // simos/simulation/apps/tcl/osf/tlaser.tcl - - uint64_t a0 = xc->readIntReg(ArgumentReg0); - - if (!TheISA::IsK0Seg(a0) || - xc->getSystemPtr()->memctrl->badaddr( - TheISA::K0Seg2Phys(a0) & EV5::PAddrImplMask)) { - - DPRINTF(BADADDR, "badaddr arg=%#x bad\n", a0); - xc->setIntReg(ReturnValueReg, 0x1); - SkipFuncEvent::process(xc); - } - else - DPRINTF(BADADDR, "badaddr arg=%#x good\n", a0); -} - -void -PrintfEvent::process(ExecContext *xc) -{ - if (DTRACE(Printf)) { - DebugOut() << curTick << ": " << xc->getCpuPtr()->name() << ": "; - - AlphaArguments args(xc); - tru64::Printf(args); - } -} - -void -DebugPrintfEvent::process(ExecContext *xc) -{ - if (DTRACE(DebugPrintf)) { - if (!raw) - DebugOut() << curTick << ": " << xc->getCpuPtr()->name() << ": "; - - AlphaArguments args(xc); - tru64::Printf(args); - } -} - -void -DumpMbufEvent::process(ExecContext *xc) -{ - if (DTRACE(DebugPrintf)) { - AlphaArguments args(xc); - tru64::DumpMbuf(args); - } -} diff --git a/python/SConscript b/python/SConscript deleted file mode 100644 index a34d3f2d5..000000000 --- a/python/SConscript +++ /dev/null @@ -1,207 +0,0 @@ -# -*- mode:python -*- - -# Copyright (c) 2004-2005 The Regents of The University of Michigan -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer; -# redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution; -# neither the name of the copyright holders nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -import os, os.path, re, sys - -Import('env') - -import scons_helper - -def WriteEmbeddedPyFile(target, source, path, name, ext, filename): - if isinstance(source, str): - source = file(source, 'r') - - if isinstance(target, str): - target = file(target, 'w') - - print >>target, "AddModule(%s, %s, %s, %s, '''\\" % \ - (`path`, `name`, `ext`, `filename`) - - for line in source: - line = line - # escape existing backslashes - line = line.replace('\\', '\\\\') - # escape existing triple quotes - line = line.replace("'''", r"\'\'\'") - - print >>target, line, - - print >>target, "''')" - print >>target - -def WriteCFile(target, source, name): - if isinstance(source, str): - source = file(source, 'r') - - if isinstance(target, str): - target = file(target, 'w') - - print >>target, 'const char %s_string[] = {' % name - - count = 0 - from array import array - try: - while True: - foo = array('B') - foo.fromfile(source, 10000) - l = [ str(i) for i in foo.tolist() ] - count += len(l) - for i in xrange(0,9999,20): - print >>target, ','.join(l[i:i+20]) + ',' - except EOFError: - l = [ str(i) for i in foo.tolist() ] - count += len(l) - for i in xrange(0,len(l),20): - print >>target, ','.join(l[i:i+20]) + ',' - print >>target, ','.join(l[i:]) + ',' - - print >>target, '};' - print >>target, 'const int %s_length = %d;' % (name, count) - print >>target - -def splitpath(path): - dir,file = os.path.split(path) - path = [] - assert(file) - while dir: - dir,base = os.path.split(dir) - path.insert(0, base) - return path, file - -def MakeEmbeddedPyFile(target, source, env): - target = file(str(target[0]), 'w') - - tree = {} - for src in source: - src = str(src) - path,pyfile = splitpath(src) - node = tree - for dir in path: - if not node.has_key(dir): - node[dir] = { } - node = node[dir] - - name,ext = pyfile.split('.') - if name == '__init__': - node['.hasinit'] = True - node[pyfile] = (src,name,ext,src) - - done = False - while not done: - done = True - for name,entry in tree.items(): - if not isinstance(entry, dict): continue - if entry.has_key('.hasinit'): continue - - done = False - del tree[name] - for key,val in entry.iteritems(): - if tree.has_key(key): - raise NameError, \ - "dir already has %s can't add it again" % key - tree[key] = val - - files = [] - def populate(node, path = []): - names = node.keys() - names.sort() - for name in names: - if name == '.hasinit': - continue - - entry = node[name] - if isinstance(entry, dict): - if not entry.has_key('.hasinit'): - raise NameError, 'package directory missing __init__.py' - populate(entry, path + [ name ]) - else: - pyfile,name,ext,filename = entry - files.append((pyfile, path, name, ext, filename)) - populate(tree) - - for pyfile, path, name, ext, filename in files: - WriteEmbeddedPyFile(target, pyfile, path, name, ext, filename) - -def MakeDefinesPyFile(target, source, env): - f = file(str(target[0]), 'w') - print >>f, "import __main__" - print >>f, "__main__.m5_build_env = ", - print >>f, source[0] - f.close() - -CFileCounter = 0 -def MakePythonCFile(target, source, env): - global CFileCounter - target = file(str(target[0]), 'w') - - print >>target, '''\ -#include "base/embedfile.hh" - -namespace { -''' - for src in source: - src = str(src) - fname = os.path.basename(src) - name = 'embedded_file%d' % CFileCounter - CFileCounter += 1 - WriteCFile(target, src, name) - print >>target, '''\ -EmbedMap %(name)s("%(fname)s", - %(name)s_string, %(name)s_length); - -''' % locals() - print >>target, '''\ - -/* namespace */ } -''' - -# base list of .py files to embed -embedded_py_files = [ '../util/pbs/jobfile.py' ] -# add all .py files in python/m5 -objpath = os.path.join(env['SRCDIR'], 'python', 'm5') -for root, dirs, files in os.walk(objpath, topdown=True): - for i,dir in enumerate(dirs): - if dir == 'SCCS': - del dirs[i] - break - - assert(root.startswith(objpath)) - for f in files: - if f.endswith('.py'): - embedded_py_files.append(os.path.join(root, f)) - -embedfile_hh = os.path.join(env['SRCDIR'], 'base/embedfile.hh') - -optionDict = dict([(opt, env[opt]) for opt in env.ExportOptions]) -env.Command('defines.py', Value(optionDict), MakeDefinesPyFile) - -env.Command('embedded_py.py', embedded_py_files, MakeEmbeddedPyFile) -env.Depends('embedded_py.cc', embedfile_hh) -env.Command('embedded_py.cc', - ['string_importer.py', 'defines.py', 'embedded_py.py'], - MakePythonCFile) diff --git a/python/m5/objects/AlphaConsole.py b/python/m5/objects/AlphaConsole.py deleted file mode 100644 index f8f034682..000000000 --- a/python/m5/objects/AlphaConsole.py +++ /dev/null @@ -1,9 +0,0 @@ -from m5 import * -from Device import PioDevice - -class AlphaConsole(PioDevice): - type = 'AlphaConsole' - cpu = Param.BaseCPU(Parent.any, "Processor") - disk = Param.SimpleDisk("Simple Disk") - sim_console = Param.SimConsole(Parent.any, "The Simulator Console") - system = Param.System(Parent.any, "system object") diff --git a/python/m5/objects/BadDevice.py b/python/m5/objects/BadDevice.py deleted file mode 100644 index 3fba4637d..000000000 --- a/python/m5/objects/BadDevice.py +++ /dev/null @@ -1,6 +0,0 @@ -from m5 import * -from Device import PioDevice - -class BadDevice(PioDevice): - type = 'BadDevice' - devicename = Param.String("Name of device to error on") diff --git a/python/m5/objects/BaseCPU.py b/python/m5/objects/BaseCPU.py deleted file mode 100644 index a90203729..000000000 --- a/python/m5/objects/BaseCPU.py +++ /dev/null @@ -1,29 +0,0 @@ -from m5 import * -class BaseCPU(SimObject): - type = 'BaseCPU' - abstract = True - icache = Param.BaseMem(NULL, "L1 instruction cache object") - dcache = Param.BaseMem(NULL, "L1 data cache object") - - if build_env['FULL_SYSTEM']: - dtb = Param.AlphaDTB("Data TLB") - itb = Param.AlphaITB("Instruction TLB") - mem = Param.FunctionalMemory("memory") - system = Param.System(Parent.any, "system object") - cpu_id = Param.Int(-1, "CPU identifier") - else: - workload = VectorParam.Process("processes to run") - - max_insts_all_threads = Param.Counter(0, - "terminate when all threads have reached this inst count") - max_insts_any_thread = Param.Counter(0, - "terminate when any thread reaches this inst count") - max_loads_all_threads = Param.Counter(0, - "terminate when all threads have reached this load count") - max_loads_any_thread = Param.Counter(0, - "terminate when any thread reaches this load count") - - defer_registration = Param.Bool(False, - "defer registration with system (for sampling)") - - clock = Param.Clock(Parent.clock, "clock speed") diff --git a/python/m5/objects/Bus.py b/python/m5/objects/Bus.py deleted file mode 100644 index 26509d7d2..000000000 --- a/python/m5/objects/Bus.py +++ /dev/null @@ -1,7 +0,0 @@ -from m5 import * -from BaseHier import BaseHier - -class Bus(BaseHier): - type = 'Bus' - clock = Param.Clock("bus frequency") - width = Param.Int("bus width in bytes") diff --git a/python/m5/objects/Device.py b/python/m5/objects/Device.py deleted file mode 100644 index d7ca014a9..000000000 --- a/python/m5/objects/Device.py +++ /dev/null @@ -1,35 +0,0 @@ -from m5 import * -from FunctionalMemory import FunctionalMemory - -# This device exists only because there are some devices that I don't -# want to have a Platform parameter because it would cause a cycle in -# the C++ that cannot be easily solved. -# -# The real solution to this problem is to pass the ParamXXX structure -# to the constructor, but with the express condition that SimObject -# parameter values are not to be available at construction time. If -# some further configuration must be done, it must be done during the -# initialization phase at which point all SimObject pointers will be -# valid. -class FooPioDevice(FunctionalMemory): - type = 'PioDevice' - abstract = True - addr = Param.Addr("Device Address") - mmu = Param.MemoryController(Parent.any, "Memory Controller") - pio_bus = Param.Bus(NULL, "Bus to attach to for PIO") - pio_latency = Param.Tick(1, "Programmed IO latency in bus cycles") - -class FooDmaDevice(FooPioDevice): - type = 'DmaDevice' - abstract = True - dma_bus = Param.Bus(Self.pio_bus, "Bus to attach to for DMA") - -class PioDevice(FooPioDevice): - type = 'PioDevice' - abstract = True - platform = Param.Platform(Parent.any, "Platform") - -class DmaDevice(PioDevice): - type = 'DmaDevice' - abstract = True - dma_bus = Param.Bus(Self.pio_bus, "Bus to attach to for DMA") diff --git a/python/m5/objects/Ethernet.py b/python/m5/objects/Ethernet.py deleted file mode 100644 index 68b21b404..000000000 --- a/python/m5/objects/Ethernet.py +++ /dev/null @@ -1,119 +0,0 @@ -from m5 import * -from Device import DmaDevice -from Pci import PciDevice - -class EtherInt(SimObject): - type = 'EtherInt' - abstract = True - peer = Param.EtherInt(NULL, "peer interface") - -class EtherLink(SimObject): - type = 'EtherLink' - int1 = Param.EtherInt("interface 1") - int2 = Param.EtherInt("interface 2") - delay = Param.Latency('0us', "packet transmit delay") - delay_var = Param.Latency('0ns', "packet transmit delay variability") - speed = Param.NetworkBandwidth('1Gbps', "link speed") - dump = Param.EtherDump(NULL, "dump object") - -class EtherBus(SimObject): - type = 'EtherBus' - loopback = Param.Bool(True, "send packet back to the sending interface") - dump = Param.EtherDump(NULL, "dump object") - speed = Param.NetworkBandwidth('100Mbps', "bus speed in bits per second") - -class EtherTap(EtherInt): - type = 'EtherTap' - bufsz = Param.Int(10000, "tap buffer size") - dump = Param.EtherDump(NULL, "dump object") - port = Param.UInt16(3500, "tap port") - -class EtherDump(SimObject): - type = 'EtherDump' - file = Param.String("dump file") - maxlen = Param.Int(96, "max portion of packet data to dump") - -if build_env['ALPHA_TLASER']: - - class EtherDev(DmaDevice): - type = 'EtherDev' - hardware_address = Param.EthernetAddr(NextEthernetAddr, - "Ethernet Hardware Address") - - dma_data_free = Param.Bool(False, "DMA of Data is free") - dma_desc_free = Param.Bool(False, "DMA of Descriptors is free") - dma_read_delay = Param.Latency('0us', "fixed delay for dma reads") - dma_read_factor = Param.Latency('0us', "multiplier for dma reads") - dma_write_delay = Param.Latency('0us', "fixed delay for dma writes") - dma_write_factor = Param.Latency('0us', "multiplier for dma writes") - dma_no_allocate = Param.Bool(True, "Should we allocate cache on read") - - rx_filter = Param.Bool(True, "Enable Receive Filter") - rx_delay = Param.Latency('1us', "Receive Delay") - tx_delay = Param.Latency('1us', "Transmit Delay") - - intr_delay = Param.Latency('0us', "Interrupt Delay") - payload_bus = Param.Bus(NULL, "The IO Bus to attach to for payload") - physmem = Param.PhysicalMemory(Parent.any, "Physical Memory") - tlaser = Param.Turbolaser(Parent.any, "Turbolaser") - - class EtherDevInt(EtherInt): - type = 'EtherDevInt' - device = Param.EtherDev("Ethernet device of this interface") - -class EtherDevBase(PciDevice): - hardware_address = Param.EthernetAddr(NextEthernetAddr, - "Ethernet Hardware Address") - - clock = Param.Clock('0ns', "State machine processor frequency") - - physmem = Param.PhysicalMemory(Parent.any, "Physical Memory") - - hier = Param.HierParams(Parent.any, "Hierarchy global variables") - payload_bus = Param.Bus(NULL, "The IO Bus to attach to for payload") - dma_read_delay = Param.Latency('0us', "fixed delay for dma reads") - dma_read_factor = Param.Latency('0us', "multiplier for dma reads") - dma_write_delay = Param.Latency('0us', "fixed delay for dma writes") - dma_write_factor = Param.Latency('0us', "multiplier for dma writes") - dma_no_allocate = Param.Bool(True, "Should we allocate cache on read") - - rx_delay = Param.Latency('1us', "Receive Delay") - tx_delay = Param.Latency('1us', "Transmit Delay") - rx_fifo_size = Param.MemorySize('512kB', "max size of rx fifo") - tx_fifo_size = Param.MemorySize('512kB', "max size of tx fifo") - - rx_filter = Param.Bool(True, "Enable Receive Filter") - intr_delay = Param.Latency('10us', "Interrupt propagation delay") - rx_thread = Param.Bool(False, "dedicated kernel thread for transmit") - tx_thread = Param.Bool(False, "dedicated kernel threads for receive") - rss = Param.Bool(False, "Receive Side Scaling") - -class NSGigE(EtherDevBase): - type = 'NSGigE' - - dma_data_free = Param.Bool(False, "DMA of Data is free") - dma_desc_free = Param.Bool(False, "DMA of Descriptors is free") - - -class NSGigEInt(EtherInt): - type = 'NSGigEInt' - device = Param.NSGigE("Ethernet device of this interface") - -class Sinic(EtherDevBase): - type = 'Sinic' - - rx_max_copy = Param.MemorySize('1514B', "rx max copy") - tx_max_copy = Param.MemorySize('16kB', "tx max copy") - rx_max_intr = Param.UInt32(10, "max rx packets per interrupt") - rx_fifo_threshold = Param.MemorySize('384kB', "rx fifo high threshold") - rx_fifo_low_mark = Param.MemorySize('128kB', "rx fifo low threshold") - tx_fifo_high_mark = Param.MemorySize('384kB', "tx fifo high threshold") - tx_fifo_threshold = Param.MemorySize('128kB', "tx fifo low threshold") - virtual_count = Param.UInt32(1, "Virtualized SINIC") - zero_copy = Param.Bool(False, "Zero copy receive") - delay_copy = Param.Bool(False, "Delayed copy transmit") - virtual_addr = Param.Bool(False, "Virtual addressing") - -class SinicInt(EtherInt): - type = 'SinicInt' - device = Param.Sinic("Ethernet device of this interface") diff --git a/python/m5/objects/Ide.py b/python/m5/objects/Ide.py deleted file mode 100644 index 6855ec653..000000000 --- a/python/m5/objects/Ide.py +++ /dev/null @@ -1,15 +0,0 @@ -from m5 import * -from Pci import PciDevice - -class IdeID(Enum): vals = ['master', 'slave'] - -class IdeDisk(SimObject): - type = 'IdeDisk' - delay = Param.Latency('1us', "Fixed disk delay in microseconds") - driveID = Param.IdeID('master', "Drive ID") - image = Param.DiskImage("Disk image") - physmem = Param.PhysicalMemory(Parent.any, "Physical memory") - -class IdeController(PciDevice): - type = 'IdeController' - disks = VectorParam.IdeDisk("IDE disks attached to this controller") diff --git a/python/m5/objects/Pci.py b/python/m5/objects/Pci.py deleted file mode 100644 index 4124d0b92..000000000 --- a/python/m5/objects/Pci.py +++ /dev/null @@ -1,55 +0,0 @@ -from m5 import * -from Device import FooPioDevice, DmaDevice - -class PciConfigData(SimObject): - type = 'PciConfigData' - VendorID = Param.UInt16("Vendor ID") - DeviceID = Param.UInt16("Device ID") - Command = Param.UInt16(0, "Command") - Status = Param.UInt16(0, "Status") - Revision = Param.UInt8(0, "Device") - ProgIF = Param.UInt8(0, "Programming Interface") - SubClassCode = Param.UInt8(0, "Sub-Class Code") - ClassCode = Param.UInt8(0, "Class Code") - CacheLineSize = Param.UInt8(0, "System Cacheline Size") - LatencyTimer = Param.UInt8(0, "PCI Latency Timer") - HeaderType = Param.UInt8(0, "PCI Header Type") - BIST = Param.UInt8(0, "Built In Self Test") - - BAR0 = Param.UInt32(0x00, "Base Address Register 0") - BAR1 = Param.UInt32(0x00, "Base Address Register 1") - BAR2 = Param.UInt32(0x00, "Base Address Register 2") - BAR3 = Param.UInt32(0x00, "Base Address Register 3") - BAR4 = Param.UInt32(0x00, "Base Address Register 4") - BAR5 = Param.UInt32(0x00, "Base Address Register 5") - BAR0Size = Param.MemorySize32('0B', "Base Address Register 0 Size") - BAR1Size = Param.MemorySize32('0B', "Base Address Register 1 Size") - BAR2Size = Param.MemorySize32('0B', "Base Address Register 2 Size") - BAR3Size = Param.MemorySize32('0B', "Base Address Register 3 Size") - BAR4Size = Param.MemorySize32('0B', "Base Address Register 4 Size") - BAR5Size = Param.MemorySize32('0B', "Base Address Register 5 Size") - - CardbusCIS = Param.UInt32(0x00, "Cardbus Card Information Structure") - SubsystemID = Param.UInt16(0x00, "Subsystem ID") - SubsystemVendorID = Param.UInt16(0x00, "Subsystem Vendor ID") - ExpansionROM = Param.UInt32(0x00, "Expansion ROM Base Address") - InterruptLine = Param.UInt8(0x00, "Interrupt Line") - InterruptPin = Param.UInt8(0x00, "Interrupt Pin") - MaximumLatency = Param.UInt8(0x00, "Maximum Latency") - MinimumGrant = Param.UInt8(0x00, "Minimum Grant") - -class PciConfigAll(FooPioDevice): - type = 'PciConfigAll' - -class PciDevice(DmaDevice): - type = 'PciDevice' - abstract = True - addr = 0xffffffffL - pci_bus = Param.Int("PCI bus") - pci_dev = Param.Int("PCI device number") - pci_func = Param.Int("PCI function code") - configdata = Param.PciConfigData(Parent.any, "PCI Config data") - configspace = Param.PciConfigAll(Parent.any, "PCI Configspace") - -class PciFake(PciDevice): - type = 'PciFake' diff --git a/python/m5/objects/PhysicalMemory.py b/python/m5/objects/PhysicalMemory.py deleted file mode 100644 index f50937ee6..000000000 --- a/python/m5/objects/PhysicalMemory.py +++ /dev/null @@ -1,8 +0,0 @@ -from m5 import * -from FunctionalMemory import FunctionalMemory - -class PhysicalMemory(FunctionalMemory): - type = 'PhysicalMemory' - range = Param.AddrRange("Device Address") - file = Param.String('', "memory mapped file") - mmu = Param.MemoryController(Parent.any, "Memory Controller") diff --git a/python/m5/objects/Process.py b/python/m5/objects/Process.py deleted file mode 100644 index b4ccc1bec..000000000 --- a/python/m5/objects/Process.py +++ /dev/null @@ -1,17 +0,0 @@ -from m5 import * -class Process(SimObject): - type = 'Process' - abstract = True - output = Param.String('cout', 'filename for stdout/stderr') - -class LiveProcess(Process): - type = 'LiveProcess' - executable = Param.String('', "executable (overrides cmd[0] if set)") - cmd = VectorParam.String("command line (executable plus arguments)") - env = VectorParam.String('', "environment settings") - input = Param.String('cin', "filename for stdin") - -class EioProcess(Process): - type = 'EioProcess' - chkpt = Param.String('', "EIO checkpoint file name (optional)") - file = Param.String("EIO trace file name") diff --git a/python/m5/objects/Root.py b/python/m5/objects/Root.py deleted file mode 100644 index 23b13fc67..000000000 --- a/python/m5/objects/Root.py +++ /dev/null @@ -1,25 +0,0 @@ -from m5 import * -from HierParams import HierParams -from Serialize import Serialize -from Statistics import Statistics -from Trace import Trace -from ExeTrace import ExecutionTrace - -class Root(SimObject): - type = 'Root' - clock = Param.RootClock('200MHz', "tick frequency") - max_tick = Param.Tick('0', "maximum simulation ticks (0 = infinite)") - progress_interval = Param.Tick('0', - "print a progress message every n ticks (0 = never)") - output_file = Param.String('cout', "file to dump simulator output to") - checkpoint = Param.String('', "checkpoint file to load") -# hier = Param.HierParams(HierParams(do_data = False, do_events = True), -# "shared memory hierarchy parameters") -# stats = Param.Statistics(Statistics(), "statistics object") -# trace = Param.Trace(Trace(), "trace object") -# serialize = Param.Serialize(Serialize(), "checkpoint generation options") - hier = HierParams(do_data = False, do_events = True) - stats = Statistics() - trace = Trace() - exetrace = ExecutionTrace() - serialize = Serialize() diff --git a/python/m5/objects/SimpleDisk.py b/python/m5/objects/SimpleDisk.py deleted file mode 100644 index 48448e6e5..000000000 --- a/python/m5/objects/SimpleDisk.py +++ /dev/null @@ -1,5 +0,0 @@ -from m5 import * -class SimpleDisk(SimObject): - type = 'SimpleDisk' - disk = Param.DiskImage("Disk Image") - physmem = Param.PhysicalMemory(Parent.any, "Physical Memory") diff --git a/python/m5/objects/System.py b/python/m5/objects/System.py deleted file mode 100644 index 5925cadf5..000000000 --- a/python/m5/objects/System.py +++ /dev/null @@ -1,21 +0,0 @@ -from m5 import * - -class System(SimObject): - type = 'System' - boot_cpu_frequency = Param.Frequency(Self.cpu[0].clock.frequency, - "boot processor frequency") - memctrl = Param.MemoryController(Parent.any, "memory controller") - physmem = Param.PhysicalMemory(Parent.any, "phsyical memory") - init_param = Param.UInt64(0, "numerical value to pass into simulator") - bin = Param.Bool(False, "is this system binned") - binned_fns = VectorParam.String([], "functions broken down and binned") - kernel = Param.String("file that contains the kernel code") - readfile = Param.String("", "file to read startup script from") - -class AlphaSystem(System): - type = 'AlphaSystem' - console = Param.String("file that contains the console code") - pal = Param.String("file that contains palcode") - boot_osflags = Param.String("a", "boot flags to pass to the kernel") - system_type = Param.UInt64("Type of system we are emulating") - system_rev = Param.UInt64("Revision of system we are emulating") diff --git a/python/m5/objects/Tsunami.py b/python/m5/objects/Tsunami.py deleted file mode 100644 index 5425f421f..000000000 --- a/python/m5/objects/Tsunami.py +++ /dev/null @@ -1,27 +0,0 @@ -from m5 import * -from Device import FooPioDevice -from Platform import Platform - -class Tsunami(Platform): - type = 'Tsunami' - pciconfig = Param.PciConfigAll("PCI configuration") - system = Param.System(Parent.any, "system") - -class TsunamiCChip(FooPioDevice): - type = 'TsunamiCChip' - tsunami = Param.Tsunami(Parent.any, "Tsunami") - -class IsaFake(FooPioDevice): - type = 'IsaFake' - size = Param.Addr("Size of address range") - -class TsunamiIO(FooPioDevice): - type = 'TsunamiIO' - time = Param.UInt64(1136073600, - "System time to use (0 for actual time, default is 1/1/06)") - tsunami = Param.Tsunami(Parent.any, "Tsunami") - frequency = Param.Frequency('1024Hz', "frequency of interrupts") - -class TsunamiPChip(FooPioDevice): - type = 'TsunamiPChip' - tsunami = Param.Tsunami(Parent.any, "Tsunami") diff --git a/python/m5/objects/Uart.py b/python/m5/objects/Uart.py deleted file mode 100644 index 6eda5cdb3..000000000 --- a/python/m5/objects/Uart.py +++ /dev/null @@ -1,16 +0,0 @@ -from m5 import * -from Device import PioDevice - -class Uart(PioDevice): - type = 'Uart' - abstract = True - console = Param.SimConsole(Parent.any, "The console") - size = Param.Addr(0x8, "Device size") - -class Uart8250(Uart): - type = 'Uart8250' - -if build_env['ALPHA_TLASER']: - class Uart8530(Uart): - type = 'Uart8530' - diff --git a/sim/byteswap.hh b/sim/byteswap.hh deleted file mode 100644 index c5d8801ab..000000000 --- a/sim/byteswap.hh +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (c) 2004 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -//The purpose of this file is to provide endainness conversion utility -//functions. Depending on the endianness of the guest system, either -//the LittleEndianGuest or BigEndianGuest namespace is used. - -#ifndef __SIM_BYTE_SWAP_HH__ -#define __SIM_BYTE_SWAP_HH__ - -#include "sim/host.hh" - -// This lets us figure out what the byte order of the host system is -#if defined(linux) -#include <endian.h> -#else -#include <machine/endian.h> -#endif - -//These functions actually perform the swapping for parameters -//of various bit lengths -static inline uint64_t -swap_byte64(uint64_t x) -{ - return (uint64_t)((((uint64_t)(x) & 0xff) << 56) | - ((uint64_t)(x) & 0xff00ULL) << 40 | - ((uint64_t)(x) & 0xff0000ULL) << 24 | - ((uint64_t)(x) & 0xff000000ULL) << 8 | - ((uint64_t)(x) & 0xff00000000ULL) >> 8 | - ((uint64_t)(x) & 0xff0000000000ULL) >> 24 | - ((uint64_t)(x) & 0xff000000000000ULL) >> 40 | - ((uint64_t)(x) & 0xff00000000000000ULL) >> 56) ; -} - -static inline uint32_t -swap_byte32(uint32_t x) -{ - return (uint32_t)(((uint32_t)(x) & 0xff) << 24 | - ((uint32_t)(x) & 0xff00) << 8 | ((uint32_t)(x) & 0xff0000) >> 8 | - ((uint32_t)(x) & 0xff000000) >> 24); - -} - -static inline uint16_t -swap_byte16(uint16_t x) -{ - return (uint16_t)(((uint16_t)(x) & 0xff) << 8 | - ((uint16_t)(x) & 0xff00) >> 8); -} - -//This lets the compiler figure out how to call the swap_byte functions above -//for different data types. -static inline uint64_t swap_byte(uint64_t x) {return swap_byte64(x);} -static inline int64_t swap_byte(int64_t x) {return swap_byte64((uint64_t)x);} -static inline uint32_t swap_byte(uint32_t x) {return swap_byte32(x);} -static inline int32_t swap_byte(int32_t x) {return swap_byte32((uint32_t)x);} -#if defined(__APPLE__) -static inline long swap_byte(long x) {return swap_byte32((long)x);} -static inline unsigned long swap_byte(unsigned long x) - { return swap_byte32((unsigned long)x);} -#endif -static inline uint16_t swap_byte(uint16_t x) {return swap_byte32(x);} -static inline int16_t swap_byte(int16_t x) {return swap_byte16((uint16_t)x);} -static inline uint8_t swap_byte(uint8_t x) {return x;} -static inline int8_t swap_byte(int8_t x) {return x;} -static inline double swap_byte(double x) {return swap_byte64((uint64_t)x);} -static inline float swap_byte(float x) {return swap_byte32((uint32_t)x);} - -//The conversion functions with fixed endianness on both ends don't need to -//be in a namespace -template <typename T> static inline T betole(T value) {return swap_byte(value);} -template <typename T> static inline T letobe(T value) {return swap_byte(value);} - -//For conversions not involving the guest system, we can define the functions -//conditionally based on the BYTE_ORDER macro and outside of the namespaces -#if BYTE_ORDER == BIG_ENDIAN -template <typename T> static inline T htole(T value) {return swap_byte(value);} -template <typename T> static inline T letoh(T value) {return swap_byte(value);} -template <typename T> static inline T htobe(T value) {return value;} -template <typename T> static inline T betoh(T value) {return value;} -#elif BYTE_ORDER == LITTLE_ENDIAN -template <typename T> static inline T htole(T value) {return value;} -template <typename T> static inline T letoh(T value) {return value;} -template <typename T> static inline T htobe(T value) {return swap_byte(value);} -template <typename T> static inline T betoh(T value) {return swap_byte(value);} -#else - #error Invalid Endianess -#endif - -namespace BigEndianGuest -{ - template <typename T> - static inline T gtole(T value) {return betole(value);} - template <typename T> - static inline T letog(T value) {return letobe(value);} - template <typename T> - static inline T gtobe(T value) {return value;} - template <typename T> - static inline T betog(T value) {return value;} - template <typename T> - static inline T htog(T value) {return htobe(value);} - template <typename T> - static inline T gtoh(T value) {return betoh(value);} -} - -namespace LittleEndianGuest -{ - template <typename T> - static inline T gtole(T value) {return value;} - template <typename T> - static inline T letog(T value) {return value;} - template <typename T> - static inline T gtobe(T value) {return letobe(value);} - template <typename T> - static inline T betog(T value) {return betole(value);} - template <typename T> - static inline T htog(T value) {return htole(value);} - template <typename T> - static inline T gtoh(T value) {return letoh(value);} -} -#endif // __SIM_BYTE_SWAP_HH__ diff --git a/sim/eventq.cc b/sim/eventq.cc deleted file mode 100644 index 0884db994..000000000 --- a/sim/eventq.cc +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright (c) 2000-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <assert.h> - -#include <iostream> -#include <string> -#include <sstream> -#include <vector> - -#include "cpu/smt.hh" -#include "base/misc.hh" - -#include "sim/eventq.hh" -#include "base/trace.hh" -#include "sim/root.hh" - -using namespace std; - -// -// Main Event Queue -// -// Events on this queue are processed at the *beginning* of each -// cycle, before the pipeline simulation is performed. -// -EventQueue mainEventQueue("MainEventQueue"); - -void -EventQueue::insert(Event *event) -{ - if (head == NULL || event->when() < head->when() || - (event->when() == head->when() && - event->priority() <= head->priority())) { - event->next = head; - head = event; - } else { - Event *prev = head; - Event *curr = head->next; - - while (curr) { - if (event->when() <= curr->when() && - (event->when() < curr->when() || - event->priority() <= curr->priority())) - break; - - prev = curr; - curr = curr->next; - } - - event->next = curr; - prev->next = event; - } -} - -void -EventQueue::remove(Event *event) -{ - if (head == NULL) - return; - - if (head == event){ - head = event->next; - return; - } - - Event *prev = head; - Event *curr = head->next; - while (curr && curr != event) { - prev = curr; - curr = curr->next; - } - - if (curr == event) - prev->next = curr->next; -} - -void -EventQueue::serviceOne() -{ - Event *event = head; - event->clearFlags(Event::Scheduled); - head = event->next; - - // handle action - if (!event->squashed()) - event->process(); - else - event->clearFlags(Event::Squashed); - - if (event->getFlags(Event::AutoDelete) && !event->scheduled()) - delete event; -} - - -void -Event::serialize(std::ostream &os) -{ - SERIALIZE_SCALAR(_when); - SERIALIZE_SCALAR(_priority); - SERIALIZE_ENUM(_flags); -} - - -void -Event::unserialize(Checkpoint *cp, const string §ion) -{ - if (scheduled()) - deschedule(); - - UNSERIALIZE_SCALAR(_when); - UNSERIALIZE_SCALAR(_priority); - - // need to see if original event was in a scheduled, unsquashed - // state, but don't want to restore those flags in the current - // object itself (since they aren't immediately true) - UNSERIALIZE_ENUM(_flags); - bool wasScheduled = (_flags & Scheduled) && !(_flags & Squashed); - _flags &= ~(Squashed | Scheduled); - - if (wasScheduled) { - DPRINTF(Config, "rescheduling at %d\n", _when); - schedule(_when); - } -} - -void -EventQueue::serialize(ostream &os) -{ - std::list<Event *> eventPtrs; - - int numEvents = 0; - Event *event = head; - while (event) { - if (event->getFlags(Event::AutoSerialize)) { - eventPtrs.push_back(event); - paramOut(os, csprintf("event%d", numEvents++), event->name()); - } - event = event->next; - } - - SERIALIZE_SCALAR(numEvents); - - for (std::list<Event *>::iterator it=eventPtrs.begin(); - it != eventPtrs.end(); ++it) { - (*it)->nameOut(os); - (*it)->serialize(os); - } -} - -void -EventQueue::unserialize(Checkpoint *cp, const std::string §ion) -{ - int numEvents; - UNSERIALIZE_SCALAR(numEvents); - - std::string eventName; - for (int i = 0; i < numEvents; i++) { - // get the pointer value associated with the event - paramIn(cp, section, csprintf("event%d", i), eventName); - - // create the event based on its pointer value - Serializable::create(cp, eventName); - } -} - -void -EventQueue::dump() -{ - cprintf("============================================================\n"); - cprintf("EventQueue Dump (cycle %d)\n", curTick); - cprintf("------------------------------------------------------------\n"); - - if (empty()) - cprintf("<No Events>\n"); - else { - Event *event = head; - while (event) { - event->dump(); - event = event->next; - } - } - - cprintf("============================================================\n"); -} - -extern "C" -void -dumpMainQueue() -{ - mainEventQueue.dump(); -} - - -const char * -Event::description() -{ - return "generic"; -} - -#if TRACING_ON -void -Event::trace(const char *action) -{ - // This DPRINTF is unconditional because calls to this function - // are protected by an 'if (DTRACE(Event))' in the inlined Event - // methods. - // - // This is just a default implementation for derived classes where - // it's not worth doing anything special. If you want to put a - // more informative message in the trace, override this method on - // the particular subclass where you have the information that - // needs to be printed. - DPRINTFN("%s event %s @ %d\n", description(), action, when()); -} -#endif - -void -Event::dump() -{ - cprintf("Event (%s)\n", description()); - cprintf("Flags: %#x\n", _flags); -#if TRACING_ON - cprintf("Created: %d\n", when_created); -#endif - if (scheduled()) { -#if TRACING_ON - cprintf("Scheduled at %d\n", when_scheduled); -#endif - cprintf("Scheduled for %d, priority %d\n", when(), _priority); - } - else { - cprintf("Not Scheduled\n"); - } -} diff --git a/sim/faults.cc b/sim/faults.cc deleted file mode 100644 index 701384989..000000000 --- a/sim/faults.cc +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "sim/faults.hh" -#include "cpu/exec_context.hh" -#include "cpu/base.hh" - -#if !FULL_SYSTEM -void FaultBase::invoke(ExecContext * xc) -{ - fatal("fault (%s) detected @ PC 0x%08p", name(), xc->readPC()); -} -#else -void FaultBase::invoke(ExecContext * xc) -{ - DPRINTF(Fault, "Fault %s at PC: %#x\n", name(), xc->readPC()); - xc->getCpuPtr()->recordEvent(csprintf("Fault %s", name())); - - assert(!xc->misspeculating()); -} -#endif diff --git a/sim/faults.hh b/sim/faults.hh deleted file mode 100644 index 18601e8f1..000000000 --- a/sim/faults.hh +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __FAULTS_HH__ -#define __FAULTS_HH__ - -#include "base/refcnt.hh" -#include "sim/stats.hh" -#include "config/full_system.hh" - -class ExecContext; -class FaultBase; -typedef RefCountingPtr<FaultBase> Fault; - -typedef const char * FaultName; -typedef Stats::Scalar<> FaultStat; - -// Each class has it's name statically define in _name, -// and has a virtual function to access it's name. -// The function is necessary because otherwise, all objects -// which are being accessed cast as a FaultBase * (namely -// all faults returned using the Fault type) will use the -// generic FaultBase name. - -class FaultBase : public RefCounted -{ - public: - virtual FaultName name() = 0; -#if FULL_SYSTEM - virtual void invoke(ExecContext * xc); -#else - virtual void invoke(ExecContext * xc); -#endif -// template<typename T> -// bool isA() {return dynamic_cast<T *>(this);} - virtual bool isMachineCheckFault() {return false;} - virtual bool isAlignmentFault() {return false;} -}; - -FaultBase * const NoFault = 0; - -#endif // __FAULTS_HH__ diff --git a/sim/host.hh b/sim/host.hh deleted file mode 100644 index f7e64f23c..000000000 --- a/sim/host.hh +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * Defines host-dependent types: - * Counter, Tick, and (indirectly) {int,uint}{8,16,32,64}_t. - */ - -#ifndef __HOST_HH__ -#define __HOST_HH__ - -#include <inttypes.h> - -/** uint64_t constant */ -#define ULL(N) ((uint64_t)N##ULL) -/** int64_t constant */ -#define LL(N) (((int64_t)N##LL) - -/** Statistics counter type. Not much excuse for not using a 64-bit - * integer here, but if you're desperate and only run short - * simulations you could make this 32 bits. - */ -typedef int64_t Counter; - -/** - * Clock cycle count type. - * @note using an unsigned breaks the cache. - */ -typedef int64_t Tick; - -/** - * Address type - * This will probably be moved somewhere else in the near future. - * This should be at least as big as the biggest address width in use - * in the system, which will probably be 64 bits. - */ -typedef uint64_t Addr; - -#endif // __HOST_H__ diff --git a/sim/main.cc b/sim/main.cc deleted file mode 100644 index 6f6143506..000000000 --- a/sim/main.cc +++ /dev/null @@ -1,429 +0,0 @@ -/* - * Copyright (c) 2000-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/// -/// @file sim/main.cc -/// -#include <sys/types.h> -#include <sys/stat.h> -#include <errno.h> -#include <libgen.h> -#include <stdlib.h> -#include <signal.h> - -#include <list> -#include <string> -#include <vector> - -#include "base/copyright.hh" -#include "base/embedfile.hh" -#include "base/inifile.hh" -#include "base/misc.hh" -#include "base/output.hh" -#include "base/pollevent.hh" -#include "base/statistics.hh" -#include "base/str.hh" -#include "base/time.hh" -#include "cpu/base.hh" -#include "cpu/smt.hh" -#include "python/pyconfig.hh" -#include "sim/async.hh" -#include "sim/builder.hh" -#include "sim/configfile.hh" -#include "sim/host.hh" -#include "sim/sim_events.hh" -#include "sim/sim_exit.hh" -#include "sim/sim_object.hh" -#include "sim/stat_control.hh" -#include "sim/stats.hh" -#include "sim/root.hh" - -using namespace std; - -// See async.h. -volatile bool async_event = false; -volatile bool async_dump = false; -volatile bool async_dumpreset = false; -volatile bool async_exit = false; -volatile bool async_io = false; -volatile bool async_alarm = false; - -/// Stats signal handler. -void -dumpStatsHandler(int sigtype) -{ - async_event = true; - async_dump = true; -} - -void -dumprstStatsHandler(int sigtype) -{ - async_event = true; - async_dumpreset = true; -} - -/// Exit signal handler. -void -exitNowHandler(int sigtype) -{ - async_event = true; - async_exit = true; -} - -/// Abort signal handler. -void -abortHandler(int sigtype) -{ - cerr << "Program aborted at cycle " << curTick << endl; - -#if TRACING_ON - // dump trace buffer, if there is one - Trace::theLog.dump(cerr); -#endif -} - -/// Simulator executable name -char *myProgName = ""; - -/// Show brief help message. -void -showBriefHelp(ostream &out) -{ - char *prog = basename(myProgName); - - ccprintf(out, "Usage:\n"); - ccprintf(out, -"%s [-d <dir>] [-E <var>[=<val>]] [-I <dir>] [-P <python>]\n" -" [--<var>=<val>] <config file>\n" -"\n" -" -d set the output directory to <dir>\n" -" -E set the environment variable <var> to <val> (or 'True')\n" -" -I add the directory <dir> to python's path\n" -" -P execute <python> directly in the configuration\n" -" --var=val set the python variable <var> to '<val>'\n" -" <configfile> config file name (ends in .py)\n\n", - prog); - - ccprintf(out, "%s -X\n -X extract embedded files\n\n", prog); - ccprintf(out, "%s -h\n -h print short help\n\n", prog); -} - -/// Print welcome message. -void -sayHello(ostream &out) -{ - extern const char *compileDate; // from date.cc - - ccprintf(out, "M5 Simulator System\n"); - // display copyright - ccprintf(out, "%s\n", briefCopyright); - ccprintf(out, "M5 compiled on %d\n", compileDate); - - char *host = getenv("HOSTNAME"); - if (!host) - host = getenv("HOST"); - - if (host) - ccprintf(out, "M5 executing on %s\n", host); - - ccprintf(out, "M5 simulation started %s\n", Time::start); -} - -/// -/// Echo the command line for posterity in such a way that it can be -/// used to rerun the same simulation (given the same .ini files). -/// -void -echoCommandLine(int argc, char **argv, ostream &out) -{ - out << "command line: " << argv[0]; - for (int i = 1; i < argc; i++) { - string arg(argv[i]); - - out << ' '; - - // If the arg contains spaces, we need to quote it. - // The rest of this is overkill to make it look purty. - - // print dashes first outside quotes - int non_dash_pos = arg.find_first_not_of("-"); - out << arg.substr(0, non_dash_pos); // print dashes - string body = arg.substr(non_dash_pos); // the rest - - // if it's an assignment, handle the lhs & rhs separately - int eq_pos = body.find("="); - if (eq_pos == string::npos) { - out << quote(body); - } - else { - string lhs(body.substr(0, eq_pos)); - string rhs(body.substr(eq_pos + 1)); - - out << quote(lhs) << "=" << quote(rhs); - } - } - out << endl << endl; -} - -char * -getOptionString(int &index, int argc, char **argv) -{ - char *option = argv[index] + 2; - if (*option != '\0') - return option; - - // We didn't find an argument, it must be in the next variable. - if (++index >= argc) - panic("option string for option '%s' not found", argv[index - 1]); - - return argv[index]; -} - -int -main(int argc, char **argv) -{ - // Save off program name - myProgName = argv[0]; - - signal(SIGFPE, SIG_IGN); // may occur on misspeculated paths - signal(SIGTRAP, SIG_IGN); - signal(SIGUSR1, dumpStatsHandler); // dump intermediate stats - signal(SIGUSR2, dumprstStatsHandler); // dump and reset stats - signal(SIGINT, exitNowHandler); // dump final stats and exit - signal(SIGABRT, abortHandler); - - bool configfile_found = false; - PythonConfig pyconfig; - string outdir; - - if (argc < 2) { - showBriefHelp(cerr); - exit(1); - } - - sayHello(cerr); - - // Parse command-line options. - // Since most of the complex options are handled through the - // config database, we don't mess with getopts, and just parse - // manually. - for (int i = 1; i < argc; ++i) { - char *arg_str = argv[i]; - - // if arg starts with '--', parse as a special python option - // of the format --<python var>=<string value>, if the arg - // starts with '-', it should be a simulator option with a - // format similar to getopt. In any other case, treat the - // option as a configuration file name and load it. - if (arg_str[0] == '-' && arg_str[1] == '-') { - string str = &arg_str[2]; - string var, val; - - if (!split_first(str, var, val, '=')) - panic("Could not parse configuration argument '%s'\n" - "Expecting --<variable>=<value>\n", arg_str); - - pyconfig.setVariable(var, val); - } else if (arg_str[0] == '-') { - char *option; - string var, val; - - // switch on second char - switch (arg_str[1]) { - case 'd': - outdir = getOptionString(i, argc, argv); - break; - - case 'h': - showBriefHelp(cerr); - exit(1); - - case 'E': - option = getOptionString(i, argc, argv); - if (!split_first(option, var, val, '=')) - val = "True"; - - if (setenv(var.c_str(), val.c_str(), true) == -1) - panic("setenv: %s\n", strerror(errno)); - break; - - case 'I': - option = getOptionString(i, argc, argv); - pyconfig.addPath(option); - break; - - case 'P': - option = getOptionString(i, argc, argv); - pyconfig.writeLine(option); - break; - - case 'X': { - list<EmbedFile> lst; - EmbedMap::all(lst); - list<EmbedFile>::iterator i = lst.begin(); - list<EmbedFile>::iterator end = lst.end(); - - while (i != end) { - cprintf("Embedded File: %s\n", i->name); - cout.write(i->data, i->length); - ++i; - } - - return 0; - } - - default: - showBriefHelp(cerr); - panic("invalid argument '%s'\n", arg_str); - } - } else { - string file(arg_str); - string base, ext; - - if (!split_last(file, base, ext, '.') || ext != "py") - panic("Config file '%s' must end in '.py'\n", file); - - pyconfig.load(file); - configfile_found = true; - } - } - - if (outdir.empty()) { - char *env = getenv("OUTPUT_DIR"); - outdir = env ? env : "."; - } - - simout.setDirectory(outdir); - - char *env = getenv("CONFIG_OUTPUT"); - if (!env) - env = "config.out"; - configStream = simout.find(env); - - if (!configfile_found) - panic("no configuration file specified!"); - - // The configuration database is now complete; start processing it. - IniFile inifile; - if (!pyconfig.output(inifile)) - panic("Error processing python code"); - - // Initialize statistics database - Stats::InitSimStats(); - - // Now process the configuration hierarchy and create the SimObjects. - ConfigHierarchy configHierarchy(inifile); - configHierarchy.build(); - configHierarchy.createSimObjects(); - - // Parse and check all non-config-hierarchy parameters. - ParamContext::parseAllContexts(inifile); - ParamContext::checkAllContexts(); - - // Print hello message to stats file if it's actually a file. If - // it's not (i.e. it's cout or cerr) then we already did it above. - if (simout.isFile(*outputStream)) - sayHello(*outputStream); - - // Echo command line and all parameter settings to stats file as well. - echoCommandLine(argc, argv, *outputStream); - ParamContext::showAllContexts(*configStream); - - // Do a second pass to finish initializing the sim objects - SimObject::initAll(); - - // Restore checkpointed state, if any. - configHierarchy.unserializeSimObjects(); - - // Done processing the configuration database. - // Check for unreferenced entries. - if (inifile.printUnreferenced()) - panic("unreferenced sections/entries in the intermediate ini file"); - - SimObject::regAllStats(); - - // uncomment the following to get PC-based execution-time profile -#ifdef DO_PROFILE - init_profile((char *)&_init, (char *)&_fini); -#endif - - // Check to make sure that the stats package is properly initialized - Stats::check(); - - // Reset to put the stats in a consistent state. - Stats::reset(); - - warn("Entering event queue. Starting simulation...\n"); - SimStartup(); - while (!mainEventQueue.empty()) { - assert(curTick <= mainEventQueue.nextTick() && - "event scheduled in the past"); - - // forward current cycle to the time of the first event on the - // queue - curTick = mainEventQueue.nextTick(); - mainEventQueue.serviceOne(); - - if (async_event) { - async_event = false; - if (async_dump) { - async_dump = false; - - using namespace Stats; - SetupEvent(Dump, curTick); - } - - if (async_dumpreset) { - async_dumpreset = false; - - using namespace Stats; - SetupEvent(Dump | Reset, curTick); - } - - if (async_exit) { - async_exit = false; - new SimExitEvent("User requested STOP"); - } - - if (async_io || async_alarm) { - async_io = false; - async_alarm = false; - pollQueue.service(); - } - } - } - - // This should never happen... every conceivable way for the - // simulation to terminate (hit max cycles/insts, signal, - // simulated system halts/exits) generates an exit event, so we - // should never run out of events on the queue. - exitNow("no events on event loop! All CPUs must be idle.", 1); - - return 0; -} diff --git a/sim/param.cc b/sim/param.cc deleted file mode 100644 index bc81881d3..000000000 --- a/sim/param.cc +++ /dev/null @@ -1,794 +0,0 @@ -/* - * Copyright (c) 2002-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <algorithm> -#include <cassert> -#include <cstdio> -#include <list> -#include <string> -#include <vector> - -#include "base/inifile.hh" -#include "base/misc.hh" -#include "base/range.hh" -#include "base/str.hh" -#include "base/trace.hh" -#include "sim/config_node.hh" -#include "sim/configfile.hh" -#include "sim/param.hh" -#include "sim/sim_object.hh" - -using namespace std; - - -//////////////////////////////////////////////////////////////////////// -// -// BaseParam member definitions -// -//////////////////////////////////////////////////////////////////////// - -void -BaseParam::die(const string &err) const -{ - context->printErrorProlog(cerr); - cerr << " parameter '" << name << "': " - << err << endl; - abort(); -} - - -//////////////////////////////////////////////////////////////////////// -// -// Param<T> and VectorParam<T> member definitions -// -// We implement parsing & displaying values for various parameter -// types T using a set of overloaded functions: -// -// - parseParam(string s, T &value) parses s into value -// - showParam(ostream &os, T &value) displays value on os -// -// By making these independent functions, we can reuse the same code -// for type T in both Param<T> and VectorParam<T>. -// -// For enum types, the parseParam function requires additional -// arguments, in which case we must specialize the Param<T>::parse and -// VectorParam<T>::parse calls as well. -// -// Type-specific instances come first, followed by more generic -// templated versions and their instantiations. -// -//////////////////////////////////////////////////////////////////////// - -// -// The base implementations use to_number for parsing and '<<' for -// displaying, suitable for integer types. -// -template <class T> -bool -parseParam(const string &s, T &value) -{ - return to_number(s, value); -} - -template <class T> -void -showParam(ostream &os, T const &value) -{ - os << value; -} - -// -// Template specializations: -// - char (8-bit integer) -// - floating-point types -// - bool -// - string -// - -// Treat 8-bit ints (chars) as ints on output, not as chars -template <> -void -showParam(ostream &os, const char &value) -{ - os << (int)value; -} - - -template <> -void -showParam(ostream &os, const unsigned char &value) -{ - os << (unsigned int)value; -} - - -// Use sscanf() for FP types as to_number() only handles integers -template <> -bool -parseParam(const string &s, float &value) -{ - return (sscanf(s.c_str(), "%f", &value) == 1); -} - -template <> -bool -parseParam(const string &s, double &value) -{ - return (sscanf(s.c_str(), "%lf", &value) == 1); -} - -// Be flexible about what we take for bool -template <> -bool -parseParam(const string &s, bool &value) -{ - const string &ls = to_lower(s); - - if (ls == "true" || ls == "t" || ls == "yes" || ls == "y" || ls == "1") { - value = true; - return true; - } - - if (ls == "false" || ls == "f" || ls == "no" || ls == "n" || ls == "0") { - value = false; - return true; - } - - return false; -} - -// Display bools as strings -template <> -void -showParam(ostream &os, const bool &value) -{ - os << (value ? "true" : "false"); -} - - -// String requires no processing to speak of -template <> -bool -parseParam(const string &s, string &value) -{ - value = s; - return true; -} - -template <> -bool -parseParam(const string &s, Range<uint32_t> &value) -{ - value = s; - return value.valid(); -} - -template <> -bool -parseParam(const string &s, Range<uint64_t> &value) -{ - value = s; - return value.valid(); -} - -// -// End of parseParam/showParam definitions. Now we move on to -// incorporate them into the Param/VectorParam parse() and showValue() -// methods. -// - -// These definitions for Param<T>::parse and VectorParam<T>::parse -// work for any type for which parseParam() takes only two arguments -// (i.e., all the fundamental types like int, bool, etc.), thanks to -// overloading. -template <class T> -void -Param<T>::parse(const string &s) -{ - if (parseParam(s, value)) { - wasSet = true; - } - else { - string err("could not parse \""); - - err += s; - err += "\""; - - die(err); - } -} - -template <class T> -void -VectorParam<T>::parse(const string &s) -{ - if (s.empty()) { - wasSet = true; - return; - } - - vector<string> tokens; - - tokenize(tokens, s, ' '); - - value.resize(tokens.size()); - - for (int i = 0; i < tokens.size(); i++) { - // need to parse into local variable to handle vector<bool>, - // for which operator[] returns a special reference class - // that's not the same as 'bool&', (since it's a packed - // vector) - T scalar_value; - if (!parseParam(tokens[i], scalar_value)) { - string err("could not parse \""); - - err += s; - err += "\""; - - die(err); - } - - // assign parsed value to vector - value[i] = scalar_value; - } - - wasSet = true; -} - -// These definitions for Param<T>::showValue() and -// VectorParam<T>::showValue() work for any type where showParam() -// takes only two arguments (i.e., everything but the SimpleEnum and -// MappedEnum classes). -template <class T> -void -Param<T>::showValue(ostream &os) const -{ - showParam(os, value); -} - -template <class T> -void -VectorParam<T>::showValue(ostream &os) const -{ - for (int i = 0; i < value.size(); i++) { - if (i != 0) { - os << " "; - } - showParam(os, value[i]); - } -} - - -#ifdef INSURE_BUILD -#define INSTANTIATE_PARAM_TEMPLATES(type, typestr) \ -void Param<type>::showType(ostream &os) const { os << typestr; } \ -void VectorParam<type>::showType(ostream &os) const { \ - os << "vector of " << typestr; \ -} \ -template Param<type>; \ -template VectorParam<type>; - -#else -// instantiate all four methods (parse/show, scalar/vector) for basic -// types that can use the above templates -#define INSTANTIATE_PARAM_TEMPLATES(type, typestr) \ -template bool parseParam<type>(const string &s, type &value); \ -template void showParam<type>(ostream &os, type const &value); \ -template void Param<type>::parse(const string &); \ -template void VectorParam<type>::parse(const string &); \ -template void Param<type>::showValue(ostream &) const; \ -template void VectorParam<type>::showValue(ostream &) const; \ -template <> void Param<type>::showType(ostream &os) const { os << typestr; } \ -template <> void VectorParam<type>::showType(ostream &os) const { \ - os << "vector of " << typestr; \ -} -#endif - -INSTANTIATE_PARAM_TEMPLATES(unsigned long long, "ull") -INSTANTIATE_PARAM_TEMPLATES(signed long long, "sll") -INSTANTIATE_PARAM_TEMPLATES(unsigned long, "uns long") -INSTANTIATE_PARAM_TEMPLATES(signed long, "long") -INSTANTIATE_PARAM_TEMPLATES(unsigned int, "uns") -INSTANTIATE_PARAM_TEMPLATES(signed int, "int") -INSTANTIATE_PARAM_TEMPLATES(unsigned short, "uns short") -INSTANTIATE_PARAM_TEMPLATES(signed short, "short") -INSTANTIATE_PARAM_TEMPLATES(unsigned char, "uns char") -INSTANTIATE_PARAM_TEMPLATES(signed char, "char") - -INSTANTIATE_PARAM_TEMPLATES(float, "float") -INSTANTIATE_PARAM_TEMPLATES(double, "double") - -INSTANTIATE_PARAM_TEMPLATES(bool, "bool") -INSTANTIATE_PARAM_TEMPLATES(string, "string") - -INSTANTIATE_PARAM_TEMPLATES(Range<uint64_t>, "uint64 range") -INSTANTIATE_PARAM_TEMPLATES(Range<uint32_t>, "uint32 range") - -#undef INSTANTIATE_PARAM_TEMPLATES - -// -// SimpleEnumParam & MappedEnumParam must specialize their parse(), -// showValue(), and showType() methods. -// - -// -// SimpleEnumParam & SimpleEnumVectorParam -// -bool -parseEnumParam(const char *const *map, const int num_values, - const string &s, int &value) -{ - for (int i = 0; i < num_values; ++i) { - if (s == map[i]) { - value = i; - return true; - } - } - - return false; -} - -void -showEnumParam(ostream &os, - const char *const *map, const int num_values, - int value) -{ - assert(0 <= value && value < num_values); - os << map[value]; -} - -void -showEnumType(ostream &os, - const char *const *map, const int num_values) -{ - os << "{" << map[0]; - for (int i = 1; i < num_values; ++i) - os << "," << map[i]; - - os << "}"; -} - - -// -// MappedEnumParam & MappedEnumVectorParam -// -bool -parseEnumParam(const EnumParamMap *map, const int num_values, - const string &s, int &value) -{ - for (int i = 0; i < num_values; ++i) { - if (s == map[i].name) { - value = map[i].value; - return true; - } - } - - return false; -} - -void -showEnumParam(ostream &os, - const EnumParamMap *map, const int num_values, - int value) -{ - for (int i = 0; i < num_values; ++i) { - if (value == map[i].value) { - os << map[i].name; - return; - } - } - - // if we can't find a reverse mapping just print the int value - os << value; -} - -void -showEnumType(ostream &os, - const EnumParamMap *map, const int num_values) -{ - os << "{" << map[0].name; - for (int i = 1; i < num_values; ++i) - os << "," << map[i].name; - - os << "}"; -} - - -template <class Map> -void -EnumParam<Map>::parse(const string &s) -{ - if (parseEnumParam(map, num_values, s, value)) { - wasSet = true; - } else { - string err("no match for enum string \""); - - err += s; - err += "\""; - - die(err); - } -} - -template <class Map> -void -EnumVectorParam<Map>::parse(const string &s) -{ - vector<string> tokens; - - if (s.empty()) { - wasSet = true; - return; - } - - tokenize(tokens, s, ' '); - - value.resize(tokens.size()); - - for (int i = 0; i < tokens.size(); i++) { - if (!parseEnumParam(map, num_values, tokens[i], value[i])) { - string err("no match for enum string \""); - - err += s; - err += "\""; - - die(err); - } - } - - wasSet = true; -} - -template <class Map> -void -EnumParam<Map>::showValue(ostream &os) const -{ - showEnumParam(os, map, num_values, value); -} - -template <class Map> -void -EnumVectorParam<Map>::showValue(ostream &os) const -{ - for (int i = 0; i < value.size(); i++) { - if (i != 0) { - os << " "; - } - showEnumParam(os, map, num_values, value[i]); - } -} - -template <class Map> -void -EnumParam<Map>::showType(ostream &os) const -{ - showEnumType(os, map, num_values); -} - -template <class Map> -void -EnumVectorParam<Map>::showType(ostream &os) const -{ - os << "vector of"; - showEnumType(os, map, num_values); -} - -template class EnumParam<const char *>; -template class EnumVectorParam<const char *>; - -template class EnumParam<EnumParamMap>; -template class EnumVectorParam<EnumParamMap>; - -//////////////////////////////////////////////////////////////////////// -// -// SimObjectBaseParam methods -// -//////////////////////////////////////////////////////////////////////// - -bool -parseSimObjectParam(ParamContext *context, const string &s, SimObject *&value) -{ - SimObject *obj; - - if (to_lower(s) == "null") { - // explicitly set to null by user; assume that's OK - obj = NULL; - } - else { - obj = context->resolveSimObject(s); - - if (obj == NULL) - return false; - } - - value = obj; - return true; -} - - -void -SimObjectBaseParam::showValue(ostream &os, SimObject *value) const -{ - os << (value ? value->name() : "null"); -} - -void -SimObjectBaseParam::parse(const string &s, SimObject *&value) -{ - if (parseSimObjectParam(context, s, value)) { - wasSet = true; - } - else { - string err("could not resolve object name \""); - - err += s; - err += "\""; - - die(err); - } -} - -void -SimObjectBaseParam::parse(const string &s, vector<SimObject *>&value) -{ - vector<string> tokens; - - tokenize(tokens, s, ' '); - - value.resize(tokens.size()); - - for (int i = 0; i < tokens.size(); i++) { - if (!parseSimObjectParam(context, tokens[i], value[i])) { - string err("could not resolve object name \""); - - err += s; - err += "\""; - - die(err); - } - } - - wasSet = true; -} - -//////////////////////////////////////////////////////////////////////// -// -// ParamContext member definitions -// -//////////////////////////////////////////////////////////////////////// - -list<ParamContext *> *ParamContext::ctxList = NULL; - -ParamContext::ParamContext(const string &_iniSection, InitPhase _initPhase) - : iniFilePtr(NULL), // initialized on call to parseParams() - iniSection(_iniSection), paramList(NULL), - initPhase(_initPhase) -{ - // Put this context on global list for initialization - if (initPhase != NoAutoInit) { - if (ctxList == NULL) - ctxList = new list<ParamContext *>(); - - // keep list sorted by ascending initPhase values - list<ParamContext *>::iterator i = ctxList->begin(); - list<ParamContext *>::iterator end = ctxList->end(); - for (; i != end; ++i) { - if (initPhase <= (*i)->initPhase) { - // found where we want to insert - break; - } - } - // (fall through case: insert at end) - ctxList->insert(i, this); - } -} - - -void -ParamContext::addParam(BaseParam *param) -{ - getParamList()->push_back(param); -} - - -void -ParamContext::parseParams(IniFile &iniFile) -{ - iniFilePtr = &iniFile; // set object member - - ParamList::iterator i; - - for (i = getParamList()->begin(); i != getParamList()->end(); ++i) { - string string_value; - - if (iniFile.find(iniSection, (*i)->name, string_value)) - (*i)->parse(string_value); - } -} - - -// Check parameter values for validity & consistency. Default -// implementation is no-op; derive subclass & override to add -// actual functionality here. -void -ParamContext::checkParams() -{ - // nada -} - - -// Clean up context-related objects at end of execution. Default -// implementation is no-op; derive subclass & override to add actual -// functionality here. -void -ParamContext::cleanup() -{ - // nada -} - - -void -ParamContext::describeParams(ostream &os) -{ - ParamList::iterator i; - - for (i = getParamList()->begin(); i != getParamList()->end(); ++i) { - BaseParam *p = *i; - - os << p->name << " ("; - p->showType(os); - os << "): " << p->description << "\n"; - } -} - - - -void -ParamContext::showParams(ostream &os) -{ - ParamList::iterator i; - - for (i = getParamList()->begin(); i != getParamList()->end(); ++i) { - BaseParam *p = *i; - - if (p->isValid()) { - os << p->name << "="; - p->showValue(os); - os << endl; - } - else { - os << "// "<< p->name << " not specified" << endl; - } - } -} - - -void -ParamContext::printErrorProlog(ostream &os) -{ - os << "Parameter error in section [" << iniSection << "]: " << endl; -} - -// -// Resolve an object name to a SimObject pointer. The object will be -// created as a side-effect if necessary. If the name contains a -// colon (e.g., "iq:IQ"), then the object is local (invisible to -// outside this context). If there is no colon, the name needs to be -// resolved through the configuration hierarchy (only possible for -// SimObjectBuilder objects, which return non-NULL for configNode()). -// -SimObject * -ParamContext::resolveSimObject(const string &name) -{ - ConfigNode *n = getConfigNode(); - return n ? n->resolveSimObject(name) : NULL; -} - - -// -// static method: call parseParams() on all registered contexts -// -void -ParamContext::parseAllContexts(IniFile &iniFile) -{ - list<ParamContext *>::iterator iter; - - for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) { - ParamContext *pc = *iter; - - pc->parseParams(iniFile); - } -} - - -// -// static method: call checkParams() on all registered contexts -// -void -ParamContext::checkAllContexts() -{ - list<ParamContext *>::iterator iter; - - for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) { - ParamContext *pc = *iter; - - pc->checkParams(); - } -} - - -// -// static method: call showParams() on all registered contexts -// -void -ParamContext::showAllContexts(ostream &os) -{ - list<ParamContext *>::iterator iter; - - for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) { - ParamContext *pc = *iter; - - os << "[" << pc->iniSection << "]" << endl; - pc->showParams(os); - os << endl; - } -} - - -// -// static method: call cleanup() on all registered contexts -// -void -ParamContext::cleanupAllContexts() -{ - list<ParamContext *>::iterator iter; - - for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) { - ParamContext *pc = *iter; - - pc->cleanup(); - } -} - - -// -// static method: call describeParams() on all registered contexts -// -void -ParamContext::describeAllContexts(ostream &os) -{ - list<ParamContext *>::iterator iter; - - for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) { - ParamContext *pc = *iter; - - os << "[" << pc->iniSection << "]\n"; - pc->describeParams(os); - os << endl; - } -} diff --git a/sim/process.cc b/sim/process.cc deleted file mode 100644 index a84a4f7ba..000000000 --- a/sim/process.cc +++ /dev/null @@ -1,446 +0,0 @@ -/* - * Copyright (c) 2001-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <unistd.h> -#include <fcntl.h> - -#include <cstdio> -#include <string> - -#include "base/intmath.hh" -#include "base/loader/object_file.hh" -#include "base/loader/symtab.hh" -#include "base/statistics.hh" -#include "config/full_system.hh" -#include "cpu/cpu_exec_context.hh" -#include "cpu/exec_context.hh" -#include "cpu/smt.hh" -#include "encumbered/cpu/full/thread.hh" -#include "encumbered/eio/eio.hh" -#include "encumbered/mem/functional/main.hh" -#include "sim/builder.hh" -#include "sim/process.hh" -#include "sim/stats.hh" -#include "sim/syscall_emul.hh" - -#include "arch/process.hh" - -using namespace std; -using namespace TheISA; - -// -// The purpose of this code is to fake the loader & syscall mechanism -// when there's no OS: thus there's no resone to use it in FULL_SYSTEM -// mode when we do have an OS -// -#if FULL_SYSTEM -#error "process.cc not compatible with FULL_SYSTEM" -#endif - -// current number of allocated processes -int num_processes = 0; - -Process::Process(const string &nm, - int stdin_fd, // initial I/O descriptors - int stdout_fd, - int stderr_fd) - : SimObject(nm) -{ - // allocate memory space - memory = new MainMemory(nm + ".MainMem"); - - // allocate initial register file - init_regs = new RegFile; - memset(init_regs, 0, sizeof(RegFile)); - - cpuXC = new CPUExecContext(init_regs); - - // initialize first 3 fds (stdin, stdout, stderr) - fd_map[STDIN_FILENO] = stdin_fd; - fd_map[STDOUT_FILENO] = stdout_fd; - fd_map[STDERR_FILENO] = stderr_fd; - - // mark remaining fds as free - for (int i = 3; i <= MAX_FD; ++i) { - fd_map[i] = -1; - } - - mmap_start = mmap_end = 0; - nxm_start = nxm_end = 0; - // other parameters will be initialized when the program is loaded -} - -void -Process::regStats() -{ - using namespace Stats; - - num_syscalls - .name(name() + ".PROG:num_syscalls") - .desc("Number of system calls") - ; -} - -// -// static helper functions -// -int -Process::openInputFile(const string &filename) -{ - int fd = open(filename.c_str(), O_RDONLY); - - if (fd == -1) { - perror(NULL); - cerr << "unable to open \"" << filename << "\" for reading\n"; - fatal("can't open input file"); - } - - return fd; -} - - -int -Process::openOutputFile(const string &filename) -{ - int fd = open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0774); - - if (fd == -1) { - perror(NULL); - cerr << "unable to open \"" << filename << "\" for writing\n"; - fatal("can't open output file"); - } - - return fd; -} - - -int -Process::registerExecContext(ExecContext *xc) -{ - // add to list - int myIndex = execContexts.size(); - execContexts.push_back(xc); - - if (myIndex == 0) { - // copy process's initial regs struct - // Hack for now to copy init regs - xc->copyArchRegs(cpuXC->getProxy()); - } - - // return CPU number to caller and increment available CPU count - return myIndex; -} - -void -Process::startup() -{ - if (execContexts.empty()) - return; - - // first exec context for this process... initialize & enable - ExecContext *xc = execContexts[0]; - - // mark this context as active so it will start ticking. - xc->activate(0); -} - -void -Process::replaceExecContext(ExecContext *xc, int xcIndex) -{ - if (xcIndex >= execContexts.size()) { - panic("replaceExecContext: bad xcIndex, %d >= %d\n", - xcIndex, execContexts.size()); - } - - execContexts[xcIndex] = xc; -} - -// map simulator fd sim_fd to target fd tgt_fd -void -Process::dup_fd(int sim_fd, int tgt_fd) -{ - if (tgt_fd < 0 || tgt_fd > MAX_FD) - panic("Process::dup_fd tried to dup past MAX_FD (%d)", tgt_fd); - - fd_map[tgt_fd] = sim_fd; -} - - -// generate new target fd for sim_fd -int -Process::alloc_fd(int sim_fd) -{ - // in case open() returns an error, don't allocate a new fd - if (sim_fd == -1) - return -1; - - // find first free target fd - for (int free_fd = 0; free_fd < MAX_FD; ++free_fd) { - if (fd_map[free_fd] == -1) { - fd_map[free_fd] = sim_fd; - return free_fd; - } - } - - panic("Process::alloc_fd: out of file descriptors!"); -} - - -// free target fd (e.g., after close) -void -Process::free_fd(int tgt_fd) -{ - if (fd_map[tgt_fd] == -1) - warn("Process::free_fd: request to free unused fd %d", tgt_fd); - - fd_map[tgt_fd] = -1; -} - - -// look up simulator fd for given target fd -int -Process::sim_fd(int tgt_fd) -{ - if (tgt_fd > MAX_FD) - return -1; - - return fd_map[tgt_fd]; -} - - - -// -// need to declare these here since there is no concrete Process type -// that can be constructed (i.e., no REGISTER_SIM_OBJECT() macro call, -// which is where these get declared for concrete types). -// -DEFINE_SIM_OBJECT_CLASS_NAME("Process", Process) - - -//////////////////////////////////////////////////////////////////////// -// -// LiveProcess member definitions -// -//////////////////////////////////////////////////////////////////////// - - -static void -copyStringArray(vector<string> &strings, Addr array_ptr, Addr data_ptr, - FunctionalMemory *memory) -{ - Addr data_ptr_swap; - for (int i = 0; i < strings.size(); ++i) { - data_ptr_swap = htog(data_ptr); - memory->access(Write, array_ptr, &data_ptr_swap, sizeof(Addr)); - memory->writeString(data_ptr, strings[i].c_str()); - array_ptr += sizeof(Addr); - data_ptr += strings[i].size() + 1; - } - // add NULL terminator - data_ptr = 0; - memory->access(Write, array_ptr, &data_ptr, sizeof(Addr)); -} - -LiveProcess::LiveProcess(const string &nm, ObjectFile *objFile, - int stdin_fd, int stdout_fd, int stderr_fd, - vector<string> &argv, vector<string> &envp) - : Process(nm, stdin_fd, stdout_fd, stderr_fd) -{ - prog_fname = argv[0]; - - prog_entry = objFile->entryPoint(); - text_base = objFile->textBase(); - text_size = objFile->textSize(); - data_base = objFile->dataBase(); - data_size = objFile->dataSize() + objFile->bssSize(); - brk_point = roundUp(data_base + data_size, VMPageSize); - - // load object file into target memory - objFile->loadSections(memory); - - // load up symbols, if any... these may be used for debugging or - // profiling. - if (!debugSymbolTable) { - debugSymbolTable = new SymbolTable(); - if (!objFile->loadGlobalSymbols(debugSymbolTable) || - !objFile->loadLocalSymbols(debugSymbolTable)) { - // didn't load any symbols - delete debugSymbolTable; - debugSymbolTable = NULL; - } - } - - // Set up stack. On Alpha, stack goes below text section. This - // code should get moved to some architecture-specific spot. - stack_base = text_base - (409600+4096); - - // Set up region for mmaps. Tru64 seems to start just above 0 and - // grow up from there. - mmap_start = mmap_end = 0x10000; - - // Set pointer for next thread stack. Reserve 8M for main stack. - next_thread_stack_base = stack_base - (8 * 1024 * 1024); - - // Calculate how much space we need for arg & env arrays. - int argv_array_size = sizeof(Addr) * (argv.size() + 1); - int envp_array_size = sizeof(Addr) * (envp.size() + 1); - int arg_data_size = 0; - for (int i = 0; i < argv.size(); ++i) { - arg_data_size += argv[i].size() + 1; - } - int env_data_size = 0; - for (int i = 0; i < envp.size(); ++i) { - env_data_size += envp[i].size() + 1; - } - - int space_needed = - argv_array_size + envp_array_size + arg_data_size + env_data_size; - // for SimpleScalar compatibility - if (space_needed < 16384) - space_needed = 16384; - - // set bottom of stack - stack_min = stack_base - space_needed; - // align it - stack_min &= ~7; - stack_size = stack_base - stack_min; - - // map out initial stack contents - Addr argv_array_base = stack_min + sizeof(uint64_t); // room for argc - Addr envp_array_base = argv_array_base + argv_array_size; - Addr arg_data_base = envp_array_base + envp_array_size; - Addr env_data_base = arg_data_base + arg_data_size; - - // write contents to stack - uint64_t argc = argv.size(); - argc = htog(argc); - memory->access(Write, stack_min, &argc, sizeof(uint64_t)); - - copyStringArray(argv, argv_array_base, arg_data_base, memory); - copyStringArray(envp, envp_array_base, env_data_base, memory); - - cpuXC->setIntReg(ArgumentReg0, argc); - cpuXC->setIntReg(ArgumentReg1, argv_array_base); - cpuXC->setIntReg(StackPointerReg, stack_min); - cpuXC->setIntReg(GlobalPointerReg, objFile->globalPointer()); - cpuXC->setPC(prog_entry); - cpuXC->setNextPC(prog_entry + sizeof(MachInst)); -} - -void -LiveProcess::syscall(ExecContext *xc) -{ - num_syscalls++; - - int64_t callnum = xc->readIntReg(SyscallNumReg); - - SyscallDesc *desc = getDesc(callnum); - if (desc == NULL) - fatal("Syscall %d out of range", callnum); - - desc->doSyscall(callnum, this, xc); -} - -LiveProcess * -LiveProcess::create(const string &nm, - int stdin_fd, int stdout_fd, int stderr_fd, - string executable, - vector<string> &argv, vector<string> &envp) -{ - LiveProcess *process = NULL; - ObjectFile *objFile = createObjectFile(executable); - if (objFile == NULL) { - fatal("Can't load object file %s", executable); - } - - // set up syscall emulation pointer for the current ISA - process = createProcess(nm, objFile, - stdin_fd, stdout_fd, stderr_fd, - argv, envp); - - delete objFile; - - if (process == NULL) - fatal("Unknown error creating process object."); - - return process; -} - - - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(LiveProcess) - - VectorParam<string> cmd; - Param<string> executable; - Param<string> input; - Param<string> output; - VectorParam<string> env; - -END_DECLARE_SIM_OBJECT_PARAMS(LiveProcess) - - -BEGIN_INIT_SIM_OBJECT_PARAMS(LiveProcess) - - INIT_PARAM(cmd, "command line (executable plus arguments)"), - INIT_PARAM(executable, "executable (overrides cmd[0] if set)"), - INIT_PARAM(input, "filename for stdin (dflt: use sim stdin)"), - INIT_PARAM(output, "filename for stdout/stderr (dflt: use sim stdout)"), - INIT_PARAM(env, "environment settings") - -END_INIT_SIM_OBJECT_PARAMS(LiveProcess) - - -CREATE_SIM_OBJECT(LiveProcess) -{ - string in = input; - string out = output; - - // initialize file descriptors to default: same as simulator - int stdin_fd, stdout_fd, stderr_fd; - - if (in == "stdin" || in == "cin") - stdin_fd = STDIN_FILENO; - else - stdin_fd = Process::openInputFile(input); - - if (out == "stdout" || out == "cout") - stdout_fd = STDOUT_FILENO; - else if (out == "stderr" || out == "cerr") - stdout_fd = STDERR_FILENO; - else - stdout_fd = Process::openOutputFile(out); - - stderr_fd = (stdout_fd != STDOUT_FILENO) ? stdout_fd : STDERR_FILENO; - - return LiveProcess::create(getInstanceName(), - stdin_fd, stdout_fd, stderr_fd, - (string)executable == "" ? cmd[0] : executable, - cmd, env); -} - -REGISTER_SIM_OBJECT("LiveProcess", LiveProcess) diff --git a/sim/process.hh b/sim/process.hh deleted file mode 100644 index 3a48f128c..000000000 --- a/sim/process.hh +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright (c) 2001-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __PROCESS_HH__ -#define __PROCESS_HH__ - -// -// The purpose of this code is to fake the loader & syscall mechanism -// when there's no OS: thus there's no reason to use it in FULL_SYSTEM -// mode when we do have an OS. -// -#include "config/full_system.hh" - -#if !FULL_SYSTEM - -#include <vector> - -#include "arch/isa_traits.hh" -#include "sim/sim_object.hh" -#include "sim/stats.hh" -#include "base/statistics.hh" -#include "base/trace.hh" - -class CPUExecContext; -class ExecContext; -class FunctionalMemory; -class SyscallDesc; -class Process : public SimObject -{ - protected: - typedef TheISA::RegFile RegFile; - typedef TheISA::MachInst MachInst; - public: - - // have we initialized an execution context from this process? If - // yes, subsequent contexts are assumed to be for dynamically - // created threads and are not initialized. - bool initialContextLoaded; - - // execution contexts associated with this process - std::vector<ExecContext *> execContexts; - - // number of CPUs (esxec contexts, really) assigned to this process. - unsigned int numCpus() { return execContexts.size(); } - - // record of blocked context - struct WaitRec - { - Addr waitChan; - ExecContext *waitingContext; - - WaitRec(Addr chan, ExecContext *ctx) - : waitChan(chan), waitingContext(ctx) - { - } - }; - - // list of all blocked contexts - std::list<WaitRec> waitList; - - RegFile *init_regs; // initial register contents - CPUExecContext *cpuXC; // XC to hold the init_regs - - Addr text_base; // text (code) segment base - unsigned text_size; // text (code) size in bytes - - Addr data_base; // initialized data segment base - unsigned data_size; // initialized data + bss size in bytes - - Addr brk_point; // top of the data segment - - Addr stack_base; // stack segment base (highest address) - unsigned stack_size; // initial stack size - Addr stack_min; // lowest address accessed on the stack - - // addr to use for next stack region (for multithreaded apps) - Addr next_thread_stack_base; - - // Base of region for mmaps (when user doesn't specify an address). - Addr mmap_start; - Addr mmap_end; - - // Base of region for nxm data - Addr nxm_start; - Addr nxm_end; - - std::string prog_fname; // file name - Addr prog_entry; // entry point (initial PC) - - Stats::Scalar<> num_syscalls; // number of syscalls executed - - - protected: - // constructor - Process(const std::string &nm, - int stdin_fd, // initial I/O descriptors - int stdout_fd, - int stderr_fd); - - // post initialization startup - virtual void startup(); - - protected: - FunctionalMemory *memory; - - private: - // file descriptor remapping support - static const int MAX_FD = 256; // max legal fd value - int fd_map[MAX_FD+1]; - - public: - // static helper functions to generate file descriptors for constructor - static int openInputFile(const std::string &filename); - static int openOutputFile(const std::string &filename); - - // override of virtual SimObject method: register statistics - virtual void regStats(); - - // register an execution context for this process. - // returns xc's cpu number (index into execContexts[]) - int registerExecContext(ExecContext *xc); - - - void replaceExecContext(ExecContext *xc, int xcIndex); - - // map simulator fd sim_fd to target fd tgt_fd - void dup_fd(int sim_fd, int tgt_fd); - - // generate new target fd for sim_fd - int alloc_fd(int sim_fd); - - // free target fd (e.g., after close) - void free_fd(int tgt_fd); - - // look up simulator fd for given target fd - int sim_fd(int tgt_fd); - - // is this a valid instruction fetch address? - bool validInstAddr(Addr addr) - { - return (text_base <= addr && - addr < text_base + text_size && - !(addr & (sizeof(MachInst)-1))); - } - - // is this a valid address? (used to filter data fetches) - // note that we just assume stack size <= 16MB - // this may be alpha-specific - bool validDataAddr(Addr addr) - { - return ((data_base <= addr && addr < brk_point) || - (next_thread_stack_base <= addr && addr < stack_base) || - (text_base <= addr && addr < (text_base + text_size)) || - (mmap_start <= addr && addr < mmap_end) || - (nxm_start <= addr && addr < nxm_end)); - } - - virtual void syscall(ExecContext *xc) = 0; - - virtual FunctionalMemory *getMemory() { return memory; } -}; - -// -// "Live" process with system calls redirected to host system -// -class ObjectFile; -class LiveProcess : public Process -{ - protected: - LiveProcess(const std::string &nm, ObjectFile *objFile, - int stdin_fd, int stdout_fd, int stderr_fd, - std::vector<std::string> &argv, - std::vector<std::string> &envp); - - public: - // this function is used to create the LiveProcess object, since - // we can't tell which subclass of LiveProcess to use until we - // open and look at the object file. - static LiveProcess *create(const std::string &nm, - int stdin_fd, int stdout_fd, int stderr_fd, - std::string executable, - std::vector<std::string> &argv, - std::vector<std::string> &envp); - - virtual void syscall(ExecContext *xc); - - virtual SyscallDesc* getDesc(int callnum) { panic("Must be implemented."); } - -}; - - -#endif // !FULL_SYSTEM - -#endif // __PROCESS_HH__ diff --git a/sim/pseudo_inst.cc b/sim/pseudo_inst.cc deleted file mode 100644 index 2d737c0a2..000000000 --- a/sim/pseudo_inst.cc +++ /dev/null @@ -1,291 +0,0 @@ -/* - * Copyright (c) 2003-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <errno.h> -#include <fcntl.h> -#include <unistd.h> -#include <cstdio> - -#include <string> - -#include "sim/pseudo_inst.hh" -#include "arch/vtophys.hh" -#include "cpu/base.hh" -#include "cpu/sampler/sampler.hh" -#include "cpu/exec_context.hh" -#include "cpu/quiesce_event.hh" -#include "kern/kernel_stats.hh" -#include "sim/param.hh" -#include "sim/serialize.hh" -#include "sim/sim_exit.hh" -#include "sim/stat_control.hh" -#include "sim/stats.hh" -#include "sim/system.hh" -#include "sim/debug.hh" -#include "sim/vptr.hh" - -using namespace std; - -extern Sampler *SampCPU; - -using namespace Stats; -using namespace TheISA; - -namespace AlphaPseudo -{ - bool doStatisticsInsts; - bool doCheckpointInsts; - bool doQuiesce; - - void - arm(ExecContext *xc) - { - if (xc->getKernelStats()) - xc->getKernelStats()->arm(); - } - - void - quiesce(ExecContext *xc) - { - if (!doQuiesce) - return; - - xc->suspend(); - if (xc->getKernelStats()) - xc->getKernelStats()->quiesce(); - } - - void - quiesceNs(ExecContext *xc, uint64_t ns) - { - if (!doQuiesce || ns == 0) - return; - - EndQuiesceEvent *quiesceEvent = xc->getQuiesceEvent(); - - if (quiesceEvent->scheduled()) - quiesceEvent->reschedule(curTick + Clock::Int::ns * ns); - else - quiesceEvent->schedule(curTick + Clock::Int::ns * ns); - - xc->suspend(); - if (xc->getKernelStats()) - xc->getKernelStats()->quiesce(); - } - - void - quiesceCycles(ExecContext *xc, uint64_t cycles) - { - if (!doQuiesce || cycles == 0) - return; - - EndQuiesceEvent *quiesceEvent = xc->getQuiesceEvent(); - - if (quiesceEvent->scheduled()) - quiesceEvent->reschedule(curTick + - xc->getCpuPtr()->cycles(cycles)); - else - quiesceEvent->schedule(curTick + - xc->getCpuPtr()->cycles(cycles)); - - xc->suspend(); - if (xc->getKernelStats()) - xc->getKernelStats()->quiesce(); - } - - uint64_t - quiesceTime(ExecContext *xc) - { - return (xc->readLastActivate() - xc->readLastSuspend()) / Clock::Int::ns; - } - - void - ivlb(ExecContext *xc) - { - if (xc->getKernelStats()) - xc->getKernelStats()->ivlb(); - } - - void - ivle(ExecContext *xc) - { - } - - void - m5exit_old(ExecContext *xc) - { - SimExit(curTick, "m5_exit_old instruction encountered"); - } - - void - m5exit(ExecContext *xc, Tick delay) - { - Tick when = curTick + delay * Clock::Int::ns; - SimExit(when, "m5_exit instruction encountered"); - } - - void - resetstats(ExecContext *xc, Tick delay, Tick period) - { - if (!doStatisticsInsts) - return; - - - Tick when = curTick + delay * Clock::Int::ns; - Tick repeat = period * Clock::Int::ns; - - using namespace Stats; - SetupEvent(Reset, when, repeat); - } - - void - dumpstats(ExecContext *xc, Tick delay, Tick period) - { - if (!doStatisticsInsts) - return; - - - Tick when = curTick + delay * Clock::Int::ns; - Tick repeat = period * Clock::Int::ns; - - using namespace Stats; - SetupEvent(Dump, when, repeat); - } - - void - addsymbol(ExecContext *xc, Addr addr, Addr symbolAddr) - { - char symb[100]; - CopyString(xc, symb, symbolAddr, 100); - std::string symbol(symb); - - DPRINTF(Loader, "Loaded symbol: %s @ %#llx\n", symbol, addr); - - xc->getSystemPtr()->kernelSymtab->insert(addr,symbol); - } - - void - dumpresetstats(ExecContext *xc, Tick delay, Tick period) - { - if (!doStatisticsInsts) - return; - - - Tick when = curTick + delay * Clock::Int::ns; - Tick repeat = period * Clock::Int::ns; - - using namespace Stats; - SetupEvent(Dump|Reset, when, repeat); - } - - void - m5checkpoint(ExecContext *xc, Tick delay, Tick period) - { - if (!doCheckpointInsts) - return; - - - Tick when = curTick + delay * Clock::Int::ns; - Tick repeat = period * Clock::Int::ns; - - Checkpoint::setup(when, repeat); - } - - uint64_t - readfile(ExecContext *xc, Addr vaddr, uint64_t len, uint64_t offset) - { - const string &file = xc->getCpuPtr()->system->params()->readfile; - if (file.empty()) { - return ULL(0); - } - - uint64_t result = 0; - - int fd = ::open(file.c_str(), O_RDONLY, 0); - if (fd < 0) - panic("could not open file %s\n", file); - - if (::lseek(fd, offset, SEEK_SET) < 0) - panic("could not seek: %s", strerror(errno)); - - char *buf = new char[len]; - char *p = buf; - while (len > 0) { - int bytes = ::read(fd, p, len); - if (bytes <= 0) - break; - - p += bytes; - result += bytes; - len -= bytes; - } - - close(fd); - CopyIn(xc, vaddr, buf, result); - delete [] buf; - return result; - } - - class Context : public ParamContext - { - public: - Context(const string §ion) : ParamContext(section) {} - void checkParams(); - }; - - Context context("pseudo_inst"); - - Param<bool> __quiesce(&context, "quiesce", - "enable quiesce instructions", - true); - Param<bool> __statistics(&context, "statistics", - "enable statistics pseudo instructions", - true); - Param<bool> __checkpoint(&context, "checkpoint", - "enable checkpoint pseudo instructions", - true); - - void - Context::checkParams() - { - doQuiesce = __quiesce; - doStatisticsInsts = __statistics; - doCheckpointInsts = __checkpoint; - } - - void debugbreak(ExecContext *xc) - { - debug_break(); - } - - void switchcpu(ExecContext *xc) - { - if (SampCPU) - SampCPU->switchCPUs(); - } -} diff --git a/sim/sim_object.cc b/sim/sim_object.cc deleted file mode 100644 index f34e17fe6..000000000 --- a/sim/sim_object.cc +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Copyright (c) 2001-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <assert.h> - -#include "base/callback.hh" -#include "base/inifile.hh" -#include "base/match.hh" -#include "base/misc.hh" -#include "base/trace.hh" -#include "base/stats/events.hh" -#include "sim/configfile.hh" -#include "sim/host.hh" -#include "sim/sim_object.hh" -#include "sim/stats.hh" -#include "sim/param.hh" - -using namespace std; - - -//////////////////////////////////////////////////////////////////////// -// -// SimObject member definitions -// -//////////////////////////////////////////////////////////////////////// - -// -// static list of all SimObjects, used for initialization etc. -// -SimObject::SimObjectList SimObject::simObjectList; - -namespace Stats { - extern ObjectMatch event_ignore; -} - -// -// SimObject constructor: used to maintain static simObjectList -// -SimObject::SimObject(Params *p) - : _params(p) -{ -#ifdef DEBUG - doDebugBreak = false; -#endif - - doRecordEvent = !Stats::event_ignore.match(name()); - simObjectList.push_back(this); -} - -// -// SimObject constructor: used to maintain static simObjectList -// -SimObject::SimObject(const string &_name) - : _params(new Params) -{ - _params->name = _name; -#ifdef DEBUG - doDebugBreak = false; -#endif - - doRecordEvent = !Stats::event_ignore.match(name()); - simObjectList.push_back(this); -} - -void -SimObject::init() -{ -} - -// -// no default statistics, so nothing to do in base implementation -// -void -SimObject::regStats() -{ -} - -void -SimObject::regFormulas() -{ -} - -void -SimObject::resetStats() -{ -} - -// -// static function: -// call regStats() on all SimObjects and then regFormulas() on all -// SimObjects. -// -struct SimObjectResetCB : public Callback -{ - virtual void process() { SimObject::resetAllStats(); } -}; - -namespace { - static SimObjectResetCB StatResetCB; -} - -void -SimObject::regAllStats() -{ - SimObjectList::iterator i; - SimObjectList::iterator end = simObjectList.end(); - - /** - * @todo change cprintfs to DPRINTFs - */ - for (i = simObjectList.begin(); i != end; ++i) { -#ifdef STAT_DEBUG - cprintf("registering stats for %s\n", (*i)->name()); -#endif - (*i)->regStats(); - } - - for (i = simObjectList.begin(); i != end; ++i) { -#ifdef STAT_DEBUG - cprintf("registering formulas for %s\n", (*i)->name()); -#endif - (*i)->regFormulas(); - } - - Stats::registerResetCallback(&StatResetCB); -} - -// -// static function: call init() on all SimObjects. -// -void -SimObject::initAll() -{ - SimObjectList::iterator i = simObjectList.begin(); - SimObjectList::iterator end = simObjectList.end(); - - for (; i != end; ++i) { - SimObject *obj = *i; - obj->init(); - } -} - -// -// static function: call resetStats() on all SimObjects. -// -void -SimObject::resetAllStats() -{ - SimObjectList::iterator i = simObjectList.begin(); - SimObjectList::iterator end = simObjectList.end(); - - for (; i != end; ++i) { - SimObject *obj = *i; - obj->resetStats(); - } -} - -// -// static function: serialize all SimObjects. -// -void -SimObject::serializeAll(ostream &os) -{ - SimObjectList::reverse_iterator ri = simObjectList.rbegin(); - SimObjectList::reverse_iterator rend = simObjectList.rend(); - - for (; ri != rend; ++ri) { - SimObject *obj = *ri; - obj->nameOut(os); - obj->serialize(os); - } -} - -#ifdef DEBUG -// -// static function: flag which objects should have the debugger break -// -void -SimObject::debugObjectBreak(const string &objs) -{ - SimObjectList::const_iterator i = simObjectList.begin(); - SimObjectList::const_iterator end = simObjectList.end(); - - ObjectMatch match(objs); - for (; i != end; ++i) { - SimObject *obj = *i; - obj->doDebugBreak = match.match(obj->name()); - } -} - -extern "C" -void -debugObjectBreak(const char *objs) -{ - SimObject::debugObjectBreak(string(objs)); -} -#endif - -void -SimObject::recordEvent(const std::string &stat) -{ - if (doRecordEvent) - Stats::recordEvent(stat); -} - -DEFINE_SIM_OBJECT_CLASS_NAME("SimObject", SimObject) diff --git a/sim/sim_object.hh b/sim/sim_object.hh deleted file mode 100644 index 59d9daf45..000000000 --- a/sim/sim_object.hh +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2001-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* @file - * User Console Definitions - */ - -#ifndef __SIM_OBJECT_HH__ -#define __SIM_OBJECT_HH__ - -#include <map> -#include <list> -#include <vector> -#include <iostream> - -#include "sim/serialize.hh" -#include "sim/startup.hh" - -/* - * Abstract superclass for simulation objects. Represents things that - * correspond to physical components and can be specified via the - * config file (CPUs, caches, etc.). - */ -class SimObject : public Serializable, protected StartupCallback -{ - public: - struct Params { - std::string name; - }; - - protected: - Params *_params; - - public: - const Params *params() const { return _params; } - - private: - friend class Serializer; - - typedef std::vector<SimObject *> SimObjectList; - - // list of all instantiated simulation objects - static SimObjectList simObjectList; - - public: - SimObject(Params *_params); - SimObject(const std::string &_name); - - virtual ~SimObject() {} - - virtual const std::string name() const { return params()->name; } - - // initialization pass of all objects. - // Gets invoked after construction, before unserialize. - virtual void init(); - static void initAll(); - - // register statistics for this object - virtual void regStats(); - virtual void regFormulas(); - virtual void resetStats(); - - // static: call reg_stats on all SimObjects - static void regAllStats(); - - // static: call resetStats on all SimObjects - static void resetAllStats(); - - // static: call nameOut() & serialize() on all SimObjects - static void serializeAll(std::ostream &); - -#ifdef DEBUG - public: - bool doDebugBreak; - static void debugObjectBreak(const std::string &objs); -#endif - - public: - bool doRecordEvent; - void recordEvent(const std::string &stat); -}; - -#endif // __SIM_OBJECT_HH__ diff --git a/sim/syscall_emul.cc b/sim/syscall_emul.cc deleted file mode 100644 index 00168b025..000000000 --- a/sim/syscall_emul.cc +++ /dev/null @@ -1,441 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <fcntl.h> -#include <unistd.h> - -#include <string> -#include <iostream> - -#include "sim/syscall_emul.hh" -#include "base/trace.hh" -#include "cpu/exec_context.hh" -#include "cpu/base.hh" -#include "sim/process.hh" - -#include "sim/sim_events.hh" - -using namespace std; -using namespace TheISA; - -void -SyscallDesc::doSyscall(int callnum, Process *process, ExecContext *xc) -{ - DPRINTFR(SyscallVerbose, "%s: syscall %s called\n", - xc->getCpuPtr()->name(), name); - - SyscallReturn retval = (*funcPtr)(this, callnum, process, xc); - - DPRINTFR(SyscallVerbose, "%s: syscall %s returns %d\n", - xc->getCpuPtr()->name(), name, retval.value()); - - if (!(flags & SyscallDesc::SuppressReturnValue)) - xc->setSyscallReturn(retval); -} - - -SyscallReturn -unimplementedFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - fatal("syscall %s (#%d) unimplemented.", desc->name, callnum); -} - - -SyscallReturn -ignoreFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - warn("ignoring syscall %s(%d, %d, ...)", desc->name, - xc->getSyscallArg(0), xc->getSyscallArg(1)); - - return 0; -} - - -SyscallReturn -exitFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - new SimExitEvent("syscall caused exit", xc->getSyscallArg(0) & 0xff); - - return 1; -} - - -SyscallReturn -getpagesizeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) -{ - return (int)VMPageSize; -} - - -SyscallReturn -obreakFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) -{ - // change brk addr to first arg - Addr new_brk = xc->getSyscallArg(0); - if (new_brk != 0) - { - p->brk_point = xc->getSyscallArg(0); - } - DPRINTF(SyscallVerbose, "Break Point changed to: %#X\n", p->brk_point); - return p->brk_point; -} - - -SyscallReturn -closeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) -{ - int target_fd = xc->getSyscallArg(0); - int status = close(p->sim_fd(target_fd)); - if (status >= 0) - p->free_fd(target_fd); - return status; -} - - -SyscallReturn -readFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) -{ - int fd = p->sim_fd(xc->getSyscallArg(0)); - int nbytes = xc->getSyscallArg(2); - BufferArg bufArg(xc->getSyscallArg(1), nbytes); - - int bytes_read = read(fd, bufArg.bufferPtr(), nbytes); - - if (bytes_read != -1) - bufArg.copyOut(xc->getMemPtr()); - - return bytes_read; -} - -SyscallReturn -writeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) -{ - int fd = p->sim_fd(xc->getSyscallArg(0)); - int nbytes = xc->getSyscallArg(2); - BufferArg bufArg(xc->getSyscallArg(1), nbytes); - - bufArg.copyIn(xc->getMemPtr()); - - int bytes_written = write(fd, bufArg.bufferPtr(), nbytes); - - fsync(fd); - - return bytes_written; -} - - -SyscallReturn -lseekFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) -{ - int fd = p->sim_fd(xc->getSyscallArg(0)); - uint64_t offs = xc->getSyscallArg(1); - int whence = xc->getSyscallArg(2); - - off_t result = lseek(fd, offs, whence); - - return (result == (off_t)-1) ? -errno : result; -} - - -SyscallReturn -munmapFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) -{ - // given that we don't really implement mmap, munmap is really easy - return 0; -} - - -const char *hostname = "m5.eecs.umich.edu"; - -SyscallReturn -gethostnameFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) -{ - int name_len = xc->getSyscallArg(1); - BufferArg name(xc->getSyscallArg(0), name_len); - - strncpy((char *)name.bufferPtr(), hostname, name_len); - - name.copyOut(xc->getMemPtr()); - - return 0; -} - -SyscallReturn -unlinkFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) -{ - string path; - - if (xc->getMemPtr()->readString(path, xc->getSyscallArg(0)) != NoFault) - return (TheISA::IntReg)-EFAULT; - - int result = unlink(path.c_str()); - return (result == -1) ? -errno : result; -} - -SyscallReturn -renameFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) -{ - string old_name; - - if (xc->getMemPtr()->readString(old_name, xc->getSyscallArg(0)) != NoFault) - return -EFAULT; - - string new_name; - - if (xc->getMemPtr()->readString(new_name, xc->getSyscallArg(1)) != NoFault) - return -EFAULT; - - int64_t result = rename(old_name.c_str(), new_name.c_str()); - return (result == -1) ? -errno : result; -} - -SyscallReturn -truncateFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) -{ - string path; - - if (xc->getMemPtr()->readString(path, xc->getSyscallArg(0)) != NoFault) - return -EFAULT; - - off_t length = xc->getSyscallArg(1); - - int result = truncate(path.c_str(), length); - return (result == -1) ? -errno : result; -} - -SyscallReturn -ftruncateFunc(SyscallDesc *desc, int num, Process *process, ExecContext *xc) -{ - int fd = process->sim_fd(xc->getSyscallArg(0)); - - if (fd < 0) - return -EBADF; - - off_t length = xc->getSyscallArg(1); - - int result = ftruncate(fd, length); - return (result == -1) ? -errno : result; -} - -SyscallReturn -chownFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) -{ - string path; - - if (xc->getMemPtr()->readString(path, xc->getSyscallArg(0)) != NoFault) - return -EFAULT; - - /* XXX endianess */ - uint32_t owner = xc->getSyscallArg(1); - uid_t hostOwner = owner; - uint32_t group = xc->getSyscallArg(2); - gid_t hostGroup = group; - - int result = chown(path.c_str(), hostOwner, hostGroup); - return (result == -1) ? -errno : result; -} - -SyscallReturn -fchownFunc(SyscallDesc *desc, int num, Process *process, ExecContext *xc) -{ - int fd = process->sim_fd(xc->getSyscallArg(0)); - - if (fd < 0) - return -EBADF; - - /* XXX endianess */ - uint32_t owner = xc->getSyscallArg(1); - uid_t hostOwner = owner; - uint32_t group = xc->getSyscallArg(2); - gid_t hostGroup = group; - - int result = fchown(fd, hostOwner, hostGroup); - return (result == -1) ? -errno : result; -} - - -SyscallReturn -fcntlFunc(SyscallDesc *desc, int num, Process *process, - ExecContext *xc) -{ - int fd = xc->getSyscallArg(0); - - if (fd < 0 || process->sim_fd(fd) < 0) - return -EBADF; - - int cmd = xc->getSyscallArg(1); - switch (cmd) { - case 0: // F_DUPFD - // if we really wanted to support this, we'd need to do it - // in the target fd space. - warn("fcntl(%d, F_DUPFD) not supported, error returned\n", fd); - return -EMFILE; - - case 1: // F_GETFD (get close-on-exec flag) - case 2: // F_SETFD (set close-on-exec flag) - return 0; - - case 3: // F_GETFL (get file flags) - case 4: // F_SETFL (set file flags) - // not sure if this is totally valid, but we'll pass it through - // to the underlying OS - warn("fcntl(%d, %d) passed through to host\n", fd, cmd); - return fcntl(process->sim_fd(fd), cmd); - // return 0; - - case 7: // F_GETLK (get lock) - case 8: // F_SETLK (set lock) - case 9: // F_SETLKW (set lock and wait) - // don't mess with file locking... just act like it's OK - warn("File lock call (fcntl(%d, %d)) ignored.\n", fd, cmd); - return 0; - - default: - warn("Unknown fcntl command %d\n", cmd); - return 0; - } -} - -SyscallReturn -pipePseudoFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - int fds[2], sim_fds[2]; - int pipe_retval = pipe(fds); - - if (pipe_retval < 0) { - // error - return pipe_retval; - } - - sim_fds[0] = process->alloc_fd(fds[0]); - sim_fds[1] = process->alloc_fd(fds[1]); - - // Alpha Linux convention for pipe() is that fd[0] is returned as - // the return value of the function, and fd[1] is returned in r20. - xc->setIntReg(SyscallPseudoReturnReg, sim_fds[1]); - return sim_fds[0]; -} - - -SyscallReturn -getpidPseudoFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - // Make up a PID. There's no interprocess communication in - // fake_syscall mode, so there's no way for a process to know it's - // not getting a unique value. - - xc->setIntReg(SyscallPseudoReturnReg, 99); - return 100; -} - - -SyscallReturn -getuidPseudoFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - // Make up a UID and EUID... it shouldn't matter, and we want the - // simulation to be deterministic. - - // EUID goes in r20. - xc->setIntReg(SyscallPseudoReturnReg, 100); //EUID - return 100; // UID -} - - -SyscallReturn -getgidPseudoFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - // Get current group ID. EGID goes in r20. - xc->setIntReg(SyscallPseudoReturnReg, 100); //EGID - return 100; -} - - -SyscallReturn -setuidFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - // can't fathom why a benchmark would call this. - warn("Ignoring call to setuid(%d)\n", xc->getSyscallArg(0)); - return 0; -} - -SyscallReturn -getpidFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - // Make up a PID. There's no interprocess communication in - // fake_syscall mode, so there's no way for a process to know it's - // not getting a unique value. - - xc->setIntReg(SyscallPseudoReturnReg, 99); //PID - return 100; -} - -SyscallReturn -getppidFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - return 99; -} - -SyscallReturn -getuidFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - return 100; // UID -} - -SyscallReturn -geteuidFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - return 100; // UID -} - -SyscallReturn -getgidFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - return 100; -} - -SyscallReturn -getegidFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - return 100; -} - - diff --git a/sim/syscall_emul.hh b/sim/syscall_emul.hh deleted file mode 100644 index 35129bcb4..000000000 --- a/sim/syscall_emul.hh +++ /dev/null @@ -1,832 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __SIM_SYSCALL_EMUL_HH__ -#define __SIM_SYSCALL_EMUL_HH__ - -#define BSD_HOST (defined(__APPLE__) || defined(__OpenBSD__) || \ - defined(__FreeBSD__)) - -/// -/// @file syscall_emul.hh -/// -/// This file defines objects used to emulate syscalls from the target -/// application on the host machine. - -#include <errno.h> -#include <string> -#ifdef __CYGWIN32__ -#include <sys/fcntl.h> // for O_BINARY -#endif -#include <sys/uio.h> - -#include "base/intmath.hh" // for RoundUp -#include "mem/functional/functional.hh" -#include "arch/isa_traits.hh" // for Addr - -#include "base/trace.hh" -#include "cpu/exec_context.hh" -#include "sim/process.hh" - -/// -/// System call descriptor. -/// -class SyscallDesc { - - public: - - /// Typedef for target syscall handler functions. - typedef SyscallReturn (*FuncPtr)(SyscallDesc *, int num, - Process *, ExecContext *); - - const char *name; //!< Syscall name (e.g., "open"). - FuncPtr funcPtr; //!< Pointer to emulation function. - int flags; //!< Flags (see Flags enum). - - /// Flag values for controlling syscall behavior. - enum Flags { - /// Don't set return regs according to funcPtr return value. - /// Used for syscalls with non-standard return conventions - /// that explicitly set the ExecContext regs (e.g., - /// sigreturn). - SuppressReturnValue = 1 - }; - - /// Constructor. - SyscallDesc(const char *_name, FuncPtr _funcPtr, int _flags = 0) - : name(_name), funcPtr(_funcPtr), flags(_flags) - { - } - - /// Emulate the syscall. Public interface for calling through funcPtr. - void doSyscall(int callnum, Process *proc, ExecContext *xc); -}; - - -class BaseBufferArg { - - public: - - BaseBufferArg(Addr _addr, int _size) : addr(_addr), size(_size) - { - bufPtr = new uint8_t[size]; - // clear out buffer: in case we only partially populate this, - // and then do a copyOut(), we want to make sure we don't - // introduce any random junk into the simulated address space - memset(bufPtr, 0, size); - } - - virtual ~BaseBufferArg() { delete [] bufPtr; } - - // - // copy data into simulator space (read from target memory) - // - virtual bool copyIn(FunctionalMemory *mem) - { - mem->access(Read, addr, bufPtr, size); - return true; // no EFAULT detection for now - } - - // - // copy data out of simulator space (write to target memory) - // - virtual bool copyOut(FunctionalMemory *mem) - { - mem->access(Write, addr, bufPtr, size); - return true; // no EFAULT detection for now - } - - protected: - Addr addr; - int size; - uint8_t *bufPtr; -}; - - -class BufferArg : public BaseBufferArg -{ - public: - BufferArg(Addr _addr, int _size) : BaseBufferArg(_addr, _size) { } - void *bufferPtr() { return bufPtr; } -}; - -template <class T> -class TypedBufferArg : public BaseBufferArg -{ - public: - // user can optionally specify a specific number of bytes to - // allocate to deal with those structs that have variable-size - // arrays at the end - TypedBufferArg(Addr _addr, int _size = sizeof(T)) - : BaseBufferArg(_addr, _size) - { } - - // type case - operator T*() { return (T *)bufPtr; } - - // dereference operators - T &operator*() { return *((T *)bufPtr); } - T* operator->() { return (T *)bufPtr; } - T &operator[](int i) { return ((T *)bufPtr)[i]; } -}; - -////////////////////////////////////////////////////////////////////// -// -// The following emulation functions are generic enough that they -// don't need to be recompiled for different emulated OS's. They are -// defined in sim/syscall_emul.cc. -// -////////////////////////////////////////////////////////////////////// - - -/// Handler for unimplemented syscalls that we haven't thought about. -SyscallReturn unimplementedFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - -/// Handler for unimplemented syscalls that we never intend to -/// implement (signal handling, etc.) and should not affect the correct -/// behavior of the program. Print a warning only if the appropriate -/// trace flag is enabled. Return success to the target program. -SyscallReturn ignoreFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - -/// Target exit() handler: terminate simulation. -SyscallReturn exitFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - -/// Target getpagesize() handler. -SyscallReturn getpagesizeFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - -/// Target obreak() handler: set brk address. -SyscallReturn obreakFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - -/// Target close() handler. -SyscallReturn closeFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - -/// Target read() handler. -SyscallReturn readFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - -/// Target write() handler. -SyscallReturn writeFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - -/// Target lseek() handler. -SyscallReturn lseekFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - -/// Target munmap() handler. -SyscallReturn munmapFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - -/// Target gethostname() handler. -SyscallReturn gethostnameFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - -/// Target unlink() handler. -SyscallReturn unlinkFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - -/// Target rename() handler. -SyscallReturn renameFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - - -/// Target truncate() handler. -SyscallReturn truncateFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - - -/// Target ftruncate() handler. -SyscallReturn ftruncateFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - - -/// Target chown() handler. -SyscallReturn chownFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - - -/// Target fchown() handler. -SyscallReturn fchownFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - -/// Target fnctl() handler. -SyscallReturn fcntlFunc(SyscallDesc *desc, int num, - Process *process, ExecContext *xc); - -/// Target setuid() handler. -SyscallReturn setuidFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - -/// Target getpid() handler. -SyscallReturn getpidFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - -/// Target getuid() handler. -SyscallReturn getuidFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - -/// Target getgid() handler. -SyscallReturn getgidFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - -/// Target getppid() handler. -SyscallReturn getppidFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - -/// Target geteuid() handler. -SyscallReturn geteuidFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - -/// Target getegid() handler. -SyscallReturn getegidFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - - - -/// Pseudo Funcs - These functions use a different return convension, -/// returning a second value in a register other than the normal return register -SyscallReturn pipePseudoFunc(SyscallDesc *desc, int num, - Process *process, ExecContext *xc); - -/// Target getpidPseudo() handler. -SyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - -/// Target getuidPseudo() handler. -SyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - -/// Target getgidPseudo() handler. -SyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - - -/// This struct is used to build an target-OS-dependent table that -/// maps the target's open() flags to the host open() flags. -struct OpenFlagTransTable { - int tgtFlag; //!< Target system flag value. - int hostFlag; //!< Corresponding host system flag value. -}; - - - -/// A readable name for 1,000,000, for converting microseconds to seconds. -const int one_million = 1000000; - -/// Approximate seconds since the epoch (1/1/1970). About a billion, -/// by my reckoning. We want to keep this a constant (not use the -/// real-world time) to keep simulations repeatable. -const unsigned seconds_since_epoch = 1000000000; - -/// Helper function to convert current elapsed time to seconds and -/// microseconds. -template <class T1, class T2> -void -getElapsedTime(T1 &sec, T2 &usec) -{ - int elapsed_usecs = curTick / Clock::Int::us; - sec = elapsed_usecs / one_million; - usec = elapsed_usecs % one_million; -} - -////////////////////////////////////////////////////////////////////// -// -// The following emulation functions are generic, but need to be -// templated to account for differences in types, constants, etc. -// -////////////////////////////////////////////////////////////////////// - -/// Target ioctl() handler. For the most part, programs call ioctl() -/// only to find out if their stdout is a tty, to determine whether to -/// do line or block buffering. -template <class OS> -SyscallReturn -ioctlFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - int fd = xc->getSyscallArg(0); - unsigned req = xc->getSyscallArg(1); - - DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", fd, req); - - if (fd < 0 || process->sim_fd(fd) < 0) { - // doesn't map to any simulator fd: not a valid target fd - return -EBADF; - } - - switch (req) { - case OS::TIOCISATTY: - case OS::TIOCGETP: - case OS::TIOCSETP: - case OS::TIOCSETN: - case OS::TIOCSETC: - case OS::TIOCGETC: - case OS::TIOCGETS: - case OS::TIOCGETA: - return -ENOTTY; - - default: - fatal("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ 0x%llx\n", - fd, req, xc->readPC()); - } -} - -/// Target open() handler. -template <class OS> -SyscallReturn -openFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - std::string path; - - if (xc->getMemPtr()->readString(path, xc->getSyscallArg(0)) != NoFault) - return -EFAULT; - - if (path == "/dev/sysdev0") { - // This is a memory-mapped high-resolution timer device on Alpha. - // We don't support it, so just punt. - warn("Ignoring open(%s, ...)\n", path); - return -ENOENT; - } - - int tgtFlags = xc->getSyscallArg(1); - int mode = xc->getSyscallArg(2); - int hostFlags = 0; - - // translate open flags - for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) { - if (tgtFlags & OS::openFlagTable[i].tgtFlag) { - tgtFlags &= ~OS::openFlagTable[i].tgtFlag; - hostFlags |= OS::openFlagTable[i].hostFlag; - } - } - - // any target flags left? - if (tgtFlags != 0) - warn("Syscall: open: cannot decode flags 0x%x", tgtFlags); - -#ifdef __CYGWIN32__ - hostFlags |= O_BINARY; -#endif - - DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str()); - - // open the file - int fd = open(path.c_str(), hostFlags, mode); - - return (fd == -1) ? -errno : process->alloc_fd(fd); -} - - -/// Target chmod() handler. -template <class OS> -SyscallReturn -chmodFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - std::string path; - - if (xc->getMemPtr()->readString(path, xc->getSyscallArg(0)) != NoFault) - return -EFAULT; - - uint32_t mode = xc->getSyscallArg(1); - mode_t hostMode = 0; - - // XXX translate mode flags via OS::something??? - hostMode = mode; - - // do the chmod - int result = chmod(path.c_str(), hostMode); - if (result < 0) - return -errno; - - return 0; -} - - -/// Target fchmod() handler. -template <class OS> -SyscallReturn -fchmodFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - int fd = xc->getSyscallArg(0); - if (fd < 0 || process->sim_fd(fd) < 0) { - // doesn't map to any simulator fd: not a valid target fd - return -EBADF; - } - - uint32_t mode = xc->getSyscallArg(1); - mode_t hostMode = 0; - - // XXX translate mode flags via OS::someting??? - hostMode = mode; - - // do the fchmod - int result = fchmod(process->sim_fd(fd), hostMode); - if (result < 0) - return -errno; - - return 0; -} - - -/// Target stat() handler. -template <class OS> -SyscallReturn -statFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - std::string path; - - if (xc->getMemPtr()->readString(path, xc->getSyscallArg(0)) != NoFault) - return -EFAULT; - - struct stat hostBuf; - int result = stat(path.c_str(), &hostBuf); - - if (result < 0) - return -errno; - - OS::copyOutStatBuf(xc->getMemPtr(), xc->getSyscallArg(1), &hostBuf); - - return 0; -} - - -/// Target fstat64() handler. -template <class OS> -SyscallReturn -fstat64Func(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - int fd = xc->getSyscallArg(0); - if (fd < 0 || process->sim_fd(fd) < 0) { - // doesn't map to any simulator fd: not a valid target fd - return -EBADF; - } - -#if BSD_HOST - struct stat hostBuf; - int result = fstat(process->sim_fd(fd), &hostBuf); -#else - struct stat64 hostBuf; - int result = fstat64(process->sim_fd(fd), &hostBuf); -#endif - - if (result < 0) - return -errno; - - OS::copyOutStat64Buf(xc->getMemPtr(), fd, xc->getSyscallArg(1), &hostBuf); - - return 0; -} - - -/// Target lstat() handler. -template <class OS> -SyscallReturn -lstatFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - std::string path; - - if (xc->getMemPtr()->readString(path, xc->getSyscallArg(0)) != NoFault) - return -EFAULT; - - struct stat hostBuf; - int result = lstat(path.c_str(), &hostBuf); - - if (result < 0) - return -errno; - - OS::copyOutStatBuf(xc->getMemPtr(), xc->getSyscallArg(1), &hostBuf); - - return 0; -} - -/// Target lstat64() handler. -template <class OS> -SyscallReturn -lstat64Func(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - std::string path; - - if (xc->getMemPtr()->readString(path, xc->getSyscallArg(0)) != NoFault) - return -EFAULT; - -#if BSD_HOST - struct stat hostBuf; - int result = lstat(path.c_str(), &hostBuf); -#else - struct stat64 hostBuf; - int result = lstat64(path.c_str(), &hostBuf); -#endif - - if (result < 0) - return -errno; - - OS::copyOutStat64Buf(xc->getMemPtr(), -1, xc->getSyscallArg(1), &hostBuf); - - return 0; -} - -/// Target fstat() handler. -template <class OS> -SyscallReturn -fstatFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - int fd = process->sim_fd(xc->getSyscallArg(0)); - - DPRINTF(SyscallVerbose, "fstat(%d, ...)\n", fd); - - if (fd < 0) - return -EBADF; - - struct stat hostBuf; - int result = fstat(fd, &hostBuf); - - if (result < 0) - return -errno; - - OS::copyOutStatBuf(xc->getMemPtr(), xc->getSyscallArg(1), &hostBuf); - return 0; -} - - -/// Target statfs() handler. -template <class OS> -SyscallReturn -statfsFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - std::string path; - - if (xc->getMemPtr()->readString(path, xc->getSyscallArg(0)) != NoFault) - return -EFAULT; - - struct statfs hostBuf; - int result = statfs(path.c_str(), &hostBuf); - - if (result < 0) - return -errno; - - OS::copyOutStatfsBuf(xc->getMemPtr(), xc->getSyscallArg(1), &hostBuf); - - return 0; -} - - -/// Target fstatfs() handler. -template <class OS> -SyscallReturn -fstatfsFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - int fd = process->sim_fd(xc->getSyscallArg(0)); - - if (fd < 0) - return -EBADF; - - struct statfs hostBuf; - int result = fstatfs(fd, &hostBuf); - - if (result < 0) - return -errno; - - OS::copyOutStatfsBuf(xc->getMemPtr(), xc->getSyscallArg(1), &hostBuf); - - return 0; -} - - -/// Target writev() handler. -template <class OS> -SyscallReturn -writevFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - int fd = xc->getSyscallArg(0); - if (fd < 0 || process->sim_fd(fd) < 0) { - // doesn't map to any simulator fd: not a valid target fd - return -EBADF; - } - - uint64_t tiov_base = xc->getSyscallArg(1); - size_t count = xc->getSyscallArg(2); - struct iovec hiov[count]; - for (int i = 0; i < count; ++i) - { - typename OS::tgt_iovec tiov; - xc->getMemPtr()->access(Read, tiov_base + i*sizeof(typename OS::tgt_iovec), - &tiov, sizeof(typename OS::tgt_iovec)); - hiov[i].iov_len = gtoh(tiov.iov_len); - hiov[i].iov_base = new char [hiov[i].iov_len]; - xc->getMemPtr()->access(Read, gtoh(tiov.iov_base), - hiov[i].iov_base, hiov[i].iov_len); - } - - int result = writev(process->sim_fd(fd), hiov, count); - - for (int i = 0; i < count; ++i) - { - delete [] (char *)hiov[i].iov_base; - } - - if (result < 0) - return -errno; - - return 0; -} - - -/// Target mmap() handler. -/// -/// We don't really handle mmap(). If the target is mmaping an -/// anonymous region or /dev/zero, we can get away with doing basically -/// nothing (since memory is initialized to zero and the simulator -/// doesn't really check addresses anyway). Always print a warning, -/// since this could be seriously broken if we're not mapping -/// /dev/zero. -// -/// Someday we should explicitly check for /dev/zero in open, flag the -/// file descriptor, and fail (or implement!) a non-anonymous mmap to -/// anything else. -template <class OS> -SyscallReturn -mmapFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) -{ - Addr start = xc->getSyscallArg(0); - uint64_t length = xc->getSyscallArg(1); - // int prot = xc->getSyscallArg(2); - int flags = xc->getSyscallArg(3); - // int fd = p->sim_fd(xc->getSyscallArg(4)); - // int offset = xc->getSyscallArg(5); - - if (start == 0) { - // user didn't give an address... pick one from our "mmap region" - start = p->mmap_end; - p->mmap_end += roundUp(length, TheISA::VMPageSize); - if (p->nxm_start != 0) { - //If we have an nxm space, make sure we haven't colided - assert(p->mmap_end < p->nxm_start); - } - } - - if (!(flags & OS::TGT_MAP_ANONYMOUS)) { - warn("allowing mmap of file @ fd %d. " - "This will break if not /dev/zero.", xc->getSyscallArg(4)); - } - - return start; -} - -/// Target getrlimit() handler. -template <class OS> -SyscallReturn -getrlimitFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - unsigned resource = xc->getSyscallArg(0); - TypedBufferArg<typename OS::rlimit> rlp(xc->getSyscallArg(1)); - - switch (resource) { - case OS::TGT_RLIMIT_STACK: - // max stack size in bytes: make up a number (2MB for now) - rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; - rlp->rlim_cur = htog(rlp->rlim_cur); - rlp->rlim_max = htog(rlp->rlim_max); - break; - - default: - std::cerr << "getrlimitFunc: unimplemented resource " << resource - << std::endl; - abort(); - break; - } - - rlp.copyOut(xc->getMemPtr()); - return 0; -} - -/// Target gettimeofday() handler. -template <class OS> -SyscallReturn -gettimeofdayFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - TypedBufferArg<typename OS::timeval> tp(xc->getSyscallArg(0)); - - getElapsedTime(tp->tv_sec, tp->tv_usec); - tp->tv_sec += seconds_since_epoch; - tp->tv_sec = htog(tp->tv_sec); - tp->tv_usec = htog(tp->tv_usec); - - tp.copyOut(xc->getMemPtr()); - - return 0; -} - - -/// Target utimes() handler. -template <class OS> -SyscallReturn -utimesFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - std::string path; - - if (xc->getMemPtr()->readString(path, xc->getSyscallArg(0)) != NoFault) - return -EFAULT; - - TypedBufferArg<typename OS::timeval [2]> tp(xc->getSyscallArg(1)); - tp.copyIn(xc->getMemPtr()); - - struct timeval hostTimeval[2]; - for (int i = 0; i < 2; ++i) - { - hostTimeval[i].tv_sec = gtoh((*tp)[i].tv_sec); - hostTimeval[i].tv_usec = gtoh((*tp)[i].tv_usec); - } - int result = utimes(path.c_str(), hostTimeval); - - if (result < 0) - return -errno; - - return 0; -} -/// Target getrusage() function. -template <class OS> -SyscallReturn -getrusageFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - int who = xc->getSyscallArg(0); // THREAD, SELF, or CHILDREN - TypedBufferArg<typename OS::rusage> rup(xc->getSyscallArg(1)); - - if (who != OS::TGT_RUSAGE_SELF) { - // don't really handle THREAD or CHILDREN, but just warn and - // plow ahead - warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.", - who); - } - - getElapsedTime(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec); - rup->ru_utime.tv_sec = htog(rup->ru_utime.tv_sec); - rup->ru_utime.tv_usec = htog(rup->ru_utime.tv_usec); - - rup->ru_stime.tv_sec = 0; - rup->ru_stime.tv_usec = 0; - rup->ru_maxrss = 0; - rup->ru_ixrss = 0; - rup->ru_idrss = 0; - rup->ru_isrss = 0; - rup->ru_minflt = 0; - rup->ru_majflt = 0; - rup->ru_nswap = 0; - rup->ru_inblock = 0; - rup->ru_oublock = 0; - rup->ru_msgsnd = 0; - rup->ru_msgrcv = 0; - rup->ru_nsignals = 0; - rup->ru_nvcsw = 0; - rup->ru_nivcsw = 0; - - rup.copyOut(xc->getMemPtr()); - - return 0; -} - -#endif // __SIM_SYSCALL_EMUL_HH__ diff --git a/sim/system.cc b/sim/system.cc deleted file mode 100644 index 8820922c1..000000000 --- a/sim/system.cc +++ /dev/null @@ -1,185 +0,0 @@ -#include "base/loader/object_file.hh" -#include "base/loader/symtab.hh" -#include "base/remote_gdb.hh" -#include "cpu/exec_context.hh" -#include "kern/kernel_stats.hh" -#include "mem/functional/memory_control.hh" -#include "mem/functional/physical.hh" -#include "arch/vtophys.hh" -#include "sim/builder.hh" -#include "arch/isa_traits.hh" -#include "sim/byteswap.hh" -#include "sim/system.hh" -#include "base/trace.hh" - -using namespace std; -using namespace TheISA; - -vector<System *> System::systemList; - -int System::numSystemsRunning = 0; - -System::System(Params *p) - : SimObject(p->name), memctrl(p->memctrl), physmem(p->physmem), - init_param(p->init_param), numcpus(0), _params(p) -{ - // add self to global system list - systemList.push_back(this); - - kernelSymtab = new SymbolTable; - debugSymbolTable = new SymbolTable; - - /** - * Load the kernel code into memory - */ - // Load kernel code - kernel = createObjectFile(params()->kernel_path); - if (kernel == NULL) - fatal("Could not load kernel file %s", params()->kernel_path); - - // Load program sections into memory - kernel->loadSections(physmem, true); - - // setup entry points - kernelStart = kernel->textBase(); - kernelEnd = kernel->bssBase() + kernel->bssSize(); - kernelEntry = kernel->entryPoint(); - - // load symbols - if (!kernel->loadGlobalSymbols(kernelSymtab)) - panic("could not load kernel symbols\n"); - - if (!kernel->loadLocalSymbols(kernelSymtab)) - panic("could not load kernel local symbols\n"); - - if (!kernel->loadGlobalSymbols(debugSymbolTable)) - panic("could not load kernel symbols\n"); - - if (!kernel->loadLocalSymbols(debugSymbolTable)) - panic("could not load kernel local symbols\n"); - - DPRINTF(Loader, "Kernel start = %#x\n", kernelStart); - DPRINTF(Loader, "Kernel end = %#x\n", kernelEnd); - DPRINTF(Loader, "Kernel entry = %#x\n", kernelEntry); - DPRINTF(Loader, "Kernel loaded...\n"); - - // increment the number of running systms - numSystemsRunning++; - - kernelBinning = new Kernel::Binning(this); -} - -System::~System() -{ - delete kernelSymtab; - delete kernel; - - delete kernelBinning; -} - - - - -int rgdb_wait = -1; - -int -System::registerExecContext(ExecContext *xc, int id) -{ - if (id == -1) { - for (id = 0; id < execContexts.size(); id++) { - if (!execContexts[id]) - break; - } - } - - if (execContexts.size() <= id) - execContexts.resize(id + 1); - - if (execContexts[id]) - panic("Cannot have two CPUs with the same id (%d)\n", id); - - execContexts[id] = xc; - numcpus++; - - RemoteGDB *rgdb = new RemoteGDB(this, xc); - GDBListener *gdbl = new GDBListener(rgdb, 7000 + id); - gdbl->listen(); - /** - * Uncommenting this line waits for a remote debugger to connect - * to the simulator before continuing. - */ - if (rgdb_wait != -1 && rgdb_wait == id) - gdbl->accept(); - - if (remoteGDB.size() <= id) { - remoteGDB.resize(id + 1); - } - - remoteGDB[id] = rgdb; - - return id; -} - -void -System::startup() -{ - int i; - for (i = 0; i < execContexts.size(); i++) - execContexts[i]->activate(0); -} - -void -System::replaceExecContext(ExecContext *xc, int id) -{ - if (id >= execContexts.size()) { - panic("replaceExecContext: bad id, %d >= %d\n", - id, execContexts.size()); - } - - execContexts[id] = xc; - remoteGDB[id]->replaceExecContext(xc); -} - -void -System::regStats() -{ - kernelBinning->regStats(name() + ".kern"); -} - -void -System::serialize(ostream &os) -{ - kernelBinning->serialize(os); - - kernelSymtab->serialize("kernel_symtab", os); -} - - -void -System::unserialize(Checkpoint *cp, const string §ion) -{ - kernelBinning->unserialize(cp, section); - - kernelSymtab->unserialize("kernel_symtab", cp, section); -} - -void -System::printSystems() -{ - vector<System *>::iterator i = systemList.begin(); - vector<System *>::iterator end = systemList.end(); - for (; i != end; ++i) { - System *sys = *i; - cerr << "System " << sys->name() << ": " << hex << sys << endl; - } -} - -extern "C" -void -printSystems() -{ - System::printSystems(); -} - -DEFINE_SIM_OBJECT_CLASS_NAME("System", System) - diff --git a/sim/system.hh b/sim/system.hh deleted file mode 100644 index ea482a102..000000000 --- a/sim/system.hh +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright (c) 2002-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __SYSTEM_HH__ -#define __SYSTEM_HH__ - -#include <string> -#include <vector> - -#include "base/statistics.hh" -#include "base/loader/symtab.hh" -#include "cpu/pc_event.hh" -#include "kern/system_events.hh" -#include "sim/sim_object.hh" - -class BaseCPU; -class ExecContext; -class GDBListener; -class MemoryController; -class ObjectFile; -class PhysicalMemory; -class Platform; -class RemoteGDB; -namespace Kernel { class Binning; } - -class System : public SimObject -{ - public: - MemoryController *memctrl; - PhysicalMemory *physmem; - Platform *platform; - PCEventQueue pcEventQueue; - uint64_t init_param; - - std::vector<ExecContext *> execContexts; - int numcpus; - - int getNumCPUs() - { - if (numcpus != execContexts.size()) - panic("cpu array not fully populated!"); - - return numcpus; - } - - /** kernel symbol table */ - SymbolTable *kernelSymtab; - - /** Object pointer for the kernel code */ - ObjectFile *kernel; - - /** Begining of kernel code */ - Addr kernelStart; - - /** End of kernel code */ - Addr kernelEnd; - - /** Entry point in the kernel to start at */ - Addr kernelEntry; - - Kernel::Binning *kernelBinning; - - protected: - - /** - * Fix up an address used to match PCs for hooking simulator - * events on to target function executions. See comment in - * system.cc for details. - */ - virtual Addr fixFuncEventAddr(Addr addr) = 0; - - /** - * Add a function-based event to the given function, to be looked - * up in the specified symbol table. - */ - template <class T> - T *System::addFuncEvent(SymbolTable *symtab, const char *lbl) - { - Addr addr = 0; // initialize only to avoid compiler warning - - if (symtab->findAddress(lbl, addr)) { - T *ev = new T(&pcEventQueue, lbl, fixFuncEventAddr(addr)); - return ev; - } - - return NULL; - } - - /** Add a function-based event to kernel code. */ - template <class T> - T *System::addKernelFuncEvent(const char *lbl) - { - return addFuncEvent<T>(kernelSymtab, lbl); - } - - public: - std::vector<RemoteGDB *> remoteGDB; - std::vector<GDBListener *> gdbListen; - virtual bool breakpoint() = 0; - - public: - struct Params - { - std::string name; - Tick boot_cpu_frequency; - MemoryController *memctrl; - PhysicalMemory *physmem; - uint64_t init_param; - bool bin; - std::vector<std::string> binned_fns; - bool bin_int; - - std::string kernel_path; - std::string readfile; - }; - - protected: - Params *_params; - - public: - System(Params *p); - ~System(); - - void startup(); - - const Params *params() const { return (const Params *)_params; } - - public: - /** - * Returns the addess the kernel starts at. - * @return address the kernel starts at - */ - Addr getKernelStart() const { return kernelStart; } - - /** - * Returns the addess the kernel ends at. - * @return address the kernel ends at - */ - Addr getKernelEnd() const { return kernelEnd; } - - /** - * Returns the addess the entry point to the kernel code. - * @return entry point of the kernel code - */ - Addr getKernelEntry() const { return kernelEntry; } - - int registerExecContext(ExecContext *xc, int xcIndex); - void replaceExecContext(ExecContext *xc, int xcIndex); - - void regStats(); - void serialize(std::ostream &os); - void unserialize(Checkpoint *cp, const std::string §ion); - - public: - //////////////////////////////////////////// - // - // STATIC GLOBAL SYSTEM LIST - // - //////////////////////////////////////////// - - static std::vector<System *> systemList; - static int numSystemsRunning; - - static void printSystems(); - - -}; - -#endif // __SYSTEM_HH__ diff --git a/sim/vptr.hh b/sim/vptr.hh deleted file mode 100644 index 0ec452f25..000000000 --- a/sim/vptr.hh +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __ARCH_ALPHA_VPTR_HH__ -#define __ARCH_ALPHA_VPTR_HH__ - -#include "arch/vtophys.hh" -#include "arch/isa_traits.hh" - -class ExecContext; - -template <class T> -class VPtr -{ - public: - typedef T Type; - - private: - ExecContext *xc; - Addr ptr; - - public: - ExecContext *GetXC() const { return xc; } - Addr GetPointer() const { return ptr; } - - public: - explicit VPtr(ExecContext *_xc, Addr p = 0) : xc(_xc), ptr(p) { } - template <class U> - VPtr(const VPtr<U> &vp) : xc(vp.GetXC()), ptr(vp.GetPointer()) {} - ~VPtr() {} - - bool operator!() const - { - return ptr == 0; - } - - VPtr<T> operator+(int offset) - { - VPtr<T> ptr(*this); - ptr += offset; - - return ptr; - } - - const VPtr<T> &operator+=(int offset) - { - ptr += offset; - assert((ptr & (TheISA::PageBytes - 1)) + sizeof(T) - < TheISA::PageBytes); - - return *this; - } - - const VPtr<T> &operator=(Addr p) - { - assert((p & (TheISA::PageBytes - 1)) + sizeof(T) - < TheISA::PageBytes); - ptr = p; - - return *this; - } - - template <class U> - const VPtr<T> &operator=(const VPtr<U> &vp) - { - xc = vp.GetXC(); - ptr = vp.GetPointer(); - - return *this; - } - - operator T *() - { - void *addr = vtomem(xc, ptr, sizeof(T)); - return (T *)addr; - } - - T *operator->() - { - void *addr = vtomem(xc, ptr, sizeof(T)); - return (T *)addr; - } - - T &operator*() - { - void *addr = vtomem(xc, ptr, sizeof(T)); - return *(T *)addr; - } -}; - -#endif // __ARCH_ALPHA_VPTR_HH__ diff --git a/Doxyfile b/src/Doxyfile index 38116f6b0..38116f6b0 100644 --- a/Doxyfile +++ b/src/Doxyfile diff --git a/src/SConscript b/src/SConscript new file mode 100644 index 000000000..268bcc745 --- /dev/null +++ b/src/SConscript @@ -0,0 +1,400 @@ +# -*- mode:python -*- + +# Copyright (c) 2004-2005 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +import os +import sys +from os.path import isdir + +# This file defines how to build a particular configuration of M5 +# based on variable settings in the 'env' build environment. + +# Import build environment variable from SConstruct. +Import('env') + +################################################### +# +# Define needed sources. +# +################################################### + +# Base sources used by all configurations. + +base_sources = Split(''' + base/circlebuf.cc + base/copyright.cc + base/cprintf.cc + base/embedfile.cc + base/fast_alloc.cc + base/fifo_buffer.cc + base/hostinfo.cc + base/hybrid_pred.cc + base/inifile.cc + base/intmath.cc + base/match.cc + base/misc.cc + base/output.cc + base/pollevent.cc + base/range.cc + base/random.cc + base/sat_counter.cc + base/serializer.cc + base/socket.cc + base/statistics.cc + base/str.cc + base/time.cc + base/trace.cc + base/traceflags.cc + base/userinfo.cc + base/compression/lzss_compression.cc + base/loader/aout_object.cc + base/loader/ecoff_object.cc + base/loader/elf_object.cc + base/loader/object_file.cc + base/loader/symtab.cc + base/stats/events.cc + base/stats/statdb.cc + base/stats/visit.cc + base/stats/text.cc + + cpu/activity.cc + cpu/base.cc + cpu/cpu_exec_context.cc + cpu/cpuevent.cc + cpu/exetrace.cc + cpu/op_class.cc + cpu/pc_event.cc + cpu/quiesce_event.cc + cpu/static_inst.cc + cpu/sampler/sampler.cc + + mem/bridge.cc + mem/bus.cc + mem/connector.cc + mem/mem_object.cc + mem/packet.cc + mem/physical.cc + mem/port.cc + mem/request.cc + + python/pyconfig.cc + python/embedded_py.cc + + sim/builder.cc + sim/configfile.cc + sim/debug.cc + sim/eventq.cc + sim/faults.cc + sim/main.cc + sim/param.cc + sim/profile.cc + sim/root.cc + sim/serialize.cc + sim/sim_events.cc + sim/sim_exit.cc + sim/sim_object.cc + sim/startup.cc + sim/stat_context.cc + sim/stat_control.cc + sim/system.cc + sim/trace_context.cc + ''') + +# Old FullCPU sources +full_cpu_sources = Split(''' + encumbered/cpu/full/bpred.cc + encumbered/cpu/full/commit.cc + encumbered/cpu/full/cpu.cc + encumbered/cpu/full/create_vector.cc + encumbered/cpu/full/cv_spec_state.cc + encumbered/cpu/full/dd_queue.cc + encumbered/cpu/full/dep_link.cc + encumbered/cpu/full/dispatch.cc + encumbered/cpu/full/dyn_inst.cc + encumbered/cpu/full/execute.cc + encumbered/cpu/full/fetch.cc + encumbered/cpu/full/floss_reasons.cc + encumbered/cpu/full/fu_pool.cc + encumbered/cpu/full/inst_fifo.cc + encumbered/cpu/full/instpipe.cc + encumbered/cpu/full/issue.cc + encumbered/cpu/full/ls_queue.cc + encumbered/cpu/full/machine_queue.cc + encumbered/cpu/full/pipetrace.cc + encumbered/cpu/full/readyq.cc + encumbered/cpu/full/reg_info.cc + encumbered/cpu/full/rob_station.cc + encumbered/cpu/full/spec_memory.cc + encumbered/cpu/full/spec_state.cc + encumbered/cpu/full/storebuffer.cc + encumbered/cpu/full/writeback.cc + encumbered/cpu/full/iq/iq_station.cc + encumbered/cpu/full/iq/iqueue.cc + encumbered/cpu/full/iq/segmented/chain_info.cc + encumbered/cpu/full/iq/segmented/chain_wire.cc + encumbered/cpu/full/iq/segmented/iq_seg.cc + encumbered/cpu/full/iq/segmented/iq_segmented.cc + encumbered/cpu/full/iq/segmented/seg_chain.cc + encumbered/cpu/full/iq/seznec/iq_seznec.cc + encumbered/cpu/full/iq/standard/iq_standard.cc + ''') + +trace_reader_sources = Split(''' + cpu/trace/reader/mem_trace_reader.cc + cpu/trace/reader/ibm_reader.cc + cpu/trace/reader/itx_reader.cc + cpu/trace/reader/m5_reader.cc + cpu/trace/opt_cpu.cc + cpu/trace/trace_cpu.cc + ''') + + + +# MySql sources +mysql_sources = Split(''' + base/mysql.cc + base/stats/mysql.cc + ''') + +# Full-system sources +full_system_sources = Split(''' + base/crc.cc + base/inet.cc + base/remote_gdb.cc + + cpu/intr_control.cc + cpu/profile.cc + + dev/alpha_console.cc + dev/baddev.cc + dev/disk_image.cc + dev/etherbus.cc + dev/etherdump.cc + dev/etherint.cc + dev/etherlink.cc + dev/etherpkt.cc + dev/ethertap.cc + dev/ide_ctrl.cc + dev/ide_disk.cc + dev/io_device.cc + dev/isa_fake.cc + dev/ns_gige.cc + dev/pciconfigall.cc + dev/pcidev.cc + dev/pcifake.cc + dev/pktfifo.cc + dev/platform.cc + dev/simconsole.cc + dev/simple_disk.cc + dev/sinic.cc + dev/tsunami.cc + dev/tsunami_cchip.cc + dev/tsunami_io.cc + dev/tsunami_fake.cc + dev/tsunami_pchip.cc + + dev/uart.cc + dev/uart8250.cc + + kern/kernel_binning.cc + kern/kernel_stats.cc + kern/system_events.cc + kern/linux/events.cc + kern/linux/linux_syscalls.cc + kern/linux/printk.cc + + mem/vport.cc + + sim/pseudo_inst.cc + ''') + + +if env['TARGET_ISA'] == 'alpha': + full_system_sources += Split(''' + kern/tru64/dump_mbuf.cc + kern/tru64/printf.cc + kern/tru64/tru64_events.cc + kern/tru64/tru64_syscalls.cc + ''') + +# turbolaser encumbered sources +turbolaser_sources = Split(''' + encumbered/dev/dma.cc + encumbered/dev/etherdev.cc + encumbered/dev/scsi.cc + encumbered/dev/scsi_ctrl.cc + encumbered/dev/scsi_disk.cc + encumbered/dev/scsi_none.cc + encumbered/dev/tlaser_clock.cc + encumbered/dev/tlaser_ipi.cc + encumbered/dev/tlaser_mbox.cc + encumbered/dev/tlaser_mc146818.cc + encumbered/dev/tlaser_node.cc + encumbered/dev/tlaser_pcia.cc + encumbered/dev/tlaser_pcidev.cc + encumbered/dev/tlaser_serial.cc + encumbered/dev/turbolaser.cc + encumbered/dev/uart8530.cc + ''') + +# Syscall emulation (non-full-system) sources +syscall_emulation_sources = Split(''' + mem/translating_port.cc + mem/page_table.cc + sim/process.cc + sim/syscall_emul.cc + ''') + +#if env['TARGET_ISA'] == 'alpha': +# syscall_emulation_sources += Split(''' +# kern/tru64/tru64.cc +# ''') + +alpha_eio_sources = Split(''' + encumbered/eio/exolex.cc + encumbered/eio/libexo.cc + encumbered/eio/eio.cc + ''') + +if env['TARGET_ISA'] == 'ALPHA_ISA': + syscall_emulation_sources += alpha_eio_sources + +memtest_sources = Split(''' + cpu/memtest/memtest.cc + ''') + +# Add a flag defining what THE_ISA should be for all compilation +env.Append(CPPDEFINES=[('THE_ISA','%s_ISA' % env['TARGET_ISA'].upper())]) + +arch_sources = SConscript('arch/SConscript', + exports = 'env', duplicate = False) + +cpu_sources = SConscript('cpu/SConscript', + exports = 'env', duplicate = False) + +# This is outside of cpu/SConscript since the source directory isn't +# underneath 'cpu'. +if 'FullCPU' in env['CPU_MODELS']: + cpu_sources += full_cpu_sources + +# Set up complete list of sources based on configuration. +sources = base_sources + arch_sources + cpu_sources + +if env['FULL_SYSTEM']: + sources += full_system_sources + if env['ALPHA_TLASER']: + sources += turbolaser_sources +else: + sources += syscall_emulation_sources + +if env['USE_MYSQL']: + sources += mysql_sources + +for opt in env.ExportOptions: + env.ConfigFile(opt) + +################################################### +# +# Special build rules. +# +################################################### + +# base/traceflags.{cc,hh} are generated from base/traceflags.py. +# $TARGET.base will expand to "<build-dir>/base/traceflags". +env.Command(Split('base/traceflags.hh base/traceflags.cc'), + 'base/traceflags.py', + 'python $SOURCE $TARGET.base') + +SConscript('python/SConscript', exports = ['env'], duplicate=0) + +# This function adds the specified sources to the given build +# environment, and returns a list of all the corresponding SCons +# Object nodes (including an extra one for date.cc). We explicitly +# add the Object nodes so we can set up special dependencies for +# date.cc. +def make_objs(sources, env): + objs = [env.Object(s) for s in sources] + # make date.cc depend on all other objects so it always gets + # recompiled whenever anything else does + date_obj = env.Object('base/date.cc') + env.Depends(date_obj, objs) + objs.append(date_obj) + return objs + +################################################### +# +# Define binaries. Each different build type (debug, opt, etc.) gets +# a slightly different build environment. +# +################################################### + +# Include file paths are rooted in this directory. SCons will +# automatically expand '.' to refer to both the source directory and +# the corresponding build directory to pick up generated include +# files. +env.Append(CPPPATH='.') + +# Debug binary +debugEnv = env.Copy(OBJSUFFIX='.do') +debugEnv.Label = 'debug' +debugEnv.Append(CCFLAGS=Split('-g3 -gdwarf-2 -O0')) +debugEnv.Append(CPPDEFINES='DEBUG') +tlist = debugEnv.Program(target = 'm5.debug', + source = make_objs(sources, debugEnv)) +debugEnv.M5Binary = tlist[0] + +# Optimized binary +optEnv = env.Copy() +optEnv.Label = 'opt' +optEnv.Append(CCFLAGS=Split('-g -O3')) +tlist = optEnv.Program(target = 'm5.opt', + source = make_objs(sources, optEnv)) +optEnv.M5Binary = tlist[0] + +# "Fast" binary +fastEnv = env.Copy(OBJSUFFIX='.fo') +fastEnv.Label = 'fast' +fastEnv.Append(CCFLAGS=Split('-O3')) +fastEnv.Append(CPPDEFINES='NDEBUG') +fastEnv.Program(target = 'm5.fast.unstripped', + source = make_objs(sources, fastEnv)) +tlist = fastEnv.Command(target = 'm5.fast', + source = 'm5.fast.unstripped', + action = 'strip $SOURCE -o $TARGET') +fastEnv.M5Binary = tlist[0] + +# Profiled binary +profEnv = env.Copy(OBJSUFFIX='.po') +profEnv.Label = 'prof' +profEnv.Append(CCFLAGS=Split('-O3 -g -pg'), LINKFLAGS='-pg') +tlist = profEnv.Program(target = 'm5.prof', + source = make_objs(sources, profEnv)) +profEnv.M5Binary = tlist[0] + +envList = [debugEnv, optEnv, fastEnv, profEnv] + +Return('envList') diff --git a/src/arch/SConscript b/src/arch/SConscript new file mode 100644 index 000000000..9c193207f --- /dev/null +++ b/src/arch/SConscript @@ -0,0 +1,150 @@ +# -*- mode:python -*- + +# Copyright (c) 2006 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +import os.path + +# Import build environment variable from SConstruct. +Import('env') + +# Right now there are no source files immediately in this directory +sources = [] + +################################################################# +# +# ISA "switch header" generation. +# +# Auto-generate arch headers that include the right ISA-specific +# header based on the setting of THE_ISA preprocessor variable. +# +################################################################# + +# List of headers to generate +isa_switch_hdrs = Split(''' + arguments.hh + constants.hh + faults.hh + isa_traits.hh + process.hh + regfile.hh + stacktrace.hh + tlb.hh + types.hh + utility.hh + vtophys.hh + ''') + +# Generate the header. target[0] is the full path of the output +# header to generate. 'source' is a dummy variable, since we get the +# list of ISAs from env['ALL_ISA_LIST']. +def gen_switch_hdr(target, source, env): + fname = str(target[0]) + basename = os.path.basename(fname) + f = open(fname, 'w') + f.write('#include "arch/isa_specific.hh"\n') + cond = '#if' + for isa in env['ALL_ISA_LIST']: + f.write('%s THE_ISA == %s_ISA\n#include "arch/%s/%s"\n' + % (cond, isa.upper(), isa, basename)) + cond = '#elif' + f.write('#else\n#error "THE_ISA not set"\n#endif\n') + f.close() + return 0 + +# String to print when generating header +def gen_switch_hdr_string(target, source, env): + return "Generating ISA switch header " + str(target[0]) + +# Build SCons Action object. 'varlist' specifies env vars that this +# action depends on; when env['ALL_ISA_LIST'] changes these actions +# should get re-executed. +switch_hdr_action = Action(gen_switch_hdr, gen_switch_hdr_string, + varlist=['ALL_ISA_LIST']) + +# Instantiate actions for each header +for hdr in isa_switch_hdrs: + env.Command(hdr, [], switch_hdr_action) + +################################################################# +# +# Include architecture-specific files. +# +################################################################# + +# +# Build a SCons scanner for ISA files +# +import SCons.Scanner + +isa_scanner = SCons.Scanner.Classic("ISAScan", + [".isa", ".ISA"], + "SRCDIR", + r'^\s*##include\s+"([\w/.-]*)"') + +env.Append(SCANNERS = isa_scanner) + +# +# Now create a Builder object that uses isa_parser.py to generate C++ +# output from the ISA description (*.isa) files. +# + +# Convert to File node to fix path +isa_parser = File('isa_parser.py') +cpu_models_file = File('../cpu/cpu_models.py') + +# This sucks in the defintions of the CpuModel objects. +execfile(cpu_models_file.srcnode().abspath) + +# Several files are generated from the ISA description. +# We always get the basic decoder and header file. +isa_desc_gen_files = Split('decoder.cc decoder.hh') +# We also get an execute file for each selected CPU model. +isa_desc_gen_files += [CpuModel.dict[cpu].filename + for cpu in env['CPU_MODELS']] + +# The emitter patches up the sources & targets to include the +# autogenerated files as targets and isa parser itself as a source. +def isa_desc_emitter(target, source, env): + return (isa_desc_gen_files, [isa_parser, cpu_models_file] + source) + +# Pieces are in place, so create the builder. +isa_desc_builder = Builder(action='python2.4 $SOURCES $TARGET.dir $CPU_MODELS', + emitter = isa_desc_emitter) + +env.Append(BUILDERS = { 'ISADesc' : isa_desc_builder }) + +# +# Now include other ISA-specific sources from the ISA subdirectories. +# + +isa = env['TARGET_ISA'] # someday this may be a list of ISAs + +# Let the target architecture define what additional sources it needs +sources += SConscript(os.path.join(isa, 'SConscript'), + exports = 'env', duplicate = False) + +Return('sources') diff --git a/src/arch/alpha/SConscript b/src/arch/alpha/SConscript new file mode 100644 index 000000000..1b20f8b1f --- /dev/null +++ b/src/arch/alpha/SConscript @@ -0,0 +1,93 @@ +# -*- mode:python -*- + +# Copyright (c) 2004-2005 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +import os +import sys +from os.path import isdir + +# This file defines how to build a particular configuration of M5 +# based on variable settings in the 'env' build environment. + +# Import build environment variable from SConstruct. +Import('env') + +################################################### +# +# Define needed sources. +# +################################################### + +# Base sources used by all configurations. +base_sources = Split(''' + faults.cc + isa_traits.cc + ''') + +# Full-system sources +full_system_sources = Split(''' + tlb.cc + arguments.cc + ev5.cc + osfpal.cc + stacktrace.cc + vtophys.cc + system.cc + freebsd/system.cc + linux/system.cc + tru64/system.cc + ''') + + +# Syscall emulation (non-full-system) sources +syscall_emulation_sources = Split(''' + linux/linux.cc + linux/process.cc + tru64/tru64.cc + tru64/process.cc + process.cc + ''') + +# Set up complete list of sources based on configuration. +sources = base_sources + +if env['FULL_SYSTEM']: + sources += full_system_sources +else: + sources += syscall_emulation_sources + +# Convert file names to SCons File objects. This takes care of the +# path relative to the top of the directory tree. +sources = [File(s) for s in sources] + +# Add in files generated by the ISA description. +isa_desc_files = env.ISADesc('isa/main.isa') +# Only non-header files need to be compiled. +isa_desc_sources = [f for f in isa_desc_files if not f.path.endswith('.hh')] +sources += isa_desc_sources + +Return('sources') diff --git a/arch/alpha/aout_machdep.h b/src/arch/alpha/aout_machdep.h index df9d9ac6a..df9d9ac6a 100644 --- a/arch/alpha/aout_machdep.h +++ b/src/arch/alpha/aout_machdep.h diff --git a/src/arch/alpha/arguments.cc b/src/arch/alpha/arguments.cc new file mode 100644 index 000000000..adc371682 --- /dev/null +++ b/src/arch/alpha/arguments.cc @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "arch/alpha/arguments.hh" +#include "arch/alpha/vtophys.hh" +#include "cpu/exec_context.hh" +#include "mem/vport.hh" + +using namespace AlphaISA; + +AlphaArguments::Data::~Data() +{ + while (!data.empty()) { + delete [] data.front(); + data.pop_front(); + } +} + +char * +AlphaArguments::Data::alloc(size_t size) +{ + char *buf = new char[size]; + data.push_back(buf); + return buf; +} + +uint64_t +AlphaArguments::getArg(bool fp) +{ + if (number < 6) { + if (fp) + return xc->readFloatRegBits(16 + number); + else + return xc->readIntReg(16 + number); + } else { + Addr sp = xc->readIntReg(30); + VirtualPort *vp = xc->getVirtPort(xc); + uint64_t arg = vp->read<uint64_t>(sp + (number-6) * sizeof(uint64_t)); + xc->delVirtPort(vp); + return arg; + } +} + diff --git a/src/arch/alpha/arguments.hh b/src/arch/alpha/arguments.hh new file mode 100644 index 000000000..bd1c6cb1d --- /dev/null +++ b/src/arch/alpha/arguments.hh @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ARCH_ALPHA_ARGUMENTS_HH__ +#define __ARCH_ALPHA_ARGUMENTS_HH__ + +#include <assert.h> + +#include "arch/alpha/vtophys.hh" +#include "base/refcnt.hh" +#include "sim/host.hh" + +class ExecContext; + +namespace AlphaISA { + +class AlphaArguments +{ + protected: + ExecContext *xc; + int number; + uint64_t getArg(bool fp = false); + + protected: + class Data : public RefCounted + { + public: + Data(){} + ~Data(); + + private: + std::list<char *> data; + + public: + char *alloc(size_t size); + }; + + RefCountingPtr<Data> data; + + public: + AlphaArguments(ExecContext *ctx, int n = 0) + : xc(ctx), number(n), data(NULL) + { assert(number >= 0); data = new Data;} + AlphaArguments(const AlphaArguments &args) + : xc(args.xc), number(args.number), data(args.data) {} + ~AlphaArguments() {} + + ExecContext *getExecContext() const { return xc; } + + const AlphaArguments &operator=(const AlphaArguments &args) { + xc = args.xc; + number = args.number; + data = args.data; + return *this; + } + + AlphaArguments &operator++() { + ++number; + assert(number >= 0); + return *this; + } + + AlphaArguments operator++(int) { + AlphaArguments args = *this; + ++number; + assert(number >= 0); + return args; + } + + AlphaArguments &operator--() { + --number; + assert(number >= 0); + return *this; + } + + AlphaArguments operator--(int) { + AlphaArguments args = *this; + --number; + assert(number >= 0); + return args; + } + + const AlphaArguments &operator+=(int index) { + number += index; + assert(number >= 0); + return *this; + } + + const AlphaArguments &operator-=(int index) { + number -= index; + assert(number >= 0); + return *this; + } + + AlphaArguments operator[](int index) { + return AlphaArguments(xc, index); + } + + template <class T> + operator T() { + assert(sizeof(T) <= sizeof(uint64_t)); + T data = static_cast<T>(getArg()); + return data; + } + + template <class T> + operator T *() { + T *buf = (T *)data->alloc(sizeof(T)); + CopyData(xc, buf, getArg(), sizeof(T)); + return buf; + } + + operator char *() { + char *buf = data->alloc(2048); + CopyStringOut(xc, buf, getArg(), 2048); + return buf; + } +}; + +}; // namespace AlphaISA + +#endif // __ARCH_ALPHA_ARGUMENTS_HH__ diff --git a/arch/alpha/ecoff_machdep.h b/src/arch/alpha/ecoff_machdep.h index 9341b8ff7..9341b8ff7 100644 --- a/arch/alpha/ecoff_machdep.h +++ b/src/arch/alpha/ecoff_machdep.h diff --git a/src/arch/alpha/ev5.cc b/src/arch/alpha/ev5.cc new file mode 100644 index 000000000..a242282ec --- /dev/null +++ b/src/arch/alpha/ev5.cc @@ -0,0 +1,584 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "arch/alpha/tlb.hh" +#include "arch/alpha/isa_traits.hh" +#include "arch/alpha/osfpal.hh" +#include "base/kgdb.h" +#include "base/remote_gdb.hh" +#include "base/stats/events.hh" +#include "config/full_system.hh" +#include "cpu/base.hh" +#include "cpu/cpu_exec_context.hh" +#include "cpu/exec_context.hh" +#include "kern/kernel_stats.hh" +#include "sim/debug.hh" +#include "sim/sim_events.hh" + +#if FULL_SYSTEM + +using namespace EV5; + +//////////////////////////////////////////////////////////////////////// +// +// Machine dependent functions +// +void +AlphaISA::initCPU(ExecContext *xc, int cpuId) +{ + initIPRs(xc, cpuId); + + xc->setIntReg(16, cpuId); + xc->setIntReg(0, cpuId); + + xc->setPC(xc->readMiscReg(IPR_PAL_BASE) + (new ResetFault)->vect()); + xc->setNextPC(xc->readPC() + sizeof(MachInst)); +} + +//////////////////////////////////////////////////////////////////////// +// +// +// +void +AlphaISA::initIPRs(ExecContext *xc, int cpuId) +{ + for (int i = 0; i < NumInternalProcRegs; ++i) { + xc->setMiscReg(i, 0); + } + + xc->setMiscReg(IPR_PAL_BASE, PalBase); + xc->setMiscReg(IPR_MCSR, 0x6); + xc->setMiscReg(IPR_PALtemp16, cpuId); +} + + +template <class CPU> +void +AlphaISA::processInterrupts(CPU *cpu) +{ + //Check if there are any outstanding interrupts + //Handle the interrupts + int ipl = 0; + int summary = 0; + + cpu->checkInterrupts = false; + + if (cpu->readMiscReg(IPR_ASTRR)) + panic("asynchronous traps not implemented\n"); + + if (cpu->readMiscReg(IPR_SIRR)) { + for (int i = INTLEVEL_SOFTWARE_MIN; + i < INTLEVEL_SOFTWARE_MAX; i++) { + if (cpu->readMiscReg(IPR_SIRR) & (ULL(1) << i)) { + // See table 4-19 of the 21164 hardware reference + ipl = (i - INTLEVEL_SOFTWARE_MIN) + 1; + summary |= (ULL(1) << i); + } + } + } + + uint64_t interrupts = cpu->intr_status(); + + if (interrupts) { + for (int i = INTLEVEL_EXTERNAL_MIN; + i < INTLEVEL_EXTERNAL_MAX; i++) { + if (interrupts & (ULL(1) << i)) { + // See table 4-19 of the 21164 hardware reference + ipl = i; + summary |= (ULL(1) << i); + } + } + } + + if (ipl && ipl > cpu->readMiscReg(IPR_IPLR)) { + cpu->setMiscReg(IPR_ISR, summary); + cpu->setMiscReg(IPR_INTID, ipl); + cpu->trap(new InterruptFault); + DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n", + cpu->readMiscReg(IPR_IPLR), ipl, summary); + } + +} + +template <class CPU> +void +AlphaISA::zeroRegisters(CPU *cpu) +{ + // Insure ISA semantics + // (no longer very clean due to the change in setIntReg() in the + // cpu model. Consider changing later.) + cpu->cpuXC->setIntReg(ZeroReg, 0); + cpu->cpuXC->setFloatReg(ZeroReg, 0.0); +} + +Fault +CPUExecContext::hwrei() +{ + if (!inPalMode()) + return new UnimplementedOpcodeFault; + + setNextPC(readMiscReg(AlphaISA::IPR_EXC_ADDR)); + + if (!misspeculating()) { + if (kernelStats) + kernelStats->hwrei(); + + cpu->checkInterrupts = true; + } + + // FIXME: XXX check for interrupts? XXX + return NoFault; +} + +int +AlphaISA::MiscRegFile::getInstAsid() +{ + return EV5::ITB_ASN_ASN(ipr[IPR_ITB_ASN]); +} + +int +AlphaISA::MiscRegFile::getDataAsid() +{ + return EV5::DTB_ASN_ASN(ipr[IPR_DTB_ASN]); +} + +AlphaISA::MiscReg +AlphaISA::MiscRegFile::readIpr(int idx, Fault &fault, ExecContext *xc) +{ + uint64_t retval = 0; // return value, default 0 + + switch (idx) { + case AlphaISA::IPR_PALtemp0: + case AlphaISA::IPR_PALtemp1: + case AlphaISA::IPR_PALtemp2: + case AlphaISA::IPR_PALtemp3: + case AlphaISA::IPR_PALtemp4: + case AlphaISA::IPR_PALtemp5: + case AlphaISA::IPR_PALtemp6: + case AlphaISA::IPR_PALtemp7: + case AlphaISA::IPR_PALtemp8: + case AlphaISA::IPR_PALtemp9: + case AlphaISA::IPR_PALtemp10: + case AlphaISA::IPR_PALtemp11: + case AlphaISA::IPR_PALtemp12: + case AlphaISA::IPR_PALtemp13: + case AlphaISA::IPR_PALtemp14: + case AlphaISA::IPR_PALtemp15: + case AlphaISA::IPR_PALtemp16: + case AlphaISA::IPR_PALtemp17: + case AlphaISA::IPR_PALtemp18: + case AlphaISA::IPR_PALtemp19: + case AlphaISA::IPR_PALtemp20: + case AlphaISA::IPR_PALtemp21: + case AlphaISA::IPR_PALtemp22: + case AlphaISA::IPR_PALtemp23: + case AlphaISA::IPR_PAL_BASE: + + case AlphaISA::IPR_IVPTBR: + case AlphaISA::IPR_DC_MODE: + case AlphaISA::IPR_MAF_MODE: + case AlphaISA::IPR_ISR: + case AlphaISA::IPR_EXC_ADDR: + case AlphaISA::IPR_IC_PERR_STAT: + case AlphaISA::IPR_DC_PERR_STAT: + case AlphaISA::IPR_MCSR: + case AlphaISA::IPR_ASTRR: + case AlphaISA::IPR_ASTER: + case AlphaISA::IPR_SIRR: + case AlphaISA::IPR_ICSR: + case AlphaISA::IPR_ICM: + case AlphaISA::IPR_DTB_CM: + case AlphaISA::IPR_IPLR: + case AlphaISA::IPR_INTID: + case AlphaISA::IPR_PMCTR: + // no side-effect + retval = ipr[idx]; + break; + + case AlphaISA::IPR_CC: + retval |= ipr[idx] & ULL(0xffffffff00000000); + retval |= xc->getCpuPtr()->curCycle() & ULL(0x00000000ffffffff); + break; + + case AlphaISA::IPR_VA: + retval = ipr[idx]; + break; + + case AlphaISA::IPR_VA_FORM: + case AlphaISA::IPR_MM_STAT: + case AlphaISA::IPR_IFAULT_VA_FORM: + case AlphaISA::IPR_EXC_MASK: + case AlphaISA::IPR_EXC_SUM: + retval = ipr[idx]; + break; + + case AlphaISA::IPR_DTB_PTE: + { + AlphaISA::PTE &pte = xc->getDTBPtr()->index(!xc->misspeculating()); + + retval |= ((u_int64_t)pte.ppn & ULL(0x7ffffff)) << 32; + retval |= ((u_int64_t)pte.xre & ULL(0xf)) << 8; + retval |= ((u_int64_t)pte.xwe & ULL(0xf)) << 12; + retval |= ((u_int64_t)pte.fonr & ULL(0x1)) << 1; + retval |= ((u_int64_t)pte.fonw & ULL(0x1))<< 2; + retval |= ((u_int64_t)pte.asma & ULL(0x1)) << 4; + retval |= ((u_int64_t)pte.asn & ULL(0x7f)) << 57; + } + break; + + // write only registers + case AlphaISA::IPR_HWINT_CLR: + case AlphaISA::IPR_SL_XMIT: + case AlphaISA::IPR_DC_FLUSH: + case AlphaISA::IPR_IC_FLUSH: + case AlphaISA::IPR_ALT_MODE: + case AlphaISA::IPR_DTB_IA: + case AlphaISA::IPR_DTB_IAP: + case AlphaISA::IPR_ITB_IA: + case AlphaISA::IPR_ITB_IAP: + fault = new UnimplementedOpcodeFault; + break; + + default: + // invalid IPR + fault = new UnimplementedOpcodeFault; + break; + } + + return retval; +} + +#ifdef DEBUG +// Cause the simulator to break when changing to the following IPL +int break_ipl = -1; +#endif + +Fault +AlphaISA::MiscRegFile::setIpr(int idx, uint64_t val, ExecContext *xc) +{ + uint64_t old; + + if (xc->misspeculating()) + return NoFault; + + switch (idx) { + case AlphaISA::IPR_PALtemp0: + case AlphaISA::IPR_PALtemp1: + case AlphaISA::IPR_PALtemp2: + case AlphaISA::IPR_PALtemp3: + case AlphaISA::IPR_PALtemp4: + case AlphaISA::IPR_PALtemp5: + case AlphaISA::IPR_PALtemp6: + case AlphaISA::IPR_PALtemp7: + case AlphaISA::IPR_PALtemp8: + case AlphaISA::IPR_PALtemp9: + case AlphaISA::IPR_PALtemp10: + case AlphaISA::IPR_PALtemp11: + case AlphaISA::IPR_PALtemp12: + case AlphaISA::IPR_PALtemp13: + case AlphaISA::IPR_PALtemp14: + case AlphaISA::IPR_PALtemp15: + case AlphaISA::IPR_PALtemp16: + case AlphaISA::IPR_PALtemp17: + case AlphaISA::IPR_PALtemp18: + case AlphaISA::IPR_PALtemp19: + case AlphaISA::IPR_PALtemp20: + case AlphaISA::IPR_PALtemp21: + case AlphaISA::IPR_PALtemp22: + case AlphaISA::IPR_PAL_BASE: + case AlphaISA::IPR_IC_PERR_STAT: + case AlphaISA::IPR_DC_PERR_STAT: + case AlphaISA::IPR_PMCTR: + // write entire quad w/ no side-effect + ipr[idx] = val; + break; + + case AlphaISA::IPR_CC_CTL: + // This IPR resets the cycle counter. We assume this only + // happens once... let's verify that. + assert(ipr[idx] == 0); + ipr[idx] = 1; + break; + + case AlphaISA::IPR_CC: + // This IPR only writes the upper 64 bits. It's ok to write + // all 64 here since we mask out the lower 32 in rpcc (see + // isa_desc). + ipr[idx] = val; + break; + + case AlphaISA::IPR_PALtemp23: + // write entire quad w/ no side-effect + old = ipr[idx]; + ipr[idx] = val; + if (xc->getKernelStats()) + xc->getKernelStats()->context(old, val, xc); + break; + + case AlphaISA::IPR_DTB_PTE: + // write entire quad w/ no side-effect, tag is forthcoming + ipr[idx] = val; + break; + + case AlphaISA::IPR_EXC_ADDR: + // second least significant bit in PC is always zero + ipr[idx] = val & ~2; + break; + + case AlphaISA::IPR_ASTRR: + case AlphaISA::IPR_ASTER: + // only write least significant four bits - privilege mask + ipr[idx] = val & 0xf; + break; + + case AlphaISA::IPR_IPLR: +#ifdef DEBUG + if (break_ipl != -1 && break_ipl == (val & 0x1f)) + debug_break(); +#endif + + // only write least significant five bits - interrupt level + ipr[idx] = val & 0x1f; + if (xc->getKernelStats()) + xc->getKernelStats()->swpipl(ipr[idx]); + break; + + case AlphaISA::IPR_DTB_CM: + if (val & 0x18) { + if (xc->getKernelStats()) + xc->getKernelStats()->mode(Kernel::user, xc); + } else { + if (xc->getKernelStats()) + xc->getKernelStats()->mode(Kernel::kernel, xc); + } + + case AlphaISA::IPR_ICM: + // only write two mode bits - processor mode + ipr[idx] = val & 0x18; + break; + + case AlphaISA::IPR_ALT_MODE: + // only write two mode bits - processor mode + ipr[idx] = val & 0x18; + break; + + case AlphaISA::IPR_MCSR: + // more here after optimization... + ipr[idx] = val; + break; + + case AlphaISA::IPR_SIRR: + // only write software interrupt mask + ipr[idx] = val & 0x7fff0; + break; + + case AlphaISA::IPR_ICSR: + ipr[idx] = val & ULL(0xffffff0300); + break; + + case AlphaISA::IPR_IVPTBR: + case AlphaISA::IPR_MVPTBR: + ipr[idx] = val & ULL(0xffffffffc0000000); + break; + + case AlphaISA::IPR_DC_TEST_CTL: + ipr[idx] = val & 0x1ffb; + break; + + case AlphaISA::IPR_DC_MODE: + case AlphaISA::IPR_MAF_MODE: + ipr[idx] = val & 0x3f; + break; + + case AlphaISA::IPR_ITB_ASN: + ipr[idx] = val & 0x7f0; + break; + + case AlphaISA::IPR_DTB_ASN: + ipr[idx] = val & ULL(0xfe00000000000000); + break; + + case AlphaISA::IPR_EXC_SUM: + case AlphaISA::IPR_EXC_MASK: + // any write to this register clears it + ipr[idx] = 0; + break; + + case AlphaISA::IPR_INTID: + case AlphaISA::IPR_SL_RCV: + case AlphaISA::IPR_MM_STAT: + case AlphaISA::IPR_ITB_PTE_TEMP: + case AlphaISA::IPR_DTB_PTE_TEMP: + // read-only registers + return new UnimplementedOpcodeFault; + + case AlphaISA::IPR_HWINT_CLR: + case AlphaISA::IPR_SL_XMIT: + case AlphaISA::IPR_DC_FLUSH: + case AlphaISA::IPR_IC_FLUSH: + // the following are write only + ipr[idx] = val; + break; + + case AlphaISA::IPR_DTB_IA: + // really a control write + ipr[idx] = 0; + + xc->getDTBPtr()->flushAll(); + break; + + case AlphaISA::IPR_DTB_IAP: + // really a control write + ipr[idx] = 0; + + xc->getDTBPtr()->flushProcesses(); + break; + + case AlphaISA::IPR_DTB_IS: + // really a control write + ipr[idx] = val; + + xc->getDTBPtr()->flushAddr(val, + DTB_ASN_ASN(ipr[AlphaISA::IPR_DTB_ASN])); + break; + + case AlphaISA::IPR_DTB_TAG: { + struct AlphaISA::PTE pte; + + // FIXME: granularity hints NYI... + if (DTB_PTE_GH(ipr[AlphaISA::IPR_DTB_PTE]) != 0) + panic("PTE GH field != 0"); + + // write entire quad + ipr[idx] = val; + + // construct PTE for new entry + pte.ppn = DTB_PTE_PPN(ipr[AlphaISA::IPR_DTB_PTE]); + pte.xre = DTB_PTE_XRE(ipr[AlphaISA::IPR_DTB_PTE]); + pte.xwe = DTB_PTE_XWE(ipr[AlphaISA::IPR_DTB_PTE]); + pte.fonr = DTB_PTE_FONR(ipr[AlphaISA::IPR_DTB_PTE]); + pte.fonw = DTB_PTE_FONW(ipr[AlphaISA::IPR_DTB_PTE]); + pte.asma = DTB_PTE_ASMA(ipr[AlphaISA::IPR_DTB_PTE]); + pte.asn = DTB_ASN_ASN(ipr[AlphaISA::IPR_DTB_ASN]); + + // insert new TAG/PTE value into data TLB + xc->getDTBPtr()->insert(val, pte); + } + break; + + case AlphaISA::IPR_ITB_PTE: { + struct AlphaISA::PTE pte; + + // FIXME: granularity hints NYI... + if (ITB_PTE_GH(val) != 0) + panic("PTE GH field != 0"); + + // write entire quad + ipr[idx] = val; + + // construct PTE for new entry + pte.ppn = ITB_PTE_PPN(val); + pte.xre = ITB_PTE_XRE(val); + pte.xwe = 0; + pte.fonr = ITB_PTE_FONR(val); + pte.fonw = ITB_PTE_FONW(val); + pte.asma = ITB_PTE_ASMA(val); + pte.asn = ITB_ASN_ASN(ipr[AlphaISA::IPR_ITB_ASN]); + + // insert new TAG/PTE value into data TLB + xc->getITBPtr()->insert(ipr[AlphaISA::IPR_ITB_TAG], pte); + } + break; + + case AlphaISA::IPR_ITB_IA: + // really a control write + ipr[idx] = 0; + + xc->getITBPtr()->flushAll(); + break; + + case AlphaISA::IPR_ITB_IAP: + // really a control write + ipr[idx] = 0; + + xc->getITBPtr()->flushProcesses(); + break; + + case AlphaISA::IPR_ITB_IS: + // really a control write + ipr[idx] = val; + + xc->getITBPtr()->flushAddr(val, + ITB_ASN_ASN(ipr[AlphaISA::IPR_ITB_ASN])); + break; + + default: + // invalid IPR + return new UnimplementedOpcodeFault; + } + + // no error... + return NoFault; +} + +void +AlphaISA::copyIprs(ExecContext *src, ExecContext *dest) +{ + for (int i = IPR_Base_DepTag; i < NumInternalProcRegs; ++i) { + dest->setMiscReg(i, src->readMiscReg(i)); + } +} + +/** + * Check for special simulator handling of specific PAL calls. + * If return value is false, actual PAL call will be suppressed. + */ +bool +CPUExecContext::simPalCheck(int palFunc) +{ + if (kernelStats) + kernelStats->callpal(palFunc, proxy); + + switch (palFunc) { + case PAL::halt: + halt(); + if (--System::numSystemsRunning == 0) + new SimExitEvent("all cpus halted"); + break; + + case PAL::bpt: + case PAL::bugchk: + if (system->breakpoint()) + return false; + break; + } + + return true; +} + +#endif // FULL_SYSTEM diff --git a/arch/alpha/ev5.hh b/src/arch/alpha/ev5.hh index 7c8465cfb..7c8465cfb 100644 --- a/arch/alpha/ev5.hh +++ b/src/arch/alpha/ev5.hh diff --git a/arch/alpha/faults.cc b/src/arch/alpha/faults.cc index 0083aa9f3..0083aa9f3 100644 --- a/arch/alpha/faults.cc +++ b/src/arch/alpha/faults.cc diff --git a/arch/alpha/faults.hh b/src/arch/alpha/faults.hh index e8ccc6b79..e8ccc6b79 100644 --- a/arch/alpha/faults.hh +++ b/src/arch/alpha/faults.hh diff --git a/src/arch/alpha/freebsd/system.cc b/src/arch/alpha/freebsd/system.cc new file mode 100644 index 000000000..3e50fb9a5 --- /dev/null +++ b/src/arch/alpha/freebsd/system.cc @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * Modifications for the FreeBSD kernel. + * Based on kern/linux/linux_system.cc. + * + */ + +#include "arch/alpha/system.hh" +#include "arch/alpha/freebsd/system.hh" +#include "base/loader/symtab.hh" +#include "cpu/exec_context.hh" +#include "mem/physical.hh" +#include "mem/port.hh" +#include "arch/isa_traits.hh" +#include "sim/builder.hh" +#include "sim/byteswap.hh" +#include "arch/vtophys.hh" + +#define TIMER_FREQUENCY 1193180 + +using namespace std; +using namespace AlphaISA; + +FreebsdAlphaSystem::FreebsdAlphaSystem(Params *p) + : AlphaSystem(p) +{ + /** + * Any time DELAY is called just skip the function. + * Shouldn't we actually emulate the delay? + */ + skipDelayEvent = addKernelFuncEvent<SkipFuncEvent>("DELAY"); + skipCalibrateClocks = + addKernelFuncEvent<SkipCalibrateClocksEvent>("calibrate_clocks"); +} + + +FreebsdAlphaSystem::~FreebsdAlphaSystem() +{ + delete skipDelayEvent; + delete skipCalibrateClocks; +} + + +void +FreebsdAlphaSystem::doCalibrateClocks(ExecContext *xc) +{ + Addr ppc_vaddr = 0; + Addr timer_vaddr = 0; + + ppc_vaddr = (Addr)xc->readIntReg(ArgumentReg1); + timer_vaddr = (Addr)xc->readIntReg(ArgumentReg2); + + virtPort.write(ppc_vaddr, (uint32_t)Clock::Frequency); + virtPort.write(timer_vaddr, (uint32_t)TIMER_FREQUENCY); +} + + +void +FreebsdAlphaSystem::SkipCalibrateClocksEvent::process(ExecContext *xc) +{ + SkipFuncEvent::process(xc); + ((FreebsdAlphaSystem *)xc->getSystemPtr())->doCalibrateClocks(xc); +} + + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(FreebsdAlphaSystem) + + Param<Tick> boot_cpu_frequency; + SimObjectParam<PhysicalMemory *> physmem; + + Param<string> kernel; + Param<string> console; + Param<string> pal; + + Param<string> boot_osflags; + Param<string> readfile; + Param<unsigned int> init_param; + + Param<uint64_t> system_type; + Param<uint64_t> system_rev; + + Param<bool> bin; + VectorParam<string> binned_fns; + Param<bool> bin_int; + +END_DECLARE_SIM_OBJECT_PARAMS(FreebsdAlphaSystem) + +BEGIN_INIT_SIM_OBJECT_PARAMS(FreebsdAlphaSystem) + + INIT_PARAM(boot_cpu_frequency, "Frequency of the boot CPU"), + INIT_PARAM(physmem, "phsyical memory"), + INIT_PARAM(kernel, "file that contains the kernel code"), + INIT_PARAM(console, "file that contains the console code"), + INIT_PARAM(pal, "file that contains palcode"), + INIT_PARAM_DFLT(boot_osflags, "flags to pass to the kernel during boot", + "a"), + INIT_PARAM_DFLT(readfile, "file to read startup script from", ""), + INIT_PARAM_DFLT(init_param, "numerical value to pass into simulator", 0), + INIT_PARAM_DFLT(system_type, "Type of system we are emulating", 34), + INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 1<<10), + INIT_PARAM_DFLT(bin, "is this system to be binned", false), + INIT_PARAM(binned_fns, "functions to be broken down and binned"), + INIT_PARAM_DFLT(bin_int, "is interrupt code binned seperately?", true) + +END_INIT_SIM_OBJECT_PARAMS(FreebsdAlphaSystem) + +CREATE_SIM_OBJECT(FreebsdAlphaSystem) +{ + AlphaSystem::Params *p = new AlphaSystem::Params; + p->name = getInstanceName(); + p->boot_cpu_frequency = boot_cpu_frequency; + p->physmem = physmem; + p->kernel_path = kernel; + p->console_path = console; + p->palcode = pal; + p->boot_osflags = boot_osflags; + p->init_param = init_param; + p->readfile = readfile; + p->system_type = system_type; + p->system_rev = system_rev; + p->bin = bin; + p->binned_fns = binned_fns; + p->bin_int = bin_int; + return new FreebsdAlphaSystem(p); +} + +REGISTER_SIM_OBJECT("FreebsdAlphaSystem", FreebsdAlphaSystem) + diff --git a/arch/alpha/freebsd/system.hh b/src/arch/alpha/freebsd/system.hh index 5d996955e..5d996955e 100644 --- a/arch/alpha/freebsd/system.hh +++ b/src/arch/alpha/freebsd/system.hh diff --git a/src/arch/alpha/isa/branch.isa b/src/arch/alpha/isa/branch.isa new file mode 100644 index 000000000..f9a425ed2 --- /dev/null +++ b/src/arch/alpha/isa/branch.isa @@ -0,0 +1,264 @@ +// -*- mode:c++ -*- + +// Copyright (c) 2003-2005 The Regents of The University of Michigan +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +//////////////////////////////////////////////////////////////////// +// +// Control transfer instructions +// + +output header {{ + + /** + * Base class for instructions whose disassembly is not purely a + * function of the machine instruction (i.e., it depends on the + * PC). This class overrides the disassemble() method to check + * the PC and symbol table values before re-using a cached + * disassembly string. This is necessary for branches and jumps, + * where the disassembly string includes the target address (which + * may depend on the PC and/or symbol table). + */ + class PCDependentDisassembly : public AlphaStaticInst + { + protected: + /// Cached program counter from last disassembly + mutable Addr cachedPC; + /// Cached symbol table pointer from last disassembly + mutable const SymbolTable *cachedSymtab; + + /// Constructor + PCDependentDisassembly(const char *mnem, ExtMachInst _machInst, + OpClass __opClass) + : AlphaStaticInst(mnem, _machInst, __opClass), + cachedPC(0), cachedSymtab(0) + { + } + + const std::string & + disassemble(Addr pc, const SymbolTable *symtab) const; + }; + + /** + * Base class for branches (PC-relative control transfers), + * conditional or unconditional. + */ + class Branch : public PCDependentDisassembly + { + protected: + /// Displacement to target address (signed). + int32_t disp; + + /// Constructor. + Branch(const char *mnem, ExtMachInst _machInst, OpClass __opClass) + : PCDependentDisassembly(mnem, _machInst, __opClass), + disp(BRDISP << 2) + { + } + + Addr branchTarget(Addr branchPC) const; + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; + + /** + * Base class for jumps (register-indirect control transfers). In + * the Alpha ISA, these are always unconditional. + */ + class Jump : public PCDependentDisassembly + { + protected: + + /// Displacement to target address (signed). + int32_t disp; + + public: + /// Constructor + Jump(const char *mnem, ExtMachInst _machInst, OpClass __opClass) + : PCDependentDisassembly(mnem, _machInst, __opClass), + disp(BRDISP) + { + } + + Addr branchTarget(ExecContext *xc) const; + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; +}}; + +output decoder {{ + Addr + Branch::branchTarget(Addr branchPC) const + { + return branchPC + 4 + disp; + } + + Addr + Jump::branchTarget(ExecContext *xc) const + { + Addr NPC = xc->readPC() + 4; + uint64_t Rb = xc->readIntReg(_srcRegIdx[0]); + return (Rb & ~3) | (NPC & 1); + } + + const std::string & + PCDependentDisassembly::disassemble(Addr pc, + const SymbolTable *symtab) const + { + if (!cachedDisassembly || + pc != cachedPC || symtab != cachedSymtab) + { + if (cachedDisassembly) + delete cachedDisassembly; + + cachedDisassembly = + new std::string(generateDisassembly(pc, symtab)); + cachedPC = pc; + cachedSymtab = symtab; + } + + return *cachedDisassembly; + } + + std::string + Branch::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + std::stringstream ss; + + ccprintf(ss, "%-10s ", mnemonic); + + // There's only one register arg (RA), but it could be + // either a source (the condition for conditional + // branches) or a destination (the link reg for + // unconditional branches) + if (_numSrcRegs > 0) { + printReg(ss, _srcRegIdx[0]); + ss << ","; + } + else if (_numDestRegs > 0) { + printReg(ss, _destRegIdx[0]); + ss << ","; + } + +#ifdef SS_COMPATIBLE_DISASSEMBLY + if (_numSrcRegs == 0 && _numDestRegs == 0) { + printReg(ss, 31); + ss << ","; + } +#endif + + Addr target = pc + 4 + disp; + + std::string str; + if (symtab && symtab->findSymbol(target, str)) + ss << str; + else + ccprintf(ss, "0x%x", target); + + return ss.str(); + } + + std::string + Jump::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + std::stringstream ss; + + ccprintf(ss, "%-10s ", mnemonic); + +#ifdef SS_COMPATIBLE_DISASSEMBLY + if (_numDestRegs == 0) { + printReg(ss, 31); + ss << ","; + } +#endif + + if (_numDestRegs > 0) { + printReg(ss, _destRegIdx[0]); + ss << ","; + } + + ccprintf(ss, "(r%d)", RB); + + return ss.str(); + } +}}; + +def template JumpOrBranchDecode {{ + return (RA == 31) + ? (StaticInst *)new %(class_name)s(machInst) + : (StaticInst *)new %(class_name)sAndLink(machInst); +}}; + +def format CondBranch(code) {{ + code = 'bool cond;\n' + code + '\nif (cond) NPC = NPC + disp;\n'; + iop = InstObjParams(name, Name, 'Branch', CodeBlock(code), + ('IsDirectControl', 'IsCondControl')) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; + +let {{ +def UncondCtrlBase(name, Name, base_class, npc_expr, flags): + # Declare basic control transfer w/o link (i.e. link reg is R31) + nolink_code = 'NPC = %s;\n' % npc_expr + nolink_iop = InstObjParams(name, Name, base_class, + CodeBlock(nolink_code), flags) + header_output = BasicDeclare.subst(nolink_iop) + decoder_output = BasicConstructor.subst(nolink_iop) + exec_output = BasicExecute.subst(nolink_iop) + + # Generate declaration of '*AndLink' version, append to decls + link_code = 'Ra = NPC & ~3;\n' + nolink_code + link_iop = InstObjParams(name, Name + 'AndLink', base_class, + CodeBlock(link_code), flags) + header_output += BasicDeclare.subst(link_iop) + decoder_output += BasicConstructor.subst(link_iop) + exec_output += BasicExecute.subst(link_iop) + + # need to use link_iop for the decode template since it is expecting + # the shorter version of class_name (w/o "AndLink") + + return (header_output, decoder_output, + JumpOrBranchDecode.subst(nolink_iop), exec_output) +}}; + +def format UncondBranch(*flags) {{ + flags += ('IsUncondControl', 'IsDirectControl') + (header_output, decoder_output, decode_block, exec_output) = \ + UncondCtrlBase(name, Name, 'Branch', 'NPC + disp', flags) +}}; + +def format Jump(*flags) {{ + flags += ('IsUncondControl', 'IsIndirectControl') + (header_output, decoder_output, decode_block, exec_output) = \ + UncondCtrlBase(name, Name, 'Jump', '(Rb & ~3) | (NPC & 1)', flags) +}}; + + diff --git a/src/arch/alpha/isa/decoder.isa b/src/arch/alpha/isa/decoder.isa new file mode 100644 index 000000000..e6b4c234f --- /dev/null +++ b/src/arch/alpha/isa/decoder.isa @@ -0,0 +1,824 @@ +// -*- mode:c++ -*- + +// Copyright (c) 2003-2006 The Regents of The University of Michigan +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +//////////////////////////////////////////////////////////////////// +// +// The actual decoder specification +// + +decode OPCODE default Unknown::unknown() { + + format LoadAddress { + 0x08: lda({{ Ra = Rb + disp; }}); + 0x09: ldah({{ Ra = Rb + (disp << 16); }}); + } + + format LoadOrNop { + 0x0a: ldbu({{ Ra.uq = Mem.ub; }}); + 0x0c: ldwu({{ Ra.uq = Mem.uw; }}); + 0x0b: ldq_u({{ Ra = Mem.uq; }}, ea_code = {{ EA = (Rb + disp) & ~7; }}); + 0x23: ldt({{ Fa = Mem.df; }}); + 0x2a: ldl_l({{ Ra.sl = Mem.sl; }}, mem_flags = LOCKED); + 0x2b: ldq_l({{ Ra.uq = Mem.uq; }}, mem_flags = LOCKED); + 0x20: MiscPrefetch::copy_load({{ EA = Ra; }}, + {{ fault = xc->copySrcTranslate(EA); }}, + inst_flags = [IsMemRef, IsLoad, IsCopy]); + } + + format LoadOrPrefetch { + 0x28: ldl({{ Ra.sl = Mem.sl; }}); + 0x29: ldq({{ Ra.uq = Mem.uq; }}, pf_flags = EVICT_NEXT); + // IsFloating flag on lds gets the prefetch to disassemble + // using f31 instead of r31... funcitonally it's unnecessary + 0x22: lds({{ Fa.uq = s_to_t(Mem.ul); }}, + pf_flags = PF_EXCLUSIVE, inst_flags = IsFloating); + } + + format Store { + 0x0e: stb({{ Mem.ub = Ra<7:0>; }}); + 0x0d: stw({{ Mem.uw = Ra<15:0>; }}); + 0x2c: stl({{ Mem.ul = Ra<31:0>; }}); + 0x2d: stq({{ Mem.uq = Ra.uq; }}); + 0x0f: stq_u({{ Mem.uq = Ra.uq; }}, {{ EA = (Rb + disp) & ~7; }}); + 0x26: sts({{ Mem.ul = t_to_s(Fa.uq); }}); + 0x27: stt({{ Mem.df = Fa; }}); + 0x24: MiscPrefetch::copy_store({{ EA = Rb; }}, + {{ fault = xc->copy(EA); }}, + inst_flags = [IsMemRef, IsStore, IsCopy]); + } + + format StoreCond { + 0x2e: stl_c({{ Mem.ul = Ra<31:0>; }}, + {{ + uint64_t tmp = write_result; + // see stq_c + Ra = (tmp == 0 || tmp == 1) ? tmp : Ra; + }}, mem_flags = LOCKED, inst_flags = IsStoreConditional); + 0x2f: stq_c({{ Mem.uq = Ra; }}, + {{ + uint64_t tmp = write_result; + // If the write operation returns 0 or 1, then + // this was a conventional store conditional, + // and the value indicates the success/failure + // of the operation. If another value is + // returned, then this was a Turbolaser + // mailbox access, and we don't update the + // result register at all. + Ra = (tmp == 0 || tmp == 1) ? tmp : Ra; + }}, mem_flags = LOCKED, inst_flags = IsStoreConditional); + } + + format IntegerOperate { + + 0x10: decode INTFUNC { // integer arithmetic operations + + 0x00: addl({{ Rc.sl = Ra.sl + Rb_or_imm.sl; }}); + 0x40: addlv({{ + uint32_t tmp = Ra.sl + Rb_or_imm.sl; + // signed overflow occurs when operands have same sign + // and sign of result does not match. + if (Ra.sl<31:> == Rb_or_imm.sl<31:> && tmp<31:> != Ra.sl<31:>) + fault = new IntegerOverflowFault; + Rc.sl = tmp; + }}); + 0x02: s4addl({{ Rc.sl = (Ra.sl << 2) + Rb_or_imm.sl; }}); + 0x12: s8addl({{ Rc.sl = (Ra.sl << 3) + Rb_or_imm.sl; }}); + + 0x20: addq({{ Rc = Ra + Rb_or_imm; }}); + 0x60: addqv({{ + uint64_t tmp = Ra + Rb_or_imm; + // signed overflow occurs when operands have same sign + // and sign of result does not match. + if (Ra<63:> == Rb_or_imm<63:> && tmp<63:> != Ra<63:>) + fault = new IntegerOverflowFault; + Rc = tmp; + }}); + 0x22: s4addq({{ Rc = (Ra << 2) + Rb_or_imm; }}); + 0x32: s8addq({{ Rc = (Ra << 3) + Rb_or_imm; }}); + + 0x09: subl({{ Rc.sl = Ra.sl - Rb_or_imm.sl; }}); + 0x49: sublv({{ + uint32_t tmp = Ra.sl - Rb_or_imm.sl; + // signed overflow detection is same as for add, + // except we need to look at the *complemented* + // sign bit of the subtrahend (Rb), i.e., if the initial + // signs are the *same* then no overflow can occur + if (Ra.sl<31:> != Rb_or_imm.sl<31:> && tmp<31:> != Ra.sl<31:>) + fault = new IntegerOverflowFault; + Rc.sl = tmp; + }}); + 0x0b: s4subl({{ Rc.sl = (Ra.sl << 2) - Rb_or_imm.sl; }}); + 0x1b: s8subl({{ Rc.sl = (Ra.sl << 3) - Rb_or_imm.sl; }}); + + 0x29: subq({{ Rc = Ra - Rb_or_imm; }}); + 0x69: subqv({{ + uint64_t tmp = Ra - Rb_or_imm; + // signed overflow detection is same as for add, + // except we need to look at the *complemented* + // sign bit of the subtrahend (Rb), i.e., if the initial + // signs are the *same* then no overflow can occur + if (Ra<63:> != Rb_or_imm<63:> && tmp<63:> != Ra<63:>) + fault = new IntegerOverflowFault; + Rc = tmp; + }}); + 0x2b: s4subq({{ Rc = (Ra << 2) - Rb_or_imm; }}); + 0x3b: s8subq({{ Rc = (Ra << 3) - Rb_or_imm; }}); + + 0x2d: cmpeq({{ Rc = (Ra == Rb_or_imm); }}); + 0x6d: cmple({{ Rc = (Ra.sq <= Rb_or_imm.sq); }}); + 0x4d: cmplt({{ Rc = (Ra.sq < Rb_or_imm.sq); }}); + 0x3d: cmpule({{ Rc = (Ra.uq <= Rb_or_imm.uq); }}); + 0x1d: cmpult({{ Rc = (Ra.uq < Rb_or_imm.uq); }}); + + 0x0f: cmpbge({{ + int hi = 7; + int lo = 0; + uint64_t tmp = 0; + for (int i = 0; i < 8; ++i) { + tmp |= (Ra.uq<hi:lo> >= Rb_or_imm.uq<hi:lo>) << i; + hi += 8; + lo += 8; + } + Rc = tmp; + }}); + } + + 0x11: decode INTFUNC { // integer logical operations + + 0x00: and({{ Rc = Ra & Rb_or_imm; }}); + 0x08: bic({{ Rc = Ra & ~Rb_or_imm; }}); + 0x20: bis({{ Rc = Ra | Rb_or_imm; }}); + 0x28: ornot({{ Rc = Ra | ~Rb_or_imm; }}); + 0x40: xor({{ Rc = Ra ^ Rb_or_imm; }}); + 0x48: eqv({{ Rc = Ra ^ ~Rb_or_imm; }}); + + // conditional moves + 0x14: cmovlbs({{ Rc = ((Ra & 1) == 1) ? Rb_or_imm : Rc; }}); + 0x16: cmovlbc({{ Rc = ((Ra & 1) == 0) ? Rb_or_imm : Rc; }}); + 0x24: cmoveq({{ Rc = (Ra == 0) ? Rb_or_imm : Rc; }}); + 0x26: cmovne({{ Rc = (Ra != 0) ? Rb_or_imm : Rc; }}); + 0x44: cmovlt({{ Rc = (Ra.sq < 0) ? Rb_or_imm : Rc; }}); + 0x46: cmovge({{ Rc = (Ra.sq >= 0) ? Rb_or_imm : Rc; }}); + 0x64: cmovle({{ Rc = (Ra.sq <= 0) ? Rb_or_imm : Rc; }}); + 0x66: cmovgt({{ Rc = (Ra.sq > 0) ? Rb_or_imm : Rc; }}); + + // For AMASK, RA must be R31. + 0x61: decode RA { + 31: amask({{ Rc = Rb_or_imm & ~ULL(0x17); }}); + } + + // For IMPLVER, RA must be R31 and the B operand + // must be the immediate value 1. + 0x6c: decode RA { + 31: decode IMM { + 1: decode INTIMM { + // return EV5 for FULL_SYSTEM and EV6 otherwise + 1: implver({{ +#if FULL_SYSTEM + Rc = 1; +#else + Rc = 2; +#endif + }}); + } + } + } + +#if FULL_SYSTEM + // The mysterious 11.25... + 0x25: WarnUnimpl::eleven25(); +#endif + } + + 0x12: decode INTFUNC { + 0x39: sll({{ Rc = Ra << Rb_or_imm<5:0>; }}); + 0x34: srl({{ Rc = Ra.uq >> Rb_or_imm<5:0>; }}); + 0x3c: sra({{ Rc = Ra.sq >> Rb_or_imm<5:0>; }}); + + 0x02: mskbl({{ Rc = Ra & ~(mask( 8) << (Rb_or_imm<2:0> * 8)); }}); + 0x12: mskwl({{ Rc = Ra & ~(mask(16) << (Rb_or_imm<2:0> * 8)); }}); + 0x22: mskll({{ Rc = Ra & ~(mask(32) << (Rb_or_imm<2:0> * 8)); }}); + 0x32: mskql({{ Rc = Ra & ~(mask(64) << (Rb_or_imm<2:0> * 8)); }}); + + 0x52: mskwh({{ + int bv = Rb_or_imm<2:0>; + Rc = bv ? (Ra & ~(mask(16) >> (64 - 8 * bv))) : Ra; + }}); + 0x62: msklh({{ + int bv = Rb_or_imm<2:0>; + Rc = bv ? (Ra & ~(mask(32) >> (64 - 8 * bv))) : Ra; + }}); + 0x72: mskqh({{ + int bv = Rb_or_imm<2:0>; + Rc = bv ? (Ra & ~(mask(64) >> (64 - 8 * bv))) : Ra; + }}); + + 0x06: extbl({{ Rc = (Ra.uq >> (Rb_or_imm<2:0> * 8))< 7:0>; }}); + 0x16: extwl({{ Rc = (Ra.uq >> (Rb_or_imm<2:0> * 8))<15:0>; }}); + 0x26: extll({{ Rc = (Ra.uq >> (Rb_or_imm<2:0> * 8))<31:0>; }}); + 0x36: extql({{ Rc = (Ra.uq >> (Rb_or_imm<2:0> * 8)); }}); + + 0x5a: extwh({{ + Rc = (Ra << (64 - (Rb_or_imm<2:0> * 8))<5:0>)<15:0>; }}); + 0x6a: extlh({{ + Rc = (Ra << (64 - (Rb_or_imm<2:0> * 8))<5:0>)<31:0>; }}); + 0x7a: extqh({{ + Rc = (Ra << (64 - (Rb_or_imm<2:0> * 8))<5:0>); }}); + + 0x0b: insbl({{ Rc = Ra< 7:0> << (Rb_or_imm<2:0> * 8); }}); + 0x1b: inswl({{ Rc = Ra<15:0> << (Rb_or_imm<2:0> * 8); }}); + 0x2b: insll({{ Rc = Ra<31:0> << (Rb_or_imm<2:0> * 8); }}); + 0x3b: insql({{ Rc = Ra << (Rb_or_imm<2:0> * 8); }}); + + 0x57: inswh({{ + int bv = Rb_or_imm<2:0>; + Rc = bv ? (Ra.uq<15:0> >> (64 - 8 * bv)) : 0; + }}); + 0x67: inslh({{ + int bv = Rb_or_imm<2:0>; + Rc = bv ? (Ra.uq<31:0> >> (64 - 8 * bv)) : 0; + }}); + 0x77: insqh({{ + int bv = Rb_or_imm<2:0>; + Rc = bv ? (Ra.uq >> (64 - 8 * bv)) : 0; + }}); + + 0x30: zap({{ + uint64_t zapmask = 0; + for (int i = 0; i < 8; ++i) { + if (Rb_or_imm<i:>) + zapmask |= (mask(8) << (i * 8)); + } + Rc = Ra & ~zapmask; + }}); + 0x31: zapnot({{ + uint64_t zapmask = 0; + for (int i = 0; i < 8; ++i) { + if (!Rb_or_imm<i:>) + zapmask |= (mask(8) << (i * 8)); + } + Rc = Ra & ~zapmask; + }}); + } + + 0x13: decode INTFUNC { // integer multiplies + 0x00: mull({{ Rc.sl = Ra.sl * Rb_or_imm.sl; }}, IntMultOp); + 0x20: mulq({{ Rc = Ra * Rb_or_imm; }}, IntMultOp); + 0x30: umulh({{ + uint64_t hi, lo; + mul128(Ra, Rb_or_imm, hi, lo); + Rc = hi; + }}, IntMultOp); + 0x40: mullv({{ + // 32-bit multiply with trap on overflow + int64_t Rax = Ra.sl; // sign extended version of Ra.sl + int64_t Rbx = Rb_or_imm.sl; + int64_t tmp = Rax * Rbx; + // To avoid overflow, all the upper 32 bits must match + // the sign bit of the lower 32. We code this as + // checking the upper 33 bits for all 0s or all 1s. + uint64_t sign_bits = tmp<63:31>; + if (sign_bits != 0 && sign_bits != mask(33)) + fault = new IntegerOverflowFault; + Rc.sl = tmp<31:0>; + }}, IntMultOp); + 0x60: mulqv({{ + // 64-bit multiply with trap on overflow + uint64_t hi, lo; + mul128(Ra, Rb_or_imm, hi, lo); + // all the upper 64 bits must match the sign bit of + // the lower 64 + if (!((hi == 0 && lo<63:> == 0) || + (hi == mask(64) && lo<63:> == 1))) + fault = new IntegerOverflowFault; + Rc = lo; + }}, IntMultOp); + } + + 0x1c: decode INTFUNC { + 0x00: decode RA { 31: sextb({{ Rc.sb = Rb_or_imm< 7:0>; }}); } + 0x01: decode RA { 31: sextw({{ Rc.sw = Rb_or_imm<15:0>; }}); } + 0x32: ctlz({{ + uint64_t count = 0; + uint64_t temp = Rb; + if (temp<63:32>) temp >>= 32; else count += 32; + if (temp<31:16>) temp >>= 16; else count += 16; + if (temp<15:8>) temp >>= 8; else count += 8; + if (temp<7:4>) temp >>= 4; else count += 4; + if (temp<3:2>) temp >>= 2; else count += 2; + if (temp<1:1>) temp >>= 1; else count += 1; + if ((temp<0:0>) != 0x1) count += 1; + Rc = count; + }}, IntAluOp); + + 0x33: cttz({{ + uint64_t count = 0; + uint64_t temp = Rb; + if (!(temp<31:0>)) { temp >>= 32; count += 32; } + if (!(temp<15:0>)) { temp >>= 16; count += 16; } + if (!(temp<7:0>)) { temp >>= 8; count += 8; } + if (!(temp<3:0>)) { temp >>= 4; count += 4; } + if (!(temp<1:0>)) { temp >>= 2; count += 2; } + if (!(temp<0:0> & ULL(0x1))) count += 1; + Rc = count; + }}, IntAluOp); + + format FailUnimpl { + 0x30: ctpop(); + 0x31: perr(); + 0x34: unpkbw(); + 0x35: unpkbl(); + 0x36: pkwb(); + 0x37: pklb(); + 0x38: minsb8(); + 0x39: minsw4(); + 0x3a: minub8(); + 0x3b: minuw4(); + 0x3c: maxub8(); + 0x3d: maxuw4(); + 0x3e: maxsb8(); + 0x3f: maxsw4(); + } + + format BasicOperateWithNopCheck { + 0x70: decode RB { + 31: ftoit({{ Rc = Fa.uq; }}, FloatCvtOp); + } + 0x78: decode RB { + 31: ftois({{ Rc.sl = t_to_s(Fa.uq); }}, + FloatCvtOp); + } + } + } + } + + // Conditional branches. + format CondBranch { + 0x39: beq({{ cond = (Ra == 0); }}); + 0x3d: bne({{ cond = (Ra != 0); }}); + 0x3e: bge({{ cond = (Ra.sq >= 0); }}); + 0x3f: bgt({{ cond = (Ra.sq > 0); }}); + 0x3b: ble({{ cond = (Ra.sq <= 0); }}); + 0x3a: blt({{ cond = (Ra.sq < 0); }}); + 0x38: blbc({{ cond = ((Ra & 1) == 0); }}); + 0x3c: blbs({{ cond = ((Ra & 1) == 1); }}); + + 0x31: fbeq({{ cond = (Fa == 0); }}); + 0x35: fbne({{ cond = (Fa != 0); }}); + 0x36: fbge({{ cond = (Fa >= 0); }}); + 0x37: fbgt({{ cond = (Fa > 0); }}); + 0x33: fble({{ cond = (Fa <= 0); }}); + 0x32: fblt({{ cond = (Fa < 0); }}); + } + + // unconditional branches + format UncondBranch { + 0x30: br(); + 0x34: bsr(IsCall); + } + + // indirect branches + 0x1a: decode JMPFUNC { + format Jump { + 0: jmp(); + 1: jsr(IsCall); + 2: ret(IsReturn); + 3: jsr_coroutine(IsCall, IsReturn); + } + } + + // Square root and integer-to-FP moves + 0x14: decode FP_SHORTFUNC { + // Integer to FP register moves must have RB == 31 + 0x4: decode RB { + 31: decode FP_FULLFUNC { + format BasicOperateWithNopCheck { + 0x004: itofs({{ Fc.uq = s_to_t(Ra.ul); }}, FloatCvtOp); + 0x024: itoft({{ Fc.uq = Ra.uq; }}, FloatCvtOp); + 0x014: FailUnimpl::itoff(); // VAX-format conversion + } + } + } + + // Square root instructions must have FA == 31 + 0xb: decode FA { + 31: decode FP_TYPEFUNC { + format FloatingPointOperate { +#if SS_COMPATIBLE_FP + 0x0b: sqrts({{ + if (Fb < 0.0) + fault = new ArithmeticFault; + Fc = sqrt(Fb); + }}, FloatSqrtOp); +#else + 0x0b: sqrts({{ + if (Fb.sf < 0.0) + fault = new ArithmeticFault; + Fc.sf = sqrt(Fb.sf); + }}, FloatSqrtOp); +#endif + 0x2b: sqrtt({{ + if (Fb < 0.0) + fault = new ArithmeticFault; + Fc = sqrt(Fb); + }}, FloatSqrtOp); + } + } + } + + // VAX-format sqrtf and sqrtg are not implemented + 0xa: FailUnimpl::sqrtfg(); + } + + // IEEE floating point + 0x16: decode FP_SHORTFUNC_TOP2 { + // The top two bits of the short function code break this + // space into four groups: binary ops, compares, reserved, and + // conversions. See Table 4-12 of AHB. There are different + // special cases in these different groups, so we decode on + // these top two bits first just to select a decode strategy. + // Most of these instructions may have various trapping and + // rounding mode flags set; these are decoded in the + // FloatingPointDecode template used by the + // FloatingPointOperate format. + + // add/sub/mul/div: just decode on the short function code + // and source type. All valid trapping and rounding modes apply. + 0: decode FP_TRAPMODE { + // check for valid trapping modes here + 0,1,5,7: decode FP_TYPEFUNC { + format FloatingPointOperate { +#if SS_COMPATIBLE_FP + 0x00: adds({{ Fc = Fa + Fb; }}); + 0x01: subs({{ Fc = Fa - Fb; }}); + 0x02: muls({{ Fc = Fa * Fb; }}, FloatMultOp); + 0x03: divs({{ Fc = Fa / Fb; }}, FloatDivOp); +#else + 0x00: adds({{ Fc.sf = Fa.sf + Fb.sf; }}); + 0x01: subs({{ Fc.sf = Fa.sf - Fb.sf; }}); + 0x02: muls({{ Fc.sf = Fa.sf * Fb.sf; }}, FloatMultOp); + 0x03: divs({{ Fc.sf = Fa.sf / Fb.sf; }}, FloatDivOp); +#endif + + 0x20: addt({{ Fc = Fa + Fb; }}); + 0x21: subt({{ Fc = Fa - Fb; }}); + 0x22: mult({{ Fc = Fa * Fb; }}, FloatMultOp); + 0x23: divt({{ Fc = Fa / Fb; }}, FloatDivOp); + } + } + } + + // Floating-point compare instructions must have the default + // rounding mode, and may use the default trapping mode or + // /SU. Both trapping modes are treated the same by M5; the + // only difference on the real hardware (as far a I can tell) + // is that without /SU you'd get an imprecise trap if you + // tried to compare a NaN with something else (instead of an + // "unordered" result). + 1: decode FP_FULLFUNC { + format BasicOperateWithNopCheck { + 0x0a5, 0x5a5: cmpteq({{ Fc = (Fa == Fb) ? 2.0 : 0.0; }}, + FloatCmpOp); + 0x0a7, 0x5a7: cmptle({{ Fc = (Fa <= Fb) ? 2.0 : 0.0; }}, + FloatCmpOp); + 0x0a6, 0x5a6: cmptlt({{ Fc = (Fa < Fb) ? 2.0 : 0.0; }}, + FloatCmpOp); + 0x0a4, 0x5a4: cmptun({{ // unordered + Fc = (!(Fa < Fb) && !(Fa == Fb) && !(Fa > Fb)) ? 2.0 : 0.0; + }}, FloatCmpOp); + } + } + + // The FP-to-integer and integer-to-FP conversion insts + // require that FA be 31. + 3: decode FA { + 31: decode FP_TYPEFUNC { + format FloatingPointOperate { + 0x2f: decode FP_ROUNDMODE { + format FPFixedRounding { + // "chopped" i.e. round toward zero + 0: cvttq({{ Fc.sq = (int64_t)trunc(Fb); }}, + Chopped); + // round to minus infinity + 1: cvttq({{ Fc.sq = (int64_t)floor(Fb); }}, + MinusInfinity); + } + default: cvttq({{ Fc.sq = (int64_t)nearbyint(Fb); }}); + } + + // The cvtts opcode is overloaded to be cvtst if the trap + // mode is 2 or 6 (which are not valid otherwise) + 0x2c: decode FP_FULLFUNC { + format BasicOperateWithNopCheck { + // trap on denorm version "cvtst/s" is + // simulated same as cvtst + 0x2ac, 0x6ac: cvtst({{ Fc = Fb.sf; }}); + } + default: cvtts({{ Fc.sf = Fb; }}); + } + + // The trapping mode for integer-to-FP conversions + // must be /SUI or nothing; /U and /SU are not + // allowed. The full set of rounding modes are + // supported though. + 0x3c: decode FP_TRAPMODE { + 0,7: cvtqs({{ Fc.sf = Fb.sq; }}); + } + 0x3e: decode FP_TRAPMODE { + 0,7: cvtqt({{ Fc = Fb.sq; }}); + } + } + } + } + } + + // misc FP operate + 0x17: decode FP_FULLFUNC { + format BasicOperateWithNopCheck { + 0x010: cvtlq({{ + Fc.sl = (Fb.uq<63:62> << 30) | Fb.uq<58:29>; + }}); + 0x030: cvtql({{ + Fc.uq = (Fb.uq<31:30> << 62) | (Fb.uq<29:0> << 29); + }}); + + // We treat the precise & imprecise trapping versions of + // cvtql identically. + 0x130, 0x530: cvtqlv({{ + // To avoid overflow, all the upper 32 bits must match + // the sign bit of the lower 32. We code this as + // checking the upper 33 bits for all 0s or all 1s. + uint64_t sign_bits = Fb.uq<63:31>; + if (sign_bits != 0 && sign_bits != mask(33)) + fault = new IntegerOverflowFault; + Fc.uq = (Fb.uq<31:30> << 62) | (Fb.uq<29:0> << 29); + }}); + + 0x020: cpys({{ // copy sign + Fc.uq = (Fa.uq<63:> << 63) | Fb.uq<62:0>; + }}); + 0x021: cpysn({{ // copy sign negated + Fc.uq = (~Fa.uq<63:> << 63) | Fb.uq<62:0>; + }}); + 0x022: cpyse({{ // copy sign and exponent + Fc.uq = (Fa.uq<63:52> << 52) | Fb.uq<51:0>; + }}); + + 0x02a: fcmoveq({{ Fc = (Fa == 0) ? Fb : Fc; }}); + 0x02b: fcmovne({{ Fc = (Fa != 0) ? Fb : Fc; }}); + 0x02c: fcmovlt({{ Fc = (Fa < 0) ? Fb : Fc; }}); + 0x02d: fcmovge({{ Fc = (Fa >= 0) ? Fb : Fc; }}); + 0x02e: fcmovle({{ Fc = (Fa <= 0) ? Fb : Fc; }}); + 0x02f: fcmovgt({{ Fc = (Fa > 0) ? Fb : Fc; }}); + + 0x024: mt_fpcr({{ FPCR = Fa.uq; }}, IsIprAccess); + 0x025: mf_fpcr({{ Fa.uq = FPCR; }}, IsIprAccess); + } + } + + // miscellaneous mem-format ops + 0x18: decode MEMFUNC { + format WarnUnimpl { + 0x8000: fetch(); + 0xa000: fetch_m(); + 0xe800: ecb(); + } + + format MiscPrefetch { + 0xf800: wh64({{ EA = Rb & ~ULL(63); }}, + {{ xc->writeHint(EA, 64, memAccessFlags); }}, + mem_flags = NO_FAULT, + inst_flags = [IsMemRef, IsDataPrefetch, + IsStore, MemWriteOp]); + } + + format BasicOperate { + 0xc000: rpcc({{ +#if FULL_SYSTEM + /* Rb is a fake dependency so here is a fun way to get + * the parser to understand that. + */ + Ra = xc->readMiscRegWithEffect(AlphaISA::IPR_CC, fault) + (Rb & 0); + +#else + Ra = curTick; +#endif + }}, IsUnverifiable); + + // All of the barrier instructions below do nothing in + // their execute() methods (hence the empty code blocks). + // All of their functionality is hard-coded in the + // pipeline based on the flags IsSerializing, + // IsMemBarrier, and IsWriteBarrier. In the current + // detailed CPU model, the execute() function only gets + // called at fetch, so there's no way to generate pipeline + // behavior at any other stage. Once we go to an + // exec-in-exec CPU model we should be able to get rid of + // these flags and implement this behavior via the + // execute() methods. + + // trapb is just a barrier on integer traps, where excb is + // a barrier on integer and FP traps. "EXCB is thus a + // superset of TRAPB." (Alpha ARM, Sec 4.11.4) We treat + // them the same though. + 0x0000: trapb({{ }}, IsSerializing, IsSerializeBefore, No_OpClass); + 0x0400: excb({{ }}, IsSerializing, IsSerializeBefore, No_OpClass); + 0x4000: mb({{ }}, IsMemBarrier, MemReadOp); + 0x4400: wmb({{ }}, IsWriteBarrier, MemWriteOp); + } + +#if FULL_SYSTEM + format BasicOperate { + 0xe000: rc({{ + Ra = xc->readIntrFlag(); + xc->setIntrFlag(0); + }}, IsNonSpeculative); + 0xf000: rs({{ + Ra = xc->readIntrFlag(); + xc->setIntrFlag(1); + }}, IsNonSpeculative); + } +#else + format FailUnimpl { + 0xe000: rc(); + 0xf000: rs(); + } +#endif + } + +#if FULL_SYSTEM + 0x00: CallPal::call_pal({{ + if (!palValid || + (palPriv + && xc->readMiscRegWithEffect(AlphaISA::IPR_ICM, fault) != AlphaISA::mode_kernel)) { + // invalid pal function code, or attempt to do privileged + // PAL call in non-kernel mode + fault = new UnimplementedOpcodeFault; + } + else { + // check to see if simulator wants to do something special + // on this PAL call (including maybe suppress it) + bool dopal = xc->simPalCheck(palFunc); + + if (dopal) { + xc->setMiscRegWithEffect(AlphaISA::IPR_EXC_ADDR, NPC); + NPC = xc->readMiscRegWithEffect(AlphaISA::IPR_PAL_BASE, fault) + palOffset; + } + } + }}, IsNonSpeculative); +#else + 0x00: decode PALFUNC { + format EmulatedCallPal { + 0x00: halt ({{ + SimExit(curTick, "halt instruction encountered"); + }}, IsNonSpeculative); + 0x83: callsys({{ + xc->syscall(R0); + }}, IsNonSpeculative); + // Read uniq reg into ABI return value register (r0) + 0x9e: rduniq({{ R0 = Runiq; }}, IsIprAccess); + // Write uniq reg with value from ABI arg register (r16) + 0x9f: wruniq({{ Runiq = R16; }}, IsIprAccess); + } + } +#endif + +#if FULL_SYSTEM + 0x1b: decode PALMODE { + 0: OpcdecFault::hw_st_quad(); + 1: decode HW_LDST_QUAD { + format HwLoad { + 0: hw_ld({{ EA = (Rb + disp) & ~3; }}, {{ Ra = Mem.ul; }}, L); + 1: hw_ld({{ EA = (Rb + disp) & ~7; }}, {{ Ra = Mem.uq; }}, Q); + } + } + } + + 0x1f: decode PALMODE { + 0: OpcdecFault::hw_st_cond(); + format HwStore { + 1: decode HW_LDST_COND { + 0: decode HW_LDST_QUAD { + 0: hw_st({{ EA = (Rb + disp) & ~3; }}, + {{ Mem.ul = Ra<31:0>; }}, L); + 1: hw_st({{ EA = (Rb + disp) & ~7; }}, + {{ Mem.uq = Ra.uq; }}, Q); + } + + 1: FailUnimpl::hw_st_cond(); + } + } + } + + 0x19: decode PALMODE { + 0: OpcdecFault::hw_mfpr(); + format HwMoveIPR { + 1: hw_mfpr({{ + Ra = xc->readMiscRegWithEffect(ipr_index, fault); + }}, IsIprAccess); + } + } + + 0x1d: decode PALMODE { + 0: OpcdecFault::hw_mtpr(); + format HwMoveIPR { + 1: hw_mtpr({{ + xc->setMiscRegWithEffect(ipr_index, Ra); + if (traceData) { traceData->setData(Ra); } + }}, IsIprAccess); + } + } + + format BasicOperate { + 0x1e: decode PALMODE { + 0: OpcdecFault::hw_rei(); + 1:hw_rei({{ xc->hwrei(); }}, IsSerializing, IsSerializeBefore); + } + + // M5 special opcodes use the reserved 0x01 opcode space + 0x01: decode M5FUNC { + 0x00: arm({{ + AlphaPseudo::arm(xc->xcBase()); + }}, IsNonSpeculative); + 0x01: quiesce({{ + AlphaPseudo::quiesce(xc->xcBase()); + }}, IsNonSpeculative, IsQuiesce); + 0x02: quiesceNs({{ + AlphaPseudo::quiesceNs(xc->xcBase(), R16); + }}, IsNonSpeculative, IsQuiesce); + 0x03: quiesceCycles({{ + AlphaPseudo::quiesceCycles(xc->xcBase(), R16); + }}, IsNonSpeculative, IsQuiesce); + 0x04: quiesceTime({{ + R0 = AlphaPseudo::quiesceTime(xc->xcBase()); + }}, IsNonSpeculative); + 0x10: ivlb({{ + AlphaPseudo::ivlb(xc->xcBase()); + }}, No_OpClass, IsNonSpeculative); + 0x11: ivle({{ + AlphaPseudo::ivle(xc->xcBase()); + }}, No_OpClass, IsNonSpeculative); + 0x20: m5exit_old({{ + AlphaPseudo::m5exit_old(xc->xcBase()); + }}, No_OpClass, IsNonSpeculative); + 0x21: m5exit({{ + AlphaPseudo::m5exit(xc->xcBase(), R16); + }}, No_OpClass, IsNonSpeculative); + 0x30: initparam({{ Ra = xc->xcBase()->getCpuPtr()->system->init_param; }}); + 0x40: resetstats({{ + AlphaPseudo::resetstats(xc->xcBase(), R16, R17); + }}, IsNonSpeculative); + 0x41: dumpstats({{ + AlphaPseudo::dumpstats(xc->xcBase(), R16, R17); + }}, IsNonSpeculative); + 0x42: dumpresetstats({{ + AlphaPseudo::dumpresetstats(xc->xcBase(), R16, R17); + }}, IsNonSpeculative); + 0x43: m5checkpoint({{ + AlphaPseudo::m5checkpoint(xc->xcBase(), R16, R17); + }}, IsNonSpeculative); + 0x50: m5readfile({{ + R0 = AlphaPseudo::readfile(xc->xcBase(), R16, R17, R18); + }}, IsNonSpeculative); + 0x51: m5break({{ + AlphaPseudo::debugbreak(xc->xcBase()); + }}, IsNonSpeculative); + 0x52: m5switchcpu({{ + AlphaPseudo::switchcpu(xc->xcBase()); + }}, IsNonSpeculative); + 0x53: m5addsymbol({{ + AlphaPseudo::addsymbol(xc->xcBase(), R16, R17); + }}, IsNonSpeculative); + 0x54: m5panic({{ + panic("M5 panic instruction called at pc=%#x.", xc->readPC()); + }}, IsNonSpeculative); + + } + } +#endif +} diff --git a/src/arch/alpha/isa/fp.isa b/src/arch/alpha/isa/fp.isa new file mode 100644 index 000000000..f855ca3a9 --- /dev/null +++ b/src/arch/alpha/isa/fp.isa @@ -0,0 +1,310 @@ +// -*- mode:c++ -*- + +// Copyright (c) 2003-2005 The Regents of The University of Michigan +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +//////////////////////////////////////////////////////////////////// +// +// Floating-point instructions +// +// Note that many FP-type instructions which do not support all the +// various rounding & trapping modes use the simpler format +// BasicOperateWithNopCheck. +// + +output exec {{ + /// Check "FP enabled" machine status bit. Called when executing any FP + /// instruction in full-system mode. + /// @retval Full-system mode: NoFault if FP is enabled, FenFault + /// if not. Non-full-system mode: always returns NoFault. +#if FULL_SYSTEM + inline Fault checkFpEnableFault(%(CPU_exec_context)s *xc) + { + Fault fault = NoFault; // dummy... this ipr access should not fault + if (!EV5::ICSR_FPE(xc->readMiscRegWithEffect(AlphaISA::IPR_ICSR, fault))) { + fault = new FloatEnableFault; + } + return fault; + } +#else + inline Fault checkFpEnableFault(%(CPU_exec_context)s *xc) + { + return NoFault; + } +#endif +}}; + +output header {{ + /** + * Base class for general floating-point instructions. Includes + * support for various Alpha rounding and trapping modes. Only FP + * instructions that require this support are derived from this + * class; the rest derive directly from AlphaStaticInst. + */ + class AlphaFP : public AlphaStaticInst + { + public: + /// Alpha FP rounding modes. + enum RoundingMode { + Chopped = 0, ///< round toward zero + Minus_Infinity = 1, ///< round toward minus infinity + Normal = 2, ///< round to nearest (default) + Dynamic = 3, ///< use FPCR setting (in instruction) + Plus_Infinity = 3 ///< round to plus inifinity (in FPCR) + }; + + /// Alpha FP trapping modes. + /// For instructions that produce integer results, the + /// "Underflow Enable" modes really mean "Overflow Enable", and + /// the assembly modifier is V rather than U. + enum TrappingMode { + /// default: nothing enabled + Imprecise = 0, ///< no modifier + /// underflow/overflow traps enabled, inexact disabled + Underflow_Imprecise = 1, ///< /U or /V + Underflow_Precise = 5, ///< /SU or /SV + /// underflow/overflow and inexact traps enabled + Underflow_Inexact_Precise = 7 ///< /SUI or /SVI + }; + + protected: + /// Map Alpha rounding mode to C99 constants from <fenv.h>. + static const int alphaToC99RoundingMode[]; + + /// Map enum RoundingMode values to disassembly suffixes. + static const char *roundingModeSuffix[]; + /// Map enum TrappingMode values to FP disassembly suffixes. + static const char *fpTrappingModeSuffix[]; + /// Map enum TrappingMode values to integer disassembly suffixes. + static const char *intTrappingModeSuffix[]; + + /// This instruction's rounding mode. + RoundingMode roundingMode; + /// This instruction's trapping mode. + TrappingMode trappingMode; + + /// Have we warned about this instruction's unsupported + /// rounding mode (if applicable)? + mutable bool warnedOnRounding; + + /// Have we warned about this instruction's unsupported + /// trapping mode (if applicable)? + mutable bool warnedOnTrapping; + + /// Constructor + AlphaFP(const char *mnem, ExtMachInst _machInst, OpClass __opClass) + : AlphaStaticInst(mnem, _machInst, __opClass), + roundingMode((enum RoundingMode)FP_ROUNDMODE), + trappingMode((enum TrappingMode)FP_TRAPMODE), + warnedOnRounding(false), + warnedOnTrapping(false) + { + } + + int getC99RoundingMode(uint64_t fpcr_val) const; + + // This differs from the AlphaStaticInst version only in + // printing suffixes for non-default rounding & trapping modes. + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; + +}}; + + +output decoder {{ + int + AlphaFP::getC99RoundingMode(uint64_t fpcr_val) const + { + if (roundingMode == Dynamic) { + return alphaToC99RoundingMode[bits(fpcr_val, 59, 58)]; + } + else { + return alphaToC99RoundingMode[roundingMode]; + } + } + + std::string + AlphaFP::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + std::string mnem_str(mnemonic); + +#ifndef SS_COMPATIBLE_DISASSEMBLY + std::string suffix(""); + suffix += ((_destRegIdx[0] >= FP_Base_DepTag) + ? fpTrappingModeSuffix[trappingMode] + : intTrappingModeSuffix[trappingMode]); + suffix += roundingModeSuffix[roundingMode]; + + if (suffix != "") { + mnem_str = csprintf("%s/%s", mnemonic, suffix); + } +#endif + + std::stringstream ss; + ccprintf(ss, "%-10s ", mnem_str.c_str()); + + // just print the first two source regs... if there's + // a third one, it's a read-modify-write dest (Rc), + // e.g. for CMOVxx + if (_numSrcRegs > 0) { + printReg(ss, _srcRegIdx[0]); + } + if (_numSrcRegs > 1) { + ss << ","; + printReg(ss, _srcRegIdx[1]); + } + + // just print the first dest... if there's a second one, + // it's generally implicit + if (_numDestRegs > 0) { + if (_numSrcRegs > 0) + ss << ","; + printReg(ss, _destRegIdx[0]); + } + + return ss.str(); + } + + const int AlphaFP::alphaToC99RoundingMode[] = { + FE_TOWARDZERO, // Chopped + FE_DOWNWARD, // Minus_Infinity + FE_TONEAREST, // Normal + FE_UPWARD // Dynamic in inst, Plus_Infinity in FPCR + }; + + const char *AlphaFP::roundingModeSuffix[] = { "c", "m", "", "d" }; + // mark invalid trapping modes, but don't fail on them, because + // you could decode anything on a misspeculated path + const char *AlphaFP::fpTrappingModeSuffix[] = + { "", "u", "INVTM2", "INVTM3", "INVTM4", "su", "INVTM6", "sui" }; + const char *AlphaFP::intTrappingModeSuffix[] = + { "", "v", "INVTM2", "INVTM3", "INVTM4", "sv", "INVTM6", "svi" }; +}}; + +// FP instruction class execute method template. Handles non-standard +// rounding modes. +def template FloatingPointExecute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + if (trappingMode != Imprecise && !warnedOnTrapping) { + warn("%s: non-standard trapping mode not supported", + generateDisassembly(0, NULL)); + warnedOnTrapping = true; + } + + Fault fault = NoFault; + + %(fp_enable_check)s; + %(op_decl)s; + %(op_rd)s; +#if USE_FENV + if (roundingMode == Normal) { + %(code)s; + } else { + fesetround(getC99RoundingMode( + xc->readMiscReg(AlphaISA::Fpcr_DepTag))); + %(code)s; + fesetround(FE_TONEAREST); + } +#else + if (roundingMode != Normal && !warnedOnRounding) { + warn("%s: non-standard rounding mode not supported", + generateDisassembly(0, NULL)); + warnedOnRounding = true; + } + %(code)s; +#endif + + if (fault == NoFault) { + %(op_wb)s; + } + + return fault; + } +}}; + +// FP instruction class execute method template where no dynamic +// rounding mode control is needed. Like BasicExecute, but includes +// check & warning for non-standard trapping mode. +def template FPFixedRoundingExecute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + if (trappingMode != Imprecise && !warnedOnTrapping) { + warn("%s: non-standard trapping mode not supported", + generateDisassembly(0, NULL)); + warnedOnTrapping = true; + } + + Fault fault = NoFault; + + %(fp_enable_check)s; + %(op_decl)s; + %(op_rd)s; + %(code)s; + + if (fault == NoFault) { + %(op_wb)s; + } + + return fault; + } +}}; + +def template FloatingPointDecode {{ + { + AlphaStaticInst *i = new %(class_name)s(machInst); + if (FC == 31) { + i = makeNop(i); + } + return i; + } +}}; + +// General format for floating-point operate instructions: +// - Checks trapping and rounding mode flags. Trapping modes +// currently unimplemented (will fail). +// - Generates NOP if FC == 31. +def format FloatingPointOperate(code, *opt_args) {{ + iop = InstObjParams(name, Name, 'AlphaFP', CodeBlock(code), opt_args) + decode_block = FloatingPointDecode.subst(iop) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + exec_output = FloatingPointExecute.subst(iop) +}}; + +// Special format for cvttq where rounding mode is pre-decoded +def format FPFixedRounding(code, class_suffix, *opt_args) {{ + Name += class_suffix + iop = InstObjParams(name, Name, 'AlphaFP', CodeBlock(code), opt_args) + decode_block = FloatingPointDecode.subst(iop) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + exec_output = FPFixedRoundingExecute.subst(iop) +}}; + diff --git a/src/arch/alpha/isa/int.isa b/src/arch/alpha/isa/int.isa new file mode 100644 index 000000000..e097c8467 --- /dev/null +++ b/src/arch/alpha/isa/int.isa @@ -0,0 +1,133 @@ +// -*- mode:c++ -*- + +// Copyright (c) 2003-2005 The Regents of The University of Michigan +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +//////////////////////////////////////////////////////////////////// +// +// Integer operate instructions +// + +output header {{ + /** + * Base class for integer immediate instructions. + */ + class IntegerImm : public AlphaStaticInst + { + protected: + /// Immediate operand value (unsigned 8-bit int). + uint8_t imm; + + /// Constructor + IntegerImm(const char *mnem, ExtMachInst _machInst, OpClass __opClass) + : AlphaStaticInst(mnem, _machInst, __opClass), imm(INTIMM) + { + } + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; +}}; + +output decoder {{ + std::string + IntegerImm::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + std::stringstream ss; + + ccprintf(ss, "%-10s ", mnemonic); + + // just print the first source reg... if there's + // a second one, it's a read-modify-write dest (Rc), + // e.g. for CMOVxx + if (_numSrcRegs > 0) { + printReg(ss, _srcRegIdx[0]); + ss << ","; + } + + ss << (int)imm; + + if (_numDestRegs > 0) { + ss << ","; + printReg(ss, _destRegIdx[0]); + } + + return ss.str(); + } +}}; + + +def template RegOrImmDecode {{ + { + AlphaStaticInst *i = + (IMM) ? (AlphaStaticInst *)new %(class_name)sImm(machInst) + : (AlphaStaticInst *)new %(class_name)s(machInst); + if (RC == 31) { + i = makeNop(i); + } + return i; + } +}}; + +// Primary format for integer operate instructions: +// - Generates both reg-reg and reg-imm versions if Rb_or_imm is used. +// - Generates NOP if RC == 31. +def format IntegerOperate(code, *opt_flags) {{ + # If the code block contains 'Rb_or_imm', we define two instructions, + # one using 'Rb' and one using 'imm', and have the decoder select + # the right one. + uses_imm = (code.find('Rb_or_imm') != -1) + if uses_imm: + orig_code = code + # base code is reg version: + # rewrite by substituting 'Rb' for 'Rb_or_imm' + code = re.sub(r'Rb_or_imm', 'Rb', orig_code) + # generate immediate version by substituting 'imm' + # note that imm takes no extenstion, so we extend + # the regexp to replace any extension as well + imm_code = re.sub(r'Rb_or_imm(\.\w+)?', 'imm', orig_code) + + # generate declaration for register version + cblk = CodeBlock(code) + iop = InstObjParams(name, Name, 'AlphaStaticInst', cblk, opt_flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + exec_output = BasicExecute.subst(iop) + + if uses_imm: + # append declaration for imm version + imm_cblk = CodeBlock(imm_code) + imm_iop = InstObjParams(name, Name + 'Imm', 'IntegerImm', imm_cblk, + opt_flags) + header_output += BasicDeclare.subst(imm_iop) + decoder_output += BasicConstructor.subst(imm_iop) + exec_output += BasicExecute.subst(imm_iop) + # decode checks IMM bit to pick correct version + decode_block = RegOrImmDecode.subst(iop) + else: + # no imm version: just check for nop + decode_block = OperateNopCheckDecode.subst(iop) +}}; diff --git a/src/arch/alpha/isa/main.isa b/src/arch/alpha/isa/main.isa new file mode 100644 index 000000000..25d9cc6e9 --- /dev/null +++ b/src/arch/alpha/isa/main.isa @@ -0,0 +1,461 @@ +// -*- mode:c++ -*- + +// Copyright (c) 2003-2005 The Regents of The University of Michigan +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +//////////////////////////////////////////////////////////////////// +// +// Alpha ISA description file. +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// +// Output include file directives. +// + +output header {{ +#include <sstream> +#include <iostream> +#include <iomanip> + +#include "config/ss_compatible_fp.hh" +#include "cpu/static_inst.hh" +#include "arch/alpha/faults.hh" +#include "mem/request.hh" // some constructors use MemReq flags +}}; + +output decoder {{ +#include "base/cprintf.hh" +#include "base/fenv.hh" +#include "base/loader/symtab.hh" +#include "config/ss_compatible_fp.hh" +#include "cpu/exec_context.hh" // for Jump::branchTarget() + +#include <math.h> + +using namespace AlphaISA; +}}; + +output exec {{ +#include <math.h> + +#if FULL_SYSTEM +#include "sim/pseudo_inst.hh" +#endif +#include "base/fenv.hh" +#include "config/ss_compatible_fp.hh" +#include "cpu/base.hh" +#include "cpu/exetrace.hh" +#include "sim/sim_exit.hh" +#include "mem/packet_impl.hh" + +using namespace AlphaISA; +}}; + +//////////////////////////////////////////////////////////////////// +// +// Namespace statement. Everything below this line will be in the +// AlphaISAInst namespace. +// + + +namespace AlphaISA; + +//////////////////////////////////////////////////////////////////// +// +// Bitfield definitions. +// + +// Universal (format-independent) fields +def bitfield PALMODE <32:32>; +def bitfield OPCODE <31:26>; +def bitfield RA <25:21>; +def bitfield RB <20:16>; + +// Memory format +def signed bitfield MEMDISP <15: 0>; // displacement +def bitfield MEMFUNC <15: 0>; // function code (same field, unsigned) + +// Memory-format jumps +def bitfield JMPFUNC <15:14>; // function code (disp<15:14>) +def bitfield JMPHINT <13: 0>; // tgt Icache idx hint (disp<13:0>) + +// Branch format +def signed bitfield BRDISP <20: 0>; // displacement + +// Integer operate format(s>; +def bitfield INTIMM <20:13>; // integer immediate (literal) +def bitfield IMM <12:12>; // immediate flag +def bitfield INTFUNC <11: 5>; // function code +def bitfield RC < 4: 0>; // dest reg + +// Floating-point operate format +def bitfield FA <25:21>; +def bitfield FB <20:16>; +def bitfield FP_FULLFUNC <15: 5>; // complete function code + def bitfield FP_TRAPMODE <15:13>; // trapping mode + def bitfield FP_ROUNDMODE <12:11>; // rounding mode + def bitfield FP_TYPEFUNC <10: 5>; // type+func: handiest for decoding + def bitfield FP_SRCTYPE <10: 9>; // source reg type + def bitfield FP_SHORTFUNC < 8: 5>; // short function code + def bitfield FP_SHORTFUNC_TOP2 <8:7>; // top 2 bits of short func code +def bitfield FC < 4: 0>; // dest reg + +// PALcode format +def bitfield PALFUNC <25: 0>; // function code + +// EV5 PAL instructions: +// HW_LD/HW_ST +def bitfield HW_LDST_PHYS <15>; // address is physical +def bitfield HW_LDST_ALT <14>; // use ALT_MODE IPR +def bitfield HW_LDST_WRTCK <13>; // HW_LD only: fault if no write acc +def bitfield HW_LDST_QUAD <12>; // size: 0=32b, 1=64b +def bitfield HW_LDST_VPTE <11>; // HW_LD only: is PTE fetch +def bitfield HW_LDST_LOCK <10>; // HW_LD only: is load locked +def bitfield HW_LDST_COND <10>; // HW_ST only: is store conditional +def signed bitfield HW_LDST_DISP <9:0>; // signed displacement + +// HW_REI +def bitfield HW_REI_TYP <15:14>; // type: stalling vs. non-stallingk +def bitfield HW_REI_MBZ <13: 0>; // must be zero + +// HW_MTPR/MW_MFPR +def bitfield HW_IPR_IDX <15:0>; // IPR index + +// M5 instructions +def bitfield M5FUNC <7:0>; + +def operand_types {{ + 'sb' : ('signed int', 8), + 'ub' : ('unsigned int', 8), + 'sw' : ('signed int', 16), + 'uw' : ('unsigned int', 16), + 'sl' : ('signed int', 32), + 'ul' : ('unsigned int', 32), + 'sq' : ('signed int', 64), + 'uq' : ('unsigned int', 64), + 'sf' : ('float', 32), + 'df' : ('float', 64) +}}; + +def operands {{ + # Int regs default to unsigned, but code should not count on this. + # For clarity, descriptions that depend on unsigned behavior should + # explicitly specify '.uq'. + 'Ra': ('IntReg', 'uq', 'PALMODE ? AlphaISA::reg_redir[RA] : RA', + 'IsInteger', 1), + 'Rb': ('IntReg', 'uq', 'PALMODE ? AlphaISA::reg_redir[RB] : RB', + 'IsInteger', 2), + 'Rc': ('IntReg', 'uq', 'PALMODE ? AlphaISA::reg_redir[RC] : RC', + 'IsInteger', 3), + 'Fa': ('FloatReg', 'df', 'FA', 'IsFloating', 1), + 'Fb': ('FloatReg', 'df', 'FB', 'IsFloating', 2), + 'Fc': ('FloatReg', 'df', 'FC', 'IsFloating', 3), + 'Mem': ('Mem', 'uq', None, ('IsMemRef', 'IsLoad', 'IsStore'), 4), + 'NPC': ('NPC', 'uq', None, ( None, None, 'IsControl' ), 4), + 'Runiq': ('ControlReg', 'uq', 'TheISA::Uniq_DepTag', None, 1), + 'FPCR': (' ControlReg', 'uq', 'TheISA::Fpcr_DepTag', None, 1), + # The next two are hacks for non-full-system call-pal emulation + 'R0': ('IntReg', 'uq', '0', None, 1), + 'R16': ('IntReg', 'uq', '16', None, 1), + 'R17': ('IntReg', 'uq', '17', None, 1), + 'R18': ('IntReg', 'uq', '18', None, 1) +}}; + +//////////////////////////////////////////////////////////////////// +// +// Basic instruction classes/templates/formats etc. +// + +output header {{ +// uncomment the following to get SimpleScalar-compatible disassembly +// (useful for diffing output traces). +// #define SS_COMPATIBLE_DISASSEMBLY + + /** + * Base class for all Alpha static instructions. + */ + class AlphaStaticInst : public StaticInst + { + protected: + + /// Make AlphaISA register dependence tags directly visible in + /// this class and derived classes. Maybe these should really + /// live here and not in the AlphaISA namespace. + enum DependenceTags { + FP_Base_DepTag = AlphaISA::FP_Base_DepTag, + Fpcr_DepTag = AlphaISA::Fpcr_DepTag, + Uniq_DepTag = AlphaISA::Uniq_DepTag, + Lock_Flag_DepTag = AlphaISA::Lock_Flag_DepTag, + Lock_Addr_DepTag = AlphaISA::Lock_Addr_DepTag, + IPR_Base_DepTag = AlphaISA::IPR_Base_DepTag + }; + + /// Constructor. + AlphaStaticInst(const char *mnem, ExtMachInst _machInst, + OpClass __opClass) + : StaticInst(mnem, _machInst, __opClass) + { + } + + /// Print a register name for disassembly given the unique + /// dependence tag number (FP or int). + void printReg(std::ostream &os, int reg) const; + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; +}}; + +output decoder {{ + void + AlphaStaticInst::printReg(std::ostream &os, int reg) const + { + if (reg < FP_Base_DepTag) { + ccprintf(os, "r%d", reg); + } + else { + ccprintf(os, "f%d", reg - FP_Base_DepTag); + } + } + + std::string + AlphaStaticInst::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { + std::stringstream ss; + + ccprintf(ss, "%-10s ", mnemonic); + + // just print the first two source regs... if there's + // a third one, it's a read-modify-write dest (Rc), + // e.g. for CMOVxx + if (_numSrcRegs > 0) { + printReg(ss, _srcRegIdx[0]); + } + if (_numSrcRegs > 1) { + ss << ","; + printReg(ss, _srcRegIdx[1]); + } + + // just print the first dest... if there's a second one, + // it's generally implicit + if (_numDestRegs > 0) { + if (_numSrcRegs > 0) + ss << ","; + printReg(ss, _destRegIdx[0]); + } + + return ss.str(); + } +}}; + +// Declarations for execute() methods. +def template BasicExecDeclare {{ + Fault execute(%(CPU_exec_context)s *, Trace::InstRecord *) const; +}}; + +// Basic instruction class declaration template. +def template BasicDeclare {{ + /** + * Static instruction class for "%(mnemonic)s". + */ + class %(class_name)s : public %(base_class)s + { + public: + /// Constructor. + %(class_name)s(ExtMachInst machInst); + + %(BasicExecDeclare)s + }; +}}; + +// Basic instruction class constructor template. +def template BasicConstructor {{ + inline %(class_name)s::%(class_name)s(ExtMachInst machInst) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s) + { + %(constructor)s; + } +}}; + +// Basic instruction class execute method template. +def template BasicExecute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Fault fault = NoFault; + + %(fp_enable_check)s; + %(op_decl)s; + %(op_rd)s; + %(code)s; + + if (fault == NoFault) { + %(op_wb)s; + } + + return fault; + } +}}; + +// Basic decode template. +def template BasicDecode {{ + return new %(class_name)s(machInst); +}}; + +// Basic decode template, passing mnemonic in as string arg to constructor. +def template BasicDecodeWithMnemonic {{ + return new %(class_name)s("%(mnemonic)s", machInst); +}}; + +// The most basic instruction format... used only for a few misc. insts +def format BasicOperate(code, *flags) {{ + iop = InstObjParams(name, Name, 'AlphaStaticInst', CodeBlock(code), flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; + + + +//////////////////////////////////////////////////////////////////// +// +// Nop +// + +output header {{ + /** + * Static instruction class for no-ops. This is a leaf class. + */ + class Nop : public AlphaStaticInst + { + /// Disassembly of original instruction. + const std::string originalDisassembly; + + public: + /// Constructor + Nop(const std::string _originalDisassembly, ExtMachInst _machInst) + : AlphaStaticInst("nop", _machInst, No_OpClass), + originalDisassembly(_originalDisassembly) + { + flags[IsNop] = true; + } + + ~Nop() { } + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + + %(BasicExecDeclare)s + }; + + /// Helper function for decoding nops. Substitute Nop object + /// for original inst passed in as arg (and delete latter). + static inline + AlphaStaticInst * + makeNop(AlphaStaticInst *inst) + { + AlphaStaticInst *nop = new Nop(inst->disassemble(0), inst->machInst); + delete inst; + return nop; + } +}}; + +output decoder {{ + std::string Nop::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { +#ifdef SS_COMPATIBLE_DISASSEMBLY + return originalDisassembly; +#else + return csprintf("%-10s (%s)", "nop", originalDisassembly); +#endif + } +}}; + +output exec {{ + Fault + Nop::execute(%(CPU_exec_context)s *, Trace::InstRecord *) const + { + return NoFault; + } +}}; + +// integer & FP operate instructions use Rc as dest, so check for +// Rc == 31 to detect nops +def template OperateNopCheckDecode {{ + { + AlphaStaticInst *i = new %(class_name)s(machInst); + if (RC == 31) { + i = makeNop(i); + } + return i; + } +}}; + +// Like BasicOperate format, but generates NOP if RC/FC == 31 +def format BasicOperateWithNopCheck(code, *opt_args) {{ + iop = InstObjParams(name, Name, 'AlphaStaticInst', CodeBlock(code), + opt_args) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = OperateNopCheckDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; + +// Integer instruction templates, formats, etc. +##include "int.isa" + +// Floating-point instruction templates, formats, etc. +##include "fp.isa" + +// Memory instruction templates, formats, etc. +##include "mem.isa" + +// Branch/jump instruction templates, formats, etc. +##include "branch.isa" + +// PAL instruction templates, formats, etc. +##include "pal.isa" + +// Opcdec fault instruction templates, formats, etc. +##include "opcdec.isa" + +// Unimplemented instruction templates, formats, etc. +##include "unimp.isa" + +// Unknown instruction templates, formats, etc. +##include "unknown.isa" + +// Execution utility functions +##include "util.isa" + +// The actual decoder +##include "decoder.isa" diff --git a/src/arch/alpha/isa/mem.isa b/src/arch/alpha/isa/mem.isa new file mode 100644 index 000000000..b2e6fc07e --- /dev/null +++ b/src/arch/alpha/isa/mem.isa @@ -0,0 +1,734 @@ +// -*- mode:c++ -*- + +// Copyright (c) 2003-2005 The Regents of The University of Michigan +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +//////////////////////////////////////////////////////////////////// +// +// Memory-format instructions: LoadAddress, Load, Store +// + +output header {{ + /** + * Base class for general Alpha memory-format instructions. + */ + class Memory : public AlphaStaticInst + { + protected: + + /// Memory request flags. See mem_req_base.hh. + unsigned memAccessFlags; + /// Pointer to EAComp object. + const StaticInstPtr eaCompPtr; + /// Pointer to MemAcc object. + const StaticInstPtr memAccPtr; + + /// Constructor + Memory(const char *mnem, ExtMachInst _machInst, OpClass __opClass, + StaticInstPtr _eaCompPtr = nullStaticInstPtr, + StaticInstPtr _memAccPtr = nullStaticInstPtr) + : AlphaStaticInst(mnem, _machInst, __opClass), + memAccessFlags(0), eaCompPtr(_eaCompPtr), memAccPtr(_memAccPtr) + { + } + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + + public: + + const StaticInstPtr &eaCompInst() const { return eaCompPtr; } + const StaticInstPtr &memAccInst() const { return memAccPtr; } + }; + + /** + * Base class for memory-format instructions using a 32-bit + * displacement (i.e. most of them). + */ + class MemoryDisp32 : public Memory + { + protected: + /// Displacement for EA calculation (signed). + int32_t disp; + + /// Constructor. + MemoryDisp32(const char *mnem, ExtMachInst _machInst, OpClass __opClass, + StaticInstPtr _eaCompPtr = nullStaticInstPtr, + StaticInstPtr _memAccPtr = nullStaticInstPtr) + : Memory(mnem, _machInst, __opClass, _eaCompPtr, _memAccPtr), + disp(MEMDISP) + { + } + }; + + + /** + * Base class for a few miscellaneous memory-format insts + * that don't interpret the disp field: wh64, fetch, fetch_m, ecb. + * None of these instructions has a destination register either. + */ + class MemoryNoDisp : public Memory + { + protected: + /// Constructor + MemoryNoDisp(const char *mnem, ExtMachInst _machInst, OpClass __opClass, + StaticInstPtr _eaCompPtr = nullStaticInstPtr, + StaticInstPtr _memAccPtr = nullStaticInstPtr) + : Memory(mnem, _machInst, __opClass, _eaCompPtr, _memAccPtr) + { + } + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; +}}; + + +output decoder {{ + std::string + Memory::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + return csprintf("%-10s %c%d,%d(r%d)", mnemonic, + flags[IsFloating] ? 'f' : 'r', RA, MEMDISP, RB); + } + + std::string + MemoryNoDisp::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + return csprintf("%-10s (r%d)", mnemonic, RB); + } +}}; + +def format LoadAddress(code) {{ + iop = InstObjParams(name, Name, 'MemoryDisp32', CodeBlock(code)) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; + + +def template LoadStoreDeclare {{ + /** + * Static instruction class for "%(mnemonic)s". + */ + class %(class_name)s : public %(base_class)s + { + protected: + + /** + * "Fake" effective address computation class for "%(mnemonic)s". + */ + class EAComp : public %(base_class)s + { + public: + /// Constructor + EAComp(ExtMachInst machInst); + + %(BasicExecDeclare)s + }; + + /** + * "Fake" memory access instruction class for "%(mnemonic)s". + */ + class MemAcc : public %(base_class)s + { + public: + /// Constructor + MemAcc(ExtMachInst machInst); + + %(BasicExecDeclare)s + }; + + public: + + /// Constructor. + %(class_name)s(ExtMachInst machInst); + + %(BasicExecDeclare)s + + %(InitiateAccDeclare)s + + %(CompleteAccDeclare)s + }; +}}; + + +def template InitiateAccDeclare {{ + Fault initiateAcc(%(CPU_exec_context)s *, Trace::InstRecord *) const; +}}; + + +def template CompleteAccDeclare {{ + Fault completeAcc(Packet *, %(CPU_exec_context)s *, + Trace::InstRecord *) const; +}}; + + +def template LoadStoreConstructor {{ + /** TODO: change op_class to AddrGenOp or something (requires + * creating new member of OpClass enum in op_class.hh, updating + * config files, etc.). */ + inline %(class_name)s::EAComp::EAComp(ExtMachInst machInst) + : %(base_class)s("%(mnemonic)s (EAComp)", machInst, IntAluOp) + { + %(ea_constructor)s; + } + + inline %(class_name)s::MemAcc::MemAcc(ExtMachInst machInst) + : %(base_class)s("%(mnemonic)s (MemAcc)", machInst, %(op_class)s) + { + %(memacc_constructor)s; + } + + inline %(class_name)s::%(class_name)s(ExtMachInst machInst) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + new EAComp(machInst), new MemAcc(machInst)) + { + %(constructor)s; + } +}}; + + +def template EACompExecute {{ + Fault + %(class_name)s::EAComp::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + + %(fp_enable_check)s; + %(op_decl)s; + %(op_rd)s; + %(code)s; + + if (fault == NoFault) { + %(op_wb)s; + xc->setEA(EA); + } + + return fault; + } +}}; + +def template LoadMemAccExecute {{ + Fault + %(class_name)s::MemAcc::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + + %(fp_enable_check)s; + %(op_decl)s; + %(op_rd)s; + EA = xc->getEA(); + + if (fault == NoFault) { + fault = xc->read(EA, (uint%(mem_acc_size)d_t&)Mem, memAccessFlags); + %(code)s; + } + + if (fault == NoFault) { + %(op_wb)s; + } + + return fault; + } +}}; + + +def template LoadExecute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + + %(fp_enable_check)s; + %(op_decl)s; + %(op_rd)s; + %(ea_code)s; + + if (fault == NoFault) { + fault = xc->read(EA, (uint%(mem_acc_size)d_t&)Mem, memAccessFlags); + %(memacc_code)s; + } + + if (fault == NoFault) { + %(op_wb)s; + } + + return fault; + } +}}; + + +def template LoadInitiateAcc {{ + Fault %(class_name)s::initiateAcc(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + + %(fp_enable_check)s; + %(op_src_decl)s; + %(op_rd)s; + %(ea_code)s; + + if (fault == NoFault) { + fault = xc->read(EA, (uint%(mem_acc_size)d_t &)Mem, memAccessFlags); + } + + return fault; + } +}}; + + +def template LoadCompleteAcc {{ + Fault %(class_name)s::completeAcc(Packet *pkt, + %(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Fault fault = NoFault; + + %(fp_enable_check)s; + %(op_decl)s; + + Mem = pkt->get<typeof(Mem)>(); + + if (fault == NoFault) { + %(memacc_code)s; + } + + if (fault == NoFault) { + %(op_wb)s; + } + + return fault; + } +}}; + + +def template StoreMemAccExecute {{ + Fault + %(class_name)s::MemAcc::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + uint64_t write_result = 0; + + %(fp_enable_check)s; + %(op_decl)s; + %(op_rd)s; + EA = xc->getEA(); + + if (fault == NoFault) { + %(code)s; + } + + if (fault == NoFault) { + fault = xc->write((uint%(mem_acc_size)d_t&)Mem, EA, + memAccessFlags, &write_result); + if (traceData) { traceData->setData(Mem); } + } + + if (fault == NoFault) { + %(postacc_code)s; + } + + if (fault == NoFault) { + %(op_wb)s; + } + + return fault; + } +}}; + + +def template StoreExecute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + uint64_t write_result = 0; + + %(fp_enable_check)s; + %(op_decl)s; + %(op_rd)s; + %(ea_code)s; + + if (fault == NoFault) { + %(memacc_code)s; + } + + if (fault == NoFault) { + fault = xc->write((uint%(mem_acc_size)d_t&)Mem, EA, + memAccessFlags, &write_result); + if (traceData) { traceData->setData(Mem); } + } + + if (fault == NoFault) { + %(postacc_code)s; + } + + if (fault == NoFault) { + %(op_wb)s; + } + + return fault; + } +}}; + +def template StoreInitiateAcc {{ + Fault %(class_name)s::initiateAcc(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + + %(fp_enable_check)s; + %(op_decl)s; + %(op_rd)s; + %(ea_code)s; + + if (fault == NoFault) { + %(memacc_code)s; + } + + if (fault == NoFault) { + fault = xc->write((uint%(mem_acc_size)d_t&)Mem, EA, + memAccessFlags, NULL); + if (traceData) { traceData->setData(Mem); } + } + + return fault; + } +}}; + + +def template StoreCompleteAcc {{ + Fault %(class_name)s::completeAcc(Packet *pkt, + %(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Fault fault = NoFault; + + %(fp_enable_check)s; + %(op_dest_decl)s; + + if (fault == NoFault) { + %(postacc_code)s; + } + + if (fault == NoFault) { + %(op_wb)s; + } + + return fault; + } +}}; + + +def template StoreCondCompleteAcc {{ + Fault %(class_name)s::completeAcc(Packet *pkt, + %(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Fault fault = NoFault; + + %(fp_enable_check)s; + %(op_dest_decl)s; + + uint64_t write_result = pkt->req->getScResult(); + + if (fault == NoFault) { + %(postacc_code)s; + } + + if (fault == NoFault) { + %(op_wb)s; + } + + return fault; + } +}}; + + +def template MiscMemAccExecute {{ + Fault %(class_name)s::MemAcc::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + + %(fp_enable_check)s; + %(op_decl)s; + %(op_rd)s; + EA = xc->getEA(); + + if (fault == NoFault) { + %(code)s; + } + + return NoFault; + } +}}; + +def template MiscExecute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + + %(fp_enable_check)s; + %(op_decl)s; + %(op_rd)s; + %(ea_code)s; + + if (fault == NoFault) { + %(memacc_code)s; + } + + return NoFault; + } +}}; + +def template MiscInitiateAcc {{ + Fault %(class_name)s::initiateAcc(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + panic("Misc instruction does not support split access method!"); + return NoFault; + } +}}; + + +def template MiscCompleteAcc {{ + Fault %(class_name)s::completeAcc(Packet *pkt, + %(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + panic("Misc instruction does not support split access method!"); + + return NoFault; + } +}}; + +// load instructions use Ra as dest, so check for +// Ra == 31 to detect nops +def template LoadNopCheckDecode {{ + { + AlphaStaticInst *i = new %(class_name)s(machInst); + if (RA == 31) { + i = makeNop(i); + } + return i; + } +}}; + + +// for some load instructions, Ra == 31 indicates a prefetch (not a nop) +def template LoadPrefetchCheckDecode {{ + { + if (RA != 31) { + return new %(class_name)s(machInst); + } + else { + return new %(class_name)sPrefetch(machInst); + } + } +}}; + + +let {{ +def LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, + postacc_code = '', base_class = 'MemoryDisp32', + decode_template = BasicDecode, exec_template_base = ''): + # Make sure flags are in lists (convert to lists if not). + mem_flags = makeList(mem_flags) + inst_flags = makeList(inst_flags) + + # add hook to get effective addresses into execution trace output. + ea_code += '\nif (traceData) { traceData->setAddr(EA); }\n' + + # generate code block objects + ea_cblk = CodeBlock(ea_code) + memacc_cblk = CodeBlock(memacc_code) + postacc_cblk = CodeBlock(postacc_code) + + # Some CPU models execute the memory operation as an atomic unit, + # while others want to separate them into an effective address + # computation and a memory access operation. As a result, we need + # to generate three StaticInst objects. Note that the latter two + # are nested inside the larger "atomic" one. + + # generate InstObjParams for EAComp object + ea_iop = InstObjParams(name, Name, base_class, ea_cblk, inst_flags) + + # generate InstObjParams for MemAcc object + memacc_iop = InstObjParams(name, Name, base_class, memacc_cblk, inst_flags) + # in the split execution model, the MemAcc portion is responsible + # for the post-access code. + memacc_iop.postacc_code = postacc_cblk.code + + # generate InstObjParams for InitiateAcc, CompleteAcc object + # The code used depends on the template being used + if (exec_template_base == 'Load'): + initiateacc_cblk = CodeBlock(ea_code + memacc_code) + completeacc_cblk = CodeBlock(memacc_code + postacc_code) + elif (exec_template_base.startswith('Store')): + initiateacc_cblk = CodeBlock(ea_code + memacc_code) + completeacc_cblk = CodeBlock(postacc_code) + else: + initiateacc_cblk = '' + completeacc_cblk = '' + + initiateacc_iop = InstObjParams(name, Name, base_class, initiateacc_cblk, + inst_flags) + + completeacc_iop = InstObjParams(name, Name, base_class, completeacc_cblk, + inst_flags) + + if (exec_template_base == 'Load'): + initiateacc_iop.ea_code = ea_cblk.code + initiateacc_iop.memacc_code = memacc_cblk.code + completeacc_iop.memacc_code = memacc_cblk.code + completeacc_iop.postacc_code = postacc_cblk.code + elif (exec_template_base.startswith('Store')): + initiateacc_iop.ea_code = ea_cblk.code + initiateacc_iop.memacc_code = memacc_cblk.code + completeacc_iop.postacc_code = postacc_cblk.code + + # generate InstObjParams for unified execution + cblk = CodeBlock(ea_code + memacc_code + postacc_code) + iop = InstObjParams(name, Name, base_class, cblk, inst_flags) + + iop.ea_constructor = ea_cblk.constructor + iop.ea_code = ea_cblk.code + iop.memacc_constructor = memacc_cblk.constructor + iop.memacc_code = memacc_cblk.code + iop.postacc_code = postacc_cblk.code + + if mem_flags: + s = '\n\tmemAccessFlags = ' + string.join(mem_flags, '|') + ';' + iop.constructor += s + memacc_iop.constructor += s + + # select templates + + # define aliases... most StoreCond templates are the same as the + # corresponding Store templates (only CompleteAcc is different). + StoreCondMemAccExecute = StoreMemAccExecute + StoreCondExecute = StoreExecute + StoreCondInitiateAcc = StoreInitiateAcc + + memAccExecTemplate = eval(exec_template_base + 'MemAccExecute') + fullExecTemplate = eval(exec_template_base + 'Execute') + initiateAccTemplate = eval(exec_template_base + 'InitiateAcc') + completeAccTemplate = eval(exec_template_base + 'CompleteAcc') + + # (header_output, decoder_output, decode_block, exec_output) + return (LoadStoreDeclare.subst(iop), LoadStoreConstructor.subst(iop), + decode_template.subst(iop), + EACompExecute.subst(ea_iop) + + memAccExecTemplate.subst(memacc_iop) + + fullExecTemplate.subst(iop) + + initiateAccTemplate.subst(initiateacc_iop) + + completeAccTemplate.subst(completeacc_iop)) +}}; + + +def format LoadOrNop(memacc_code, ea_code = {{ EA = Rb + disp; }}, + mem_flags = [], inst_flags = []) {{ + (header_output, decoder_output, decode_block, exec_output) = \ + LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, + decode_template = LoadNopCheckDecode, + exec_template_base = 'Load') +}}; + + +// Note that the flags passed in apply only to the prefetch version +def format LoadOrPrefetch(memacc_code, ea_code = {{ EA = Rb + disp; }}, + mem_flags = [], pf_flags = [], inst_flags = []) {{ + # declare the load instruction object and generate the decode block + (header_output, decoder_output, decode_block, exec_output) = \ + LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, + decode_template = LoadPrefetchCheckDecode, + exec_template_base = 'Load') + + # Declare the prefetch instruction object. + + # Make sure flag args are lists so we can mess with them. + mem_flags = makeList(mem_flags) + pf_flags = makeList(pf_flags) + inst_flags = makeList(inst_flags) + + pf_mem_flags = mem_flags + pf_flags + ['NO_FAULT'] + pf_inst_flags = inst_flags + ['IsMemRef', 'IsLoad', + 'IsDataPrefetch', 'MemReadOp'] + + (pf_header_output, pf_decoder_output, _, pf_exec_output) = \ + LoadStoreBase(name, Name + 'Prefetch', ea_code, + 'xc->prefetch(EA, memAccessFlags);', + pf_mem_flags, pf_inst_flags, exec_template_base = 'Misc') + + header_output += pf_header_output + decoder_output += pf_decoder_output + exec_output += pf_exec_output +}}; + + +def format Store(memacc_code, ea_code = {{ EA = Rb + disp; }}, + mem_flags = [], inst_flags = []) {{ + (header_output, decoder_output, decode_block, exec_output) = \ + LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, + exec_template_base = 'Store') +}}; + + +def format StoreCond(memacc_code, postacc_code, + ea_code = {{ EA = Rb + disp; }}, + mem_flags = [], inst_flags = []) {{ + (header_output, decoder_output, decode_block, exec_output) = \ + LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, + postacc_code, exec_template_base = 'StoreCond') +}}; + + +// Use 'MemoryNoDisp' as base: for wh64, fetch, ecb +def format MiscPrefetch(ea_code, memacc_code, + mem_flags = [], inst_flags = []) {{ + (header_output, decoder_output, decode_block, exec_output) = \ + LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, + base_class = 'MemoryNoDisp', exec_template_base = 'Misc') +}}; + + diff --git a/src/arch/alpha/isa/opcdec.isa b/src/arch/alpha/isa/opcdec.isa new file mode 100644 index 000000000..add4704dd --- /dev/null +++ b/src/arch/alpha/isa/opcdec.isa @@ -0,0 +1,77 @@ +// -*- mode:c++ -*- + +// Copyright (c) 2003-2005 The Regents of The University of Michigan +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +//////////////////////////////////////////////////////////////////// +// +// OPCDEC fault instructions +// + +output header {{ + /** + * Static instruction class for instructions that cause an OPCDEC fault + * when executed. This is currently only for PAL mode instructions + * executed in non-PAL mode. + */ + class OpcdecFault : public AlphaStaticInst + { + public: + /// Constructor + OpcdecFault(ExtMachInst _machInst) + : AlphaStaticInst("opcdec fault", _machInst, No_OpClass) + { + } + + %(BasicExecDeclare)s + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; +}}; + +output decoder {{ + std::string + OpcdecFault::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + return csprintf("%-10s (inst 0x%x, opcode 0x%x)", + " OPCDEC fault", machInst, OPCODE); + } +}}; + +output exec {{ + Fault + OpcdecFault::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + return new UnimplementedOpcodeFault; + } +}}; + +def format OpcdecFault() {{ + decode_block = 'return new OpcdecFault(machInst);\n' +}}; + diff --git a/src/arch/alpha/isa/pal.isa b/src/arch/alpha/isa/pal.isa new file mode 100644 index 000000000..37de20617 --- /dev/null +++ b/src/arch/alpha/isa/pal.isa @@ -0,0 +1,278 @@ +// -*- mode:c++ -*- + +// Copyright (c) 2003-2005 The Regents of The University of Michigan +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +//////////////////////////////////////////////////////////////////// +// +// PAL calls & PAL-specific instructions +// + +output header {{ + /** + * Base class for emulated call_pal calls (used only in + * non-full-system mode). + */ + class EmulatedCallPal : public AlphaStaticInst + { + protected: + + /// Constructor. + EmulatedCallPal(const char *mnem, ExtMachInst _machInst, + OpClass __opClass) + : AlphaStaticInst(mnem, _machInst, __opClass) + { + } + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; +}}; + +output decoder {{ + std::string + EmulatedCallPal::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { +#ifdef SS_COMPATIBLE_DISASSEMBLY + return csprintf("%s %s", "call_pal", mnemonic); +#else + return csprintf("%-10s %s", "call_pal", mnemonic); +#endif + } +}}; + +def format EmulatedCallPal(code, *flags) {{ + iop = InstObjParams(name, Name, 'EmulatedCallPal', CodeBlock(code), flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; + +output header {{ + /** + * Base class for full-system-mode call_pal instructions. + * Probably could turn this into a leaf class and get rid of the + * parser template. + */ + class CallPalBase : public AlphaStaticInst + { + protected: + int palFunc; ///< Function code part of instruction + int palOffset; ///< Target PC, offset from IPR_PAL_BASE + bool palValid; ///< is the function code valid? + bool palPriv; ///< is this call privileged? + + /// Constructor. + CallPalBase(const char *mnem, ExtMachInst _machInst, + OpClass __opClass); + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; +}}; + +output decoder {{ + inline + CallPalBase::CallPalBase(const char *mnem, ExtMachInst _machInst, + OpClass __opClass) + : AlphaStaticInst(mnem, _machInst, __opClass), + palFunc(PALFUNC) + { + // From the 21164 HRM (paraphrased): + // Bit 7 of the function code (mask 0x80) indicates + // whether the call is privileged (bit 7 == 0) or + // unprivileged (bit 7 == 1). The privileged call table + // starts at 0x2000, the unprivielged call table starts at + // 0x3000. Bits 5-0 (mask 0x3f) are used to calculate the + // offset. + const int palPrivMask = 0x80; + const int palOffsetMask = 0x3f; + + // Pal call is invalid unless all other bits are 0 + palValid = ((machInst & ~(palPrivMask | palOffsetMask)) == 0); + palPriv = ((machInst & palPrivMask) == 0); + int shortPalFunc = (machInst & palOffsetMask); + // Add 1 to base to set pal-mode bit + palOffset = (palPriv ? 0x2001 : 0x3001) + (shortPalFunc << 6); + } + + std::string + CallPalBase::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + return csprintf("%-10s %#x", "call_pal", palFunc); + } +}}; + +def format CallPal(code, *flags) {{ + iop = InstObjParams(name, Name, 'CallPalBase', CodeBlock(code), flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; + +//////////////////////////////////////////////////////////////////// +// +// hw_ld, hw_st +// + +output header {{ + /** + * Base class for hw_ld and hw_st. + */ + class HwLoadStore : public Memory + { + protected: + + /// Displacement for EA calculation (signed). + int16_t disp; + + /// Constructor + HwLoadStore(const char *mnem, ExtMachInst _machInst, OpClass __opClass, + StaticInstPtr _eaCompPtr = nullStaticInstPtr, + StaticInstPtr _memAccPtr = nullStaticInstPtr); + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; +}}; + + +output decoder {{ + inline + HwLoadStore::HwLoadStore(const char *mnem, ExtMachInst _machInst, + OpClass __opClass, + StaticInstPtr _eaCompPtr, + StaticInstPtr _memAccPtr) + : Memory(mnem, _machInst, __opClass, _eaCompPtr, _memAccPtr), + disp(HW_LDST_DISP) + { + memAccessFlags = 0; + if (HW_LDST_PHYS) memAccessFlags |= PHYSICAL; + if (HW_LDST_ALT) memAccessFlags |= ALTMODE; + if (HW_LDST_VPTE) memAccessFlags |= VPTE; + if (HW_LDST_LOCK) memAccessFlags |= LOCKED; + } + + std::string + HwLoadStore::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { +#ifdef SS_COMPATIBLE_DISASSEMBLY + return csprintf("%-10s r%d,%d(r%d)", mnemonic, RA, disp, RB); +#else + // HW_LDST_LOCK and HW_LDST_COND are the same bit. + const char *lock_str = + (HW_LDST_LOCK) ? (flags[IsLoad] ? ",LOCK" : ",COND") : ""; + + return csprintf("%-10s r%d,%d(r%d)%s%s%s%s%s", + mnemonic, RA, disp, RB, + HW_LDST_PHYS ? ",PHYS" : "", + HW_LDST_ALT ? ",ALT" : "", + HW_LDST_QUAD ? ",QUAD" : "", + HW_LDST_VPTE ? ",VPTE" : "", + lock_str); +#endif + } +}}; + +def format HwLoad(ea_code, memacc_code, class_ext, *flags) {{ + (header_output, decoder_output, decode_block, exec_output) = \ + LoadStoreBase(name, Name + class_ext, ea_code, memacc_code, + mem_flags = [], inst_flags = flags, + base_class = 'HwLoadStore', exec_template_base = 'Load') +}}; + + +def format HwStore(ea_code, memacc_code, class_ext, *flags) {{ + (header_output, decoder_output, decode_block, exec_output) = \ + LoadStoreBase(name, Name + class_ext, ea_code, memacc_code, + mem_flags = [], inst_flags = flags, + base_class = 'HwLoadStore', exec_template_base = 'Store') +}}; + + +def format HwStoreCond(ea_code, memacc_code, postacc_code, class_ext, + *flags) {{ + (header_output, decoder_output, decode_block, exec_output) = \ + LoadStoreBase(name, Name + class_ext, ea_code, memacc_code, + postacc_code, mem_flags = [], inst_flags = flags, + base_class = 'HwLoadStore') +}}; + + +output header {{ + /** + * Base class for hw_mfpr and hw_mtpr. + */ + class HwMoveIPR : public AlphaStaticInst + { + protected: + /// Index of internal processor register. + int ipr_index; + + /// Constructor + HwMoveIPR(const char *mnem, ExtMachInst _machInst, OpClass __opClass) + : AlphaStaticInst(mnem, _machInst, __opClass), + ipr_index(HW_IPR_IDX) + { + } + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; +}}; + +output decoder {{ + std::string + HwMoveIPR::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + if (_numSrcRegs > 0) { + // must be mtpr + return csprintf("%-10s r%d,IPR(%#x)", + mnemonic, RA, ipr_index); + } + else { + // must be mfpr + return csprintf("%-10s IPR(%#x),r%d", + mnemonic, ipr_index, RA); + } + } +}}; + +def format HwMoveIPR(code, *flags) {{ + all_flags = ['IprAccessOp'] + all_flags += flags + iop = InstObjParams(name, Name, 'HwMoveIPR', CodeBlock(code), + all_flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; + + diff --git a/src/arch/alpha/isa/unimp.isa b/src/arch/alpha/isa/unimp.isa new file mode 100644 index 000000000..c96498764 --- /dev/null +++ b/src/arch/alpha/isa/unimp.isa @@ -0,0 +1,170 @@ +// -*- mode:c++ -*- + +// Copyright (c) 2003-2005 The Regents of The University of Michigan +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +//////////////////////////////////////////////////////////////////// +// +// Unimplemented instructions +// + +output header {{ + /** + * Static instruction class for unimplemented instructions that + * cause simulator termination. Note that these are recognized + * (legal) instructions that the simulator does not support; the + * 'Unknown' class is used for unrecognized/illegal instructions. + * This is a leaf class. + */ + class FailUnimplemented : public AlphaStaticInst + { + public: + /// Constructor + FailUnimplemented(const char *_mnemonic, ExtMachInst _machInst) + : AlphaStaticInst(_mnemonic, _machInst, No_OpClass) + { + // don't call execute() (which panics) if we're on a + // speculative path + flags[IsNonSpeculative] = true; + } + + %(BasicExecDeclare)s + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; + + /** + * Base class for unimplemented instructions that cause a warning + * to be printed (but do not terminate simulation). This + * implementation is a little screwy in that it will print a + * warning for each instance of a particular unimplemented machine + * instruction, not just for each unimplemented opcode. Should + * probably make the 'warned' flag a static member of the derived + * class. + */ + class WarnUnimplemented : public AlphaStaticInst + { + private: + /// Have we warned on this instruction yet? + mutable bool warned; + + public: + /// Constructor + WarnUnimplemented(const char *_mnemonic, ExtMachInst _machInst) + : AlphaStaticInst(_mnemonic, _machInst, No_OpClass), warned(false) + { + // don't call execute() (which panics) if we're on a + // speculative path + flags[IsNonSpeculative] = true; + } + + %(BasicExecDeclare)s + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; +}}; + +output decoder {{ + std::string + FailUnimplemented::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { + return csprintf("%-10s (unimplemented)", mnemonic); + } + + std::string + WarnUnimplemented::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { +#ifdef SS_COMPATIBLE_DISASSEMBLY + return csprintf("%-10s", mnemonic); +#else + return csprintf("%-10s (unimplemented)", mnemonic); +#endif + } +}}; + +output exec {{ + Fault + FailUnimplemented::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + panic("attempt to execute unimplemented instruction '%s' " + "(inst 0x%08x, opcode 0x%x)", mnemonic, machInst, OPCODE); + return new UnimplementedOpcodeFault; + } + + Fault + WarnUnimplemented::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + if (!warned) { + warn("instruction '%s' unimplemented\n", mnemonic); + warned = true; + } + + return NoFault; + } +}}; + + +def format FailUnimpl() {{ + iop = InstObjParams(name, 'FailUnimplemented') + decode_block = BasicDecodeWithMnemonic.subst(iop) +}}; + +def format WarnUnimpl() {{ + iop = InstObjParams(name, 'WarnUnimplemented') + decode_block = BasicDecodeWithMnemonic.subst(iop) +}}; + +output header {{ + /** + * Static instruction class for unknown (illegal) instructions. + * These cause simulator termination if they are executed in a + * non-speculative mode. This is a leaf class. + */ + class Unknown : public AlphaStaticInst + { + public: + /// Constructor + Unknown(ExtMachInst _machInst) + : AlphaStaticInst("unknown", _machInst, No_OpClass) + { + // don't call execute() (which panics) if we're on a + // speculative path + flags[IsNonSpeculative] = true; + } + + %(BasicExecDeclare)s + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; +}}; + diff --git a/src/arch/alpha/isa/unknown.isa b/src/arch/alpha/isa/unknown.isa new file mode 100644 index 000000000..fb0cee54e --- /dev/null +++ b/src/arch/alpha/isa/unknown.isa @@ -0,0 +1,57 @@ +// -*- mode:c++ -*- + +// Copyright (c) 2003-2005 The Regents of The University of Michigan +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +//////////////////////////////////////////////////////////////////// +// +// Unknown instructions +// + +output decoder {{ + std::string + Unknown::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + return csprintf("%-10s (inst 0x%x, opcode 0x%x)", + "unknown", machInst, OPCODE); + } +}}; + +output exec {{ + Fault + Unknown::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + panic("attempt to execute unknown instruction " + "(inst 0x%08x, opcode 0x%x)", machInst, OPCODE); + return new UnimplementedOpcodeFault; + } +}}; + +def format Unknown() {{ + decode_block = 'return new Unknown(machInst);\n' +}}; + diff --git a/src/arch/alpha/isa/util.isa b/src/arch/alpha/isa/util.isa new file mode 100644 index 000000000..b4ee9cc8d --- /dev/null +++ b/src/arch/alpha/isa/util.isa @@ -0,0 +1,117 @@ +// -*- mode:c++ -*- + +// Copyright (c) 2003-2005 The Regents of The University of Michigan +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +//////////////////////////////////////////////////////////////////// +// +// Utility functions for execute methods +// + +output exec {{ + + /// Return opa + opb, summing carry into third arg. + inline uint64_t + addc(uint64_t opa, uint64_t opb, int &carry) + { + uint64_t res = opa + opb; + if (res < opa || res < opb) + ++carry; + return res; + } + + /// Multiply two 64-bit values (opa * opb), returning the 128-bit + /// product in res_hi and res_lo. + inline void + mul128(uint64_t opa, uint64_t opb, uint64_t &res_hi, uint64_t &res_lo) + { + // do a 64x64 --> 128 multiply using four 32x32 --> 64 multiplies + uint64_t opa_hi = opa<63:32>; + uint64_t opa_lo = opa<31:0>; + uint64_t opb_hi = opb<63:32>; + uint64_t opb_lo = opb<31:0>; + + res_lo = opa_lo * opb_lo; + + // The middle partial products logically belong in bit + // positions 95 to 32. Thus the lower 32 bits of each product + // sum into the upper 32 bits of the low result, while the + // upper 32 sum into the low 32 bits of the upper result. + uint64_t partial1 = opa_hi * opb_lo; + uint64_t partial2 = opa_lo * opb_hi; + + uint64_t partial1_lo = partial1<31:0> << 32; + uint64_t partial1_hi = partial1<63:32>; + uint64_t partial2_lo = partial2<31:0> << 32; + uint64_t partial2_hi = partial2<63:32>; + + // Add partial1_lo and partial2_lo to res_lo, keeping track + // of any carries out + int carry_out = 0; + res_lo = addc(partial1_lo, res_lo, carry_out); + res_lo = addc(partial2_lo, res_lo, carry_out); + + // Now calculate the high 64 bits... + res_hi = (opa_hi * opb_hi) + partial1_hi + partial2_hi + carry_out; + } + + /// Map 8-bit S-floating exponent to 11-bit T-floating exponent. + /// See Table 2-2 of Alpha AHB. + inline int + map_s(int old_exp) + { + int hibit = old_exp<7:>; + int lobits = old_exp<6:0>; + + if (hibit == 1) { + return (lobits == 0x7f) ? 0x7ff : (0x400 | lobits); + } + else { + return (lobits == 0) ? 0 : (0x380 | lobits); + } + } + + /// Convert a 32-bit S-floating value to the equivalent 64-bit + /// representation to be stored in an FP reg. + inline uint64_t + s_to_t(uint32_t s_val) + { + uint64_t tmp = s_val; + return (tmp<31:> << 63 // sign bit + | (uint64_t)map_s(tmp<30:23>) << 52 // exponent + | tmp<22:0> << 29); // fraction + } + + /// Convert a 64-bit T-floating value to the equivalent 32-bit + /// S-floating representation to be stored in memory. + inline int32_t + t_to_s(uint64_t t_val) + { + return (t_val<63:62> << 30 // sign bit & hi exp bit + | t_val<58:29>); // rest of exp & fraction + } +}}; + diff --git a/src/arch/alpha/isa_traits.hh b/src/arch/alpha/isa_traits.hh new file mode 100644 index 000000000..65c72115b --- /dev/null +++ b/src/arch/alpha/isa_traits.hh @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ARCH_ALPHA_ISA_TRAITS_HH__ +#define __ARCH_ALPHA_ISA_TRAITS_HH__ + +namespace LittleEndianGuest {} + +#include "arch/alpha/types.hh" +#include "arch/alpha/constants.hh" +#include "arch/alpha/regfile.hh" +#include "config/full_system.hh" +#include "sim/host.hh" + +class StaticInstPtr; + +#if !FULL_SYSTEM +class SyscallReturn { + public: + template <class T> + SyscallReturn(T v, bool s) + { + retval = (uint64_t)v; + success = s; + } + + template <class T> + SyscallReturn(T v) + { + success = (v >= 0); + retval = (uint64_t)v; + } + + ~SyscallReturn() {} + + SyscallReturn& operator=(const SyscallReturn& s) { + retval = s.retval; + success = s.success; + return *this; + } + + bool successful() { return success; } + uint64_t value() { return retval; } + + + private: + uint64_t retval; + bool success; +}; + +#endif + +#if FULL_SYSTEM +#include "arch/alpha/isa_fullsys_traits.hh" +#endif + + +namespace AlphaISA +{ + +using namespace LittleEndianGuest; + +// redirected register map, really only used for the full system case. +extern const int reg_redir[NumIntRegs]; + + StaticInstPtr decodeInst(ExtMachInst); + +#if !FULL_SYSTEM + static inline void setSyscallReturn(SyscallReturn return_value, RegFile *regs) + { + // check for error condition. Alpha syscall convention is to + // indicate success/failure in reg a3 (r19) and put the + // return value itself in the standard return value reg (v0). + if (return_value.successful()) { + // no error + regs->setIntReg(SyscallSuccessReg, 0); + regs->setIntReg(ReturnValueReg, return_value.value()); + } else { + // got an error, return details + regs->setIntReg(SyscallSuccessReg, (IntReg)-1); + regs->setIntReg(ReturnValueReg, -return_value.value()); + } + } +#endif +}; + +#endif // __ARCH_ALPHA_ISA_TRAITS_HH__ diff --git a/arch/alpha/linux/aligned.hh b/src/arch/alpha/linux/aligned.hh index cabecb283..cabecb283 100644 --- a/arch/alpha/linux/aligned.hh +++ b/src/arch/alpha/linux/aligned.hh diff --git a/arch/alpha/linux/hwrpb.hh b/src/arch/alpha/linux/hwrpb.hh index 869ce026b..869ce026b 100644 --- a/arch/alpha/linux/hwrpb.hh +++ b/src/arch/alpha/linux/hwrpb.hh diff --git a/src/arch/alpha/linux/linux.cc b/src/arch/alpha/linux/linux.cc new file mode 100644 index 000000000..f123ae1fe --- /dev/null +++ b/src/arch/alpha/linux/linux.cc @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "arch/alpha/linux/linux.hh" + +// open(2) flags translation table +OpenFlagTransTable AlphaLinux::openFlagTable[] = { +#ifdef _MSC_VER + { AlphaLinux::TGT_O_RDONLY, _O_RDONLY }, + { AlphaLinux::TGT_O_WRONLY, _O_WRONLY }, + { AlphaLinux::TGT_O_RDWR, _O_RDWR }, + { AlphaLinux::TGT_O_APPEND, _O_APPEND }, + { AlphaLinux::TGT_O_CREAT, _O_CREAT }, + { AlphaLinux::TGT_O_TRUNC, _O_TRUNC }, + { AlphaLinux::TGT_O_EXCL, _O_EXCL }, +#ifdef _O_NONBLOCK + { AlphaLinux::TGT_O_NONBLOCK, _O_NONBLOCK }, +#endif +#ifdef _O_NOCTTY + { AlphaLinux::TGT_O_NOCTTY, _O_NOCTTY }, +#endif +#ifdef _O_SYNC + { AlphaLinux::TGT_O_SYNC, _O_SYNC }, +#endif +#else /* !_MSC_VER */ + { AlphaLinux::TGT_O_RDONLY, O_RDONLY }, + { AlphaLinux::TGT_O_WRONLY, O_WRONLY }, + { AlphaLinux::TGT_O_RDWR, O_RDWR }, + { AlphaLinux::TGT_O_APPEND, O_APPEND }, + { AlphaLinux::TGT_O_CREAT, O_CREAT }, + { AlphaLinux::TGT_O_TRUNC, O_TRUNC }, + { AlphaLinux::TGT_O_EXCL, O_EXCL }, + { AlphaLinux::TGT_O_NONBLOCK, O_NONBLOCK }, + { AlphaLinux::TGT_O_NOCTTY, O_NOCTTY }, +#ifdef O_SYNC + { AlphaLinux::TGT_O_SYNC, O_SYNC }, +#endif +#endif /* _MSC_VER */ +}; + +const int AlphaLinux::NUM_OPEN_FLAGS = + (sizeof(AlphaLinux::openFlagTable)/sizeof(AlphaLinux::openFlagTable[0])); + + + diff --git a/src/arch/alpha/linux/linux.hh b/src/arch/alpha/linux/linux.hh new file mode 100644 index 000000000..f04e2bfa8 --- /dev/null +++ b/src/arch/alpha/linux/linux.hh @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ALPHA_ALPHA_LINUX_HH +#define __ALPHA_ALPHA_LINUX_HH + +#include "kern/linux/linux.hh" + +/* AlphaLinux class contains static constants/definitions/misc. + * structures which are specific to the Linux OS AND the Alpha + * architecture + */ +class AlphaLinux : public Linux +{ + public: + + /// This table maps the target open() flags to the corresponding + /// host open() flags. + static OpenFlagTransTable openFlagTable[]; + + /// Number of entries in openFlagTable[]. + static const int NUM_OPEN_FLAGS; + + //@{ + /// open(2) flag values. + static const int TGT_O_RDONLY = 00000000; //!< O_RDONLY + static const int TGT_O_WRONLY = 00000001; //!< O_WRONLY + static const int TGT_O_RDWR = 00000002; //!< O_RDWR + static const int TGT_O_NONBLOCK = 00000004; //!< O_NONBLOCK + static const int TGT_O_APPEND = 00000010; //!< O_APPEND + static const int TGT_O_CREAT = 00001000; //!< O_CREAT + static const int TGT_O_TRUNC = 00002000; //!< O_TRUNC + static const int TGT_O_EXCL = 00004000; //!< O_EXCL + static const int TGT_O_NOCTTY = 00010000; //!< O_NOCTTY + static const int TGT_O_SYNC = 00040000; //!< O_SYNC + static const int TGT_O_DRD = 00100000; //!< O_DRD + static const int TGT_O_DIRECTIO = 00200000; //!< O_DIRECTIO + static const int TGT_O_CACHE = 00400000; //!< O_CACHE + static const int TGT_O_DSYNC = 02000000; //!< O_DSYNC + static const int TGT_O_RSYNC = 04000000; //!< O_RSYNC + //@} + + /// For mmap(). + static const unsigned TGT_MAP_ANONYMOUS = 0x10; + + //@{ + /// For getsysinfo(). + static const unsigned GSI_PLATFORM_NAME = 103; //!< platform name as string + static const unsigned GSI_CPU_INFO = 59; //!< CPU information + static const unsigned GSI_PROC_TYPE = 60; //!< get proc_type + static const unsigned GSI_MAX_CPU = 30; //!< max # cpu's on this machine + static const unsigned GSI_CPUS_IN_BOX = 55; //!< number of CPUs in system + static const unsigned GSI_PHYSMEM = 19; //!< Physical memory in KB + static const unsigned GSI_CLK_TCK = 42; //!< clock freq in Hz + static const unsigned GSI_IEEE_FP_CONTROL = 45; + //@} + + //@{ + /// For getrusage(). + static const int TGT_RUSAGE_SELF = 0; + static const int TGT_RUSAGE_CHILDREN = -1; + static const int TGT_RUSAGE_BOTH = -2; + //@} + + //@{ + /// For setsysinfo(). + static const unsigned SSI_IEEE_FP_CONTROL = 14; //!< ieee_set_fp_control() + //@} + + //@{ + /// ioctl() command codes. + static const unsigned TIOCGETP = 0x40067408; + static const unsigned TIOCSETP = 0x80067409; + static const unsigned TIOCSETN = 0x8006740a; + static const unsigned TIOCSETC = 0x80067411; + static const unsigned TIOCGETC = 0x40067412; + static const unsigned FIONREAD = 0x4004667f; + static const unsigned TIOCISATTY = 0x2000745e; + static const unsigned TIOCGETS = 0x402c7413; + static const unsigned TIOCGETA = 0x40127417; + //@} + + /// For table(). + static const int TBL_SYSINFO = 12; + + /// Resource enumeration for getrlimit(). + enum rlimit_resources { + TGT_RLIMIT_CPU = 0, + TGT_RLIMIT_FSIZE = 1, + TGT_RLIMIT_DATA = 2, + TGT_RLIMIT_STACK = 3, + TGT_RLIMIT_CORE = 4, + TGT_RLIMIT_RSS = 5, + TGT_RLIMIT_NOFILE = 6, + TGT_RLIMIT_AS = 7, + TGT_RLIMIT_VMEM = 7, + TGT_RLIMIT_NPROC = 8, + TGT_RLIMIT_MEMLOCK = 9, + TGT_RLIMIT_LOCKS = 10 + }; +}; + +#endif diff --git a/src/arch/alpha/linux/process.cc b/src/arch/alpha/linux/process.cc new file mode 100644 index 000000000..9f4f65db8 --- /dev/null +++ b/src/arch/alpha/linux/process.cc @@ -0,0 +1,591 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "arch/alpha/linux/linux.hh" +#include "arch/alpha/linux/process.hh" +#include "arch/alpha/isa_traits.hh" + +#include "base/trace.hh" +#include "cpu/exec_context.hh" +#include "kern/linux/linux.hh" + +#include "sim/process.hh" +#include "sim/syscall_emul.hh" + +using namespace std; +using namespace AlphaISA; + + + +/// Target uname() handler. +static SyscallReturn +unameFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + TypedBufferArg<Linux::utsname> name(xc->getSyscallArg(0)); + + strcpy(name->sysname, "Linux"); + strcpy(name->nodename, "m5.eecs.umich.edu"); + strcpy(name->release, "2.4.20"); + strcpy(name->version, "#1 Mon Aug 18 11:32:15 EDT 2003"); + strcpy(name->machine, "alpha"); + + name.copyOut(xc->getMemPort()); + return 0; +} + +/// Target osf_getsysyinfo() handler. Even though this call is +/// borrowed from Tru64, the subcases that get used appear to be +/// different in practice from those used by Tru64 processes. +static SyscallReturn +osf_getsysinfoFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + unsigned op = xc->getSyscallArg(0); + // unsigned nbytes = xc->getSyscallArg(2); + + switch (op) { + + case 45: { // GSI_IEEE_FP_CONTROL + TypedBufferArg<uint64_t> fpcr(xc->getSyscallArg(1)); + // I don't think this exactly matches the HW FPCR + *fpcr = 0; + fpcr.copyOut(xc->getMemPort()); + return 0; + } + + default: + cerr << "osf_getsysinfo: unknown op " << op << endl; + abort(); + break; + } + + return 1; +} + +/// Target osf_setsysinfo() handler. +static SyscallReturn +osf_setsysinfoFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + unsigned op = xc->getSyscallArg(0); + // unsigned nbytes = xc->getSyscallArg(2); + + switch (op) { + + case 14: { // SSI_IEEE_FP_CONTROL + TypedBufferArg<uint64_t> fpcr(xc->getSyscallArg(1)); + // I don't think this exactly matches the HW FPCR + fpcr.copyIn(xc->getMemPort()); + DPRINTFR(SyscallVerbose, "osf_setsysinfo(SSI_IEEE_FP_CONTROL): " + " setting FPCR to 0x%x\n", gtoh(*(uint64_t*)fpcr)); + return 0; + } + + default: + cerr << "osf_setsysinfo: unknown op " << op << endl; + abort(); + break; + } + + return 1; +} + + +SyscallDesc AlphaLinuxProcess::syscallDescs[] = { + /* 0 */ SyscallDesc("osf_syscall", unimplementedFunc), + /* 1 */ SyscallDesc("exit", exitFunc), + /* 2 */ SyscallDesc("fork", unimplementedFunc), + /* 3 */ SyscallDesc("read", readFunc), + /* 4 */ SyscallDesc("write", writeFunc), + /* 5 */ SyscallDesc("osf_old_open", unimplementedFunc), + /* 6 */ SyscallDesc("close", closeFunc), + /* 7 */ SyscallDesc("osf_wait4", unimplementedFunc), + /* 8 */ SyscallDesc("osf_old_creat", unimplementedFunc), + /* 9 */ SyscallDesc("link", unimplementedFunc), + /* 10 */ SyscallDesc("unlink", unlinkFunc), + /* 11 */ SyscallDesc("osf_execve", unimplementedFunc), + /* 12 */ SyscallDesc("chdir", unimplementedFunc), + /* 13 */ SyscallDesc("fchdir", unimplementedFunc), + /* 14 */ SyscallDesc("mknod", unimplementedFunc), + /* 15 */ SyscallDesc("chmod", chmodFunc<AlphaLinux>), + /* 16 */ SyscallDesc("chown", chownFunc), + /* 17 */ SyscallDesc("brk", obreakFunc), + /* 18 */ SyscallDesc("osf_getfsstat", unimplementedFunc), + /* 19 */ SyscallDesc("lseek", lseekFunc), + /* 20 */ SyscallDesc("getxpid", getpidPseudoFunc), + /* 21 */ SyscallDesc("osf_mount", unimplementedFunc), + /* 22 */ SyscallDesc("umount", unimplementedFunc), + /* 23 */ SyscallDesc("setuid", setuidFunc), + /* 24 */ SyscallDesc("getxuid", getuidPseudoFunc), + /* 25 */ SyscallDesc("exec_with_loader", unimplementedFunc), + /* 26 */ SyscallDesc("osf_ptrace", unimplementedFunc), + /* 27 */ SyscallDesc("osf_nrecvmsg", unimplementedFunc), + /* 28 */ SyscallDesc("osf_nsendmsg", unimplementedFunc), + /* 29 */ SyscallDesc("osf_nrecvfrom", unimplementedFunc), + /* 30 */ SyscallDesc("osf_naccept", unimplementedFunc), + /* 31 */ SyscallDesc("osf_ngetpeername", unimplementedFunc), + /* 32 */ SyscallDesc("osf_ngetsockname", unimplementedFunc), + /* 33 */ SyscallDesc("access", unimplementedFunc), + /* 34 */ SyscallDesc("osf_chflags", unimplementedFunc), + /* 35 */ SyscallDesc("osf_fchflags", unimplementedFunc), + /* 36 */ SyscallDesc("sync", unimplementedFunc), + /* 37 */ SyscallDesc("kill", unimplementedFunc), + /* 38 */ SyscallDesc("osf_old_stat", unimplementedFunc), + /* 39 */ SyscallDesc("setpgid", unimplementedFunc), + /* 40 */ SyscallDesc("osf_old_lstat", unimplementedFunc), + /* 41 */ SyscallDesc("dup", unimplementedFunc), + /* 42 */ SyscallDesc("pipe", pipePseudoFunc), + /* 43 */ SyscallDesc("osf_set_program_attributes", unimplementedFunc), + /* 44 */ SyscallDesc("osf_profil", unimplementedFunc), + /* 45 */ SyscallDesc("open", openFunc<AlphaLinux>), + /* 46 */ SyscallDesc("osf_old_sigaction", unimplementedFunc), + /* 47 */ SyscallDesc("getxgid", getgidPseudoFunc), + /* 48 */ SyscallDesc("osf_sigprocmask", ignoreFunc), + /* 49 */ SyscallDesc("osf_getlogin", unimplementedFunc), + /* 50 */ SyscallDesc("osf_setlogin", unimplementedFunc), + /* 51 */ SyscallDesc("acct", unimplementedFunc), + /* 52 */ SyscallDesc("sigpending", unimplementedFunc), + /* 53 */ SyscallDesc("osf_classcntl", unimplementedFunc), + /* 54 */ SyscallDesc("ioctl", ioctlFunc<AlphaLinux>), + /* 55 */ SyscallDesc("osf_reboot", unimplementedFunc), + /* 56 */ SyscallDesc("osf_revoke", unimplementedFunc), + /* 57 */ SyscallDesc("symlink", unimplementedFunc), + /* 58 */ SyscallDesc("readlink", unimplementedFunc), + /* 59 */ SyscallDesc("execve", unimplementedFunc), + /* 60 */ SyscallDesc("umask", unimplementedFunc), + /* 61 */ SyscallDesc("chroot", unimplementedFunc), + /* 62 */ SyscallDesc("osf_old_fstat", unimplementedFunc), + /* 63 */ SyscallDesc("getpgrp", unimplementedFunc), + /* 64 */ SyscallDesc("getpagesize", getpagesizeFunc), + /* 65 */ SyscallDesc("osf_mremap", unimplementedFunc), + /* 66 */ SyscallDesc("vfork", unimplementedFunc), + /* 67 */ SyscallDesc("stat", statFunc<AlphaLinux>), + /* 68 */ SyscallDesc("lstat", lstatFunc<AlphaLinux>), + /* 69 */ SyscallDesc("osf_sbrk", unimplementedFunc), + /* 70 */ SyscallDesc("osf_sstk", unimplementedFunc), + /* 71 */ SyscallDesc("mmap", mmapFunc<AlphaLinux>), + /* 72 */ SyscallDesc("osf_old_vadvise", unimplementedFunc), + /* 73 */ SyscallDesc("munmap", munmapFunc), + /* 74 */ SyscallDesc("mprotect", ignoreFunc), + /* 75 */ SyscallDesc("madvise", unimplementedFunc), + /* 76 */ SyscallDesc("vhangup", unimplementedFunc), + /* 77 */ SyscallDesc("osf_kmodcall", unimplementedFunc), + /* 78 */ SyscallDesc("osf_mincore", unimplementedFunc), + /* 79 */ SyscallDesc("getgroups", unimplementedFunc), + /* 80 */ SyscallDesc("setgroups", unimplementedFunc), + /* 81 */ SyscallDesc("osf_old_getpgrp", unimplementedFunc), + /* 82 */ SyscallDesc("setpgrp", unimplementedFunc), + /* 83 */ SyscallDesc("osf_setitimer", unimplementedFunc), + /* 84 */ SyscallDesc("osf_old_wait", unimplementedFunc), + /* 85 */ SyscallDesc("osf_table", unimplementedFunc), + /* 86 */ SyscallDesc("osf_getitimer", unimplementedFunc), + /* 87 */ SyscallDesc("gethostname", gethostnameFunc), + /* 88 */ SyscallDesc("sethostname", unimplementedFunc), + /* 89 */ SyscallDesc("getdtablesize", unimplementedFunc), + /* 90 */ SyscallDesc("dup2", unimplementedFunc), + /* 91 */ SyscallDesc("fstat", fstatFunc<AlphaLinux>), + /* 92 */ SyscallDesc("fcntl", fcntlFunc), + /* 93 */ SyscallDesc("osf_select", unimplementedFunc), + /* 94 */ SyscallDesc("poll", unimplementedFunc), + /* 95 */ SyscallDesc("fsync", unimplementedFunc), + /* 96 */ SyscallDesc("setpriority", unimplementedFunc), + /* 97 */ SyscallDesc("socket", unimplementedFunc), + /* 98 */ SyscallDesc("connect", unimplementedFunc), + /* 99 */ SyscallDesc("accept", unimplementedFunc), + /* 100 */ SyscallDesc("getpriority", unimplementedFunc), + /* 101 */ SyscallDesc("send", unimplementedFunc), + /* 102 */ SyscallDesc("recv", unimplementedFunc), + /* 103 */ SyscallDesc("sigreturn", unimplementedFunc), + /* 104 */ SyscallDesc("bind", unimplementedFunc), + /* 105 */ SyscallDesc("setsockopt", unimplementedFunc), + /* 106 */ SyscallDesc("listen", unimplementedFunc), + /* 107 */ SyscallDesc("osf_plock", unimplementedFunc), + /* 108 */ SyscallDesc("osf_old_sigvec", unimplementedFunc), + /* 109 */ SyscallDesc("osf_old_sigblock", unimplementedFunc), + /* 110 */ SyscallDesc("osf_old_sigsetmask", unimplementedFunc), + /* 111 */ SyscallDesc("sigsuspend", unimplementedFunc), + /* 112 */ SyscallDesc("osf_sigstack", ignoreFunc), + /* 113 */ SyscallDesc("recvmsg", unimplementedFunc), + /* 114 */ SyscallDesc("sendmsg", unimplementedFunc), + /* 115 */ SyscallDesc("osf_old_vtrace", unimplementedFunc), + /* 116 */ SyscallDesc("osf_gettimeofday", unimplementedFunc), + /* 117 */ SyscallDesc("osf_getrusage", unimplementedFunc), + /* 118 */ SyscallDesc("getsockopt", unimplementedFunc), + /* 119 */ SyscallDesc("numa_syscalls", unimplementedFunc), + /* 120 */ SyscallDesc("readv", unimplementedFunc), + /* 121 */ SyscallDesc("writev", writevFunc<AlphaLinux>), + /* 122 */ SyscallDesc("osf_settimeofday", unimplementedFunc), + /* 123 */ SyscallDesc("fchown", fchownFunc), + /* 124 */ SyscallDesc("fchmod", fchmodFunc<AlphaLinux>), + /* 125 */ SyscallDesc("recvfrom", unimplementedFunc), + /* 126 */ SyscallDesc("setreuid", unimplementedFunc), + /* 127 */ SyscallDesc("setregid", unimplementedFunc), + /* 128 */ SyscallDesc("rename", renameFunc), + /* 129 */ SyscallDesc("truncate", unimplementedFunc), + /* 130 */ SyscallDesc("ftruncate", unimplementedFunc), + /* 131 */ SyscallDesc("flock", unimplementedFunc), + /* 132 */ SyscallDesc("setgid", unimplementedFunc), + /* 133 */ SyscallDesc("sendto", unimplementedFunc), + /* 134 */ SyscallDesc("shutdown", unimplementedFunc), + /* 135 */ SyscallDesc("socketpair", unimplementedFunc), + /* 136 */ SyscallDesc("mkdir", unimplementedFunc), + /* 137 */ SyscallDesc("rmdir", unimplementedFunc), + /* 138 */ SyscallDesc("osf_utimes", unimplementedFunc), + /* 139 */ SyscallDesc("osf_old_sigreturn", unimplementedFunc), + /* 140 */ SyscallDesc("osf_adjtime", unimplementedFunc), + /* 141 */ SyscallDesc("getpeername", unimplementedFunc), + /* 142 */ SyscallDesc("osf_gethostid", unimplementedFunc), + /* 143 */ SyscallDesc("osf_sethostid", unimplementedFunc), + /* 144 */ SyscallDesc("getrlimit", getrlimitFunc<AlphaLinux>), + /* 145 */ SyscallDesc("setrlimit", ignoreFunc), + /* 146 */ SyscallDesc("osf_old_killpg", unimplementedFunc), + /* 147 */ SyscallDesc("setsid", unimplementedFunc), + /* 148 */ SyscallDesc("quotactl", unimplementedFunc), + /* 149 */ SyscallDesc("osf_oldquota", unimplementedFunc), + /* 150 */ SyscallDesc("getsockname", unimplementedFunc), + /* 151 */ SyscallDesc("osf_pread", unimplementedFunc), + /* 152 */ SyscallDesc("osf_pwrite", unimplementedFunc), + /* 153 */ SyscallDesc("osf_pid_block", unimplementedFunc), + /* 154 */ SyscallDesc("osf_pid_unblock", unimplementedFunc), + /* 155 */ SyscallDesc("osf_signal_urti", unimplementedFunc), + /* 156 */ SyscallDesc("sigaction", ignoreFunc), + /* 157 */ SyscallDesc("osf_sigwaitprim", unimplementedFunc), + /* 158 */ SyscallDesc("osf_nfssvc", unimplementedFunc), + /* 159 */ SyscallDesc("osf_getdirentries", unimplementedFunc), + /* 160 */ SyscallDesc("osf_statfs", unimplementedFunc), + /* 161 */ SyscallDesc("osf_fstatfs", unimplementedFunc), + /* 162 */ SyscallDesc("unknown #162", unimplementedFunc), + /* 163 */ SyscallDesc("osf_async_daemon", unimplementedFunc), + /* 164 */ SyscallDesc("osf_getfh", unimplementedFunc), + /* 165 */ SyscallDesc("osf_getdomainname", unimplementedFunc), + /* 166 */ SyscallDesc("setdomainname", unimplementedFunc), + /* 167 */ SyscallDesc("unknown #167", unimplementedFunc), + /* 168 */ SyscallDesc("unknown #168", unimplementedFunc), + /* 169 */ SyscallDesc("osf_exportfs", unimplementedFunc), + /* 170 */ SyscallDesc("unknown #170", unimplementedFunc), + /* 171 */ SyscallDesc("unknown #171", unimplementedFunc), + /* 172 */ SyscallDesc("unknown #172", unimplementedFunc), + /* 173 */ SyscallDesc("unknown #173", unimplementedFunc), + /* 174 */ SyscallDesc("unknown #174", unimplementedFunc), + /* 175 */ SyscallDesc("unknown #175", unimplementedFunc), + /* 176 */ SyscallDesc("unknown #176", unimplementedFunc), + /* 177 */ SyscallDesc("unknown #177", unimplementedFunc), + /* 178 */ SyscallDesc("unknown #178", unimplementedFunc), + /* 179 */ SyscallDesc("unknown #179", unimplementedFunc), + /* 180 */ SyscallDesc("unknown #180", unimplementedFunc), + /* 181 */ SyscallDesc("osf_alt_plock", unimplementedFunc), + /* 182 */ SyscallDesc("unknown #182", unimplementedFunc), + /* 183 */ SyscallDesc("unknown #183", unimplementedFunc), + /* 184 */ SyscallDesc("osf_getmnt", unimplementedFunc), + /* 185 */ SyscallDesc("unknown #185", unimplementedFunc), + /* 186 */ SyscallDesc("unknown #186", unimplementedFunc), + /* 187 */ SyscallDesc("osf_alt_sigpending", unimplementedFunc), + /* 188 */ SyscallDesc("osf_alt_setsid", unimplementedFunc), + /* 189 */ SyscallDesc("unknown #189", unimplementedFunc), + /* 190 */ SyscallDesc("unknown #190", unimplementedFunc), + /* 191 */ SyscallDesc("unknown #191", unimplementedFunc), + /* 192 */ SyscallDesc("unknown #192", unimplementedFunc), + /* 193 */ SyscallDesc("unknown #193", unimplementedFunc), + /* 194 */ SyscallDesc("unknown #194", unimplementedFunc), + /* 195 */ SyscallDesc("unknown #195", unimplementedFunc), + /* 196 */ SyscallDesc("unknown #196", unimplementedFunc), + /* 197 */ SyscallDesc("unknown #197", unimplementedFunc), + /* 198 */ SyscallDesc("unknown #198", unimplementedFunc), + /* 199 */ SyscallDesc("osf_swapon", unimplementedFunc), + /* 200 */ SyscallDesc("msgctl", unimplementedFunc), + /* 201 */ SyscallDesc("msgget", unimplementedFunc), + /* 202 */ SyscallDesc("msgrcv", unimplementedFunc), + /* 203 */ SyscallDesc("msgsnd", unimplementedFunc), + /* 204 */ SyscallDesc("semctl", unimplementedFunc), + /* 205 */ SyscallDesc("semget", unimplementedFunc), + /* 206 */ SyscallDesc("semop", unimplementedFunc), + /* 207 */ SyscallDesc("osf_utsname", unimplementedFunc), + /* 208 */ SyscallDesc("lchown", unimplementedFunc), + /* 209 */ SyscallDesc("osf_shmat", unimplementedFunc), + /* 210 */ SyscallDesc("shmctl", unimplementedFunc), + /* 211 */ SyscallDesc("shmdt", unimplementedFunc), + /* 212 */ SyscallDesc("shmget", unimplementedFunc), + /* 213 */ SyscallDesc("osf_mvalid", unimplementedFunc), + /* 214 */ SyscallDesc("osf_getaddressconf", unimplementedFunc), + /* 215 */ SyscallDesc("osf_msleep", unimplementedFunc), + /* 216 */ SyscallDesc("osf_mwakeup", unimplementedFunc), + /* 217 */ SyscallDesc("msync", unimplementedFunc), + /* 218 */ SyscallDesc("osf_signal", unimplementedFunc), + /* 219 */ SyscallDesc("osf_utc_gettime", unimplementedFunc), + /* 220 */ SyscallDesc("osf_utc_adjtime", unimplementedFunc), + /* 221 */ SyscallDesc("unknown #221", unimplementedFunc), + /* 222 */ SyscallDesc("osf_security", unimplementedFunc), + /* 223 */ SyscallDesc("osf_kloadcall", unimplementedFunc), + /* 224 */ SyscallDesc("unknown #224", unimplementedFunc), + /* 225 */ SyscallDesc("unknown #225", unimplementedFunc), + /* 226 */ SyscallDesc("unknown #226", unimplementedFunc), + /* 227 */ SyscallDesc("unknown #227", unimplementedFunc), + /* 228 */ SyscallDesc("unknown #228", unimplementedFunc), + /* 229 */ SyscallDesc("unknown #229", unimplementedFunc), + /* 230 */ SyscallDesc("unknown #230", unimplementedFunc), + /* 231 */ SyscallDesc("unknown #231", unimplementedFunc), + /* 232 */ SyscallDesc("unknown #232", unimplementedFunc), + /* 233 */ SyscallDesc("getpgid", unimplementedFunc), + /* 234 */ SyscallDesc("getsid", unimplementedFunc), + /* 235 */ SyscallDesc("sigaltstack", ignoreFunc), + /* 236 */ SyscallDesc("osf_waitid", unimplementedFunc), + /* 237 */ SyscallDesc("osf_priocntlset", unimplementedFunc), + /* 238 */ SyscallDesc("osf_sigsendset", unimplementedFunc), + /* 239 */ SyscallDesc("osf_set_speculative", unimplementedFunc), + /* 240 */ SyscallDesc("osf_msfs_syscall", unimplementedFunc), + /* 241 */ SyscallDesc("osf_sysinfo", unimplementedFunc), + /* 242 */ SyscallDesc("osf_uadmin", unimplementedFunc), + /* 243 */ SyscallDesc("osf_fuser", unimplementedFunc), + /* 244 */ SyscallDesc("osf_proplist_syscall", unimplementedFunc), + /* 245 */ SyscallDesc("osf_ntp_adjtime", unimplementedFunc), + /* 246 */ SyscallDesc("osf_ntp_gettime", unimplementedFunc), + /* 247 */ SyscallDesc("osf_pathconf", unimplementedFunc), + /* 248 */ SyscallDesc("osf_fpathconf", unimplementedFunc), + /* 249 */ SyscallDesc("unknown #249", unimplementedFunc), + /* 250 */ SyscallDesc("osf_uswitch", unimplementedFunc), + /* 251 */ SyscallDesc("osf_usleep_thread", unimplementedFunc), + /* 252 */ SyscallDesc("osf_audcntl", unimplementedFunc), + /* 253 */ SyscallDesc("osf_audgen", unimplementedFunc), + /* 254 */ SyscallDesc("sysfs", unimplementedFunc), + /* 255 */ SyscallDesc("osf_subsys_info", unimplementedFunc), + /* 256 */ SyscallDesc("osf_getsysinfo", osf_getsysinfoFunc), + /* 257 */ SyscallDesc("osf_setsysinfo", osf_setsysinfoFunc), + /* 258 */ SyscallDesc("osf_afs_syscall", unimplementedFunc), + /* 259 */ SyscallDesc("osf_swapctl", unimplementedFunc), + /* 260 */ SyscallDesc("osf_memcntl", unimplementedFunc), + /* 261 */ SyscallDesc("osf_fdatasync", unimplementedFunc), + /* 262 */ SyscallDesc("unknown #262", unimplementedFunc), + /* 263 */ SyscallDesc("unknown #263", unimplementedFunc), + /* 264 */ SyscallDesc("unknown #264", unimplementedFunc), + /* 265 */ SyscallDesc("unknown #265", unimplementedFunc), + /* 266 */ SyscallDesc("unknown #266", unimplementedFunc), + /* 267 */ SyscallDesc("unknown #267", unimplementedFunc), + /* 268 */ SyscallDesc("unknown #268", unimplementedFunc), + /* 269 */ SyscallDesc("unknown #269", unimplementedFunc), + /* 270 */ SyscallDesc("unknown #270", unimplementedFunc), + /* 271 */ SyscallDesc("unknown #271", unimplementedFunc), + /* 272 */ SyscallDesc("unknown #272", unimplementedFunc), + /* 273 */ SyscallDesc("unknown #273", unimplementedFunc), + /* 274 */ SyscallDesc("unknown #274", unimplementedFunc), + /* 275 */ SyscallDesc("unknown #275", unimplementedFunc), + /* 276 */ SyscallDesc("unknown #276", unimplementedFunc), + /* 277 */ SyscallDesc("unknown #277", unimplementedFunc), + /* 278 */ SyscallDesc("unknown #278", unimplementedFunc), + /* 279 */ SyscallDesc("unknown #279", unimplementedFunc), + /* 280 */ SyscallDesc("unknown #280", unimplementedFunc), + /* 281 */ SyscallDesc("unknown #281", unimplementedFunc), + /* 282 */ SyscallDesc("unknown #282", unimplementedFunc), + /* 283 */ SyscallDesc("unknown #283", unimplementedFunc), + /* 284 */ SyscallDesc("unknown #284", unimplementedFunc), + /* 285 */ SyscallDesc("unknown #285", unimplementedFunc), + /* 286 */ SyscallDesc("unknown #286", unimplementedFunc), + /* 287 */ SyscallDesc("unknown #287", unimplementedFunc), + /* 288 */ SyscallDesc("unknown #288", unimplementedFunc), + /* 289 */ SyscallDesc("unknown #289", unimplementedFunc), + /* 290 */ SyscallDesc("unknown #290", unimplementedFunc), + /* 291 */ SyscallDesc("unknown #291", unimplementedFunc), + /* 292 */ SyscallDesc("unknown #292", unimplementedFunc), + /* 293 */ SyscallDesc("unknown #293", unimplementedFunc), + /* 294 */ SyscallDesc("unknown #294", unimplementedFunc), + /* 295 */ SyscallDesc("unknown #295", unimplementedFunc), + /* 296 */ SyscallDesc("unknown #296", unimplementedFunc), + /* 297 */ SyscallDesc("unknown #297", unimplementedFunc), + /* 298 */ SyscallDesc("unknown #298", unimplementedFunc), + /* 299 */ SyscallDesc("unknown #299", unimplementedFunc), +/* + * Linux-specific system calls begin at 300 + */ + /* 300 */ SyscallDesc("bdflush", unimplementedFunc), + /* 301 */ SyscallDesc("sethae", unimplementedFunc), + /* 302 */ SyscallDesc("mount", unimplementedFunc), + /* 303 */ SyscallDesc("old_adjtimex", unimplementedFunc), + /* 304 */ SyscallDesc("swapoff", unimplementedFunc), + /* 305 */ SyscallDesc("getdents", unimplementedFunc), + /* 306 */ SyscallDesc("create_module", unimplementedFunc), + /* 307 */ SyscallDesc("init_module", unimplementedFunc), + /* 308 */ SyscallDesc("delete_module", unimplementedFunc), + /* 309 */ SyscallDesc("get_kernel_syms", unimplementedFunc), + /* 310 */ SyscallDesc("syslog", unimplementedFunc), + /* 311 */ SyscallDesc("reboot", unimplementedFunc), + /* 312 */ SyscallDesc("clone", unimplementedFunc), + /* 313 */ SyscallDesc("uselib", unimplementedFunc), + /* 314 */ SyscallDesc("mlock", unimplementedFunc), + /* 315 */ SyscallDesc("munlock", unimplementedFunc), + /* 316 */ SyscallDesc("mlockall", unimplementedFunc), + /* 317 */ SyscallDesc("munlockall", unimplementedFunc), + /* 318 */ SyscallDesc("sysinfo", unimplementedFunc), + /* 319 */ SyscallDesc("_sysctl", unimplementedFunc), + /* 320 */ SyscallDesc("was sys_idle", unimplementedFunc), + /* 321 */ SyscallDesc("oldumount", unimplementedFunc), + /* 322 */ SyscallDesc("swapon", unimplementedFunc), + /* 323 */ SyscallDesc("times", ignoreFunc), + /* 324 */ SyscallDesc("personality", unimplementedFunc), + /* 325 */ SyscallDesc("setfsuid", unimplementedFunc), + /* 326 */ SyscallDesc("setfsgid", unimplementedFunc), + /* 327 */ SyscallDesc("ustat", unimplementedFunc), + /* 328 */ SyscallDesc("statfs", unimplementedFunc), + /* 329 */ SyscallDesc("fstatfs", unimplementedFunc), + /* 330 */ SyscallDesc("sched_setparam", unimplementedFunc), + /* 331 */ SyscallDesc("sched_getparam", unimplementedFunc), + /* 332 */ SyscallDesc("sched_setscheduler", unimplementedFunc), + /* 333 */ SyscallDesc("sched_getscheduler", unimplementedFunc), + /* 334 */ SyscallDesc("sched_yield", unimplementedFunc), + /* 335 */ SyscallDesc("sched_get_priority_max", unimplementedFunc), + /* 336 */ SyscallDesc("sched_get_priority_min", unimplementedFunc), + /* 337 */ SyscallDesc("sched_rr_get_interval", unimplementedFunc), + /* 338 */ SyscallDesc("afs_syscall", unimplementedFunc), + /* 339 */ SyscallDesc("uname", unameFunc), + /* 340 */ SyscallDesc("nanosleep", unimplementedFunc), + /* 341 */ SyscallDesc("mremap", unimplementedFunc), + /* 342 */ SyscallDesc("nfsservctl", unimplementedFunc), + /* 343 */ SyscallDesc("setresuid", unimplementedFunc), + /* 344 */ SyscallDesc("getresuid", unimplementedFunc), + /* 345 */ SyscallDesc("pciconfig_read", unimplementedFunc), + /* 346 */ SyscallDesc("pciconfig_write", unimplementedFunc), + /* 347 */ SyscallDesc("query_module", unimplementedFunc), + /* 348 */ SyscallDesc("prctl", unimplementedFunc), + /* 349 */ SyscallDesc("pread", unimplementedFunc), + /* 350 */ SyscallDesc("pwrite", unimplementedFunc), + /* 351 */ SyscallDesc("rt_sigreturn", unimplementedFunc), + /* 352 */ SyscallDesc("rt_sigaction", ignoreFunc), + /* 353 */ SyscallDesc("rt_sigprocmask", unimplementedFunc), + /* 354 */ SyscallDesc("rt_sigpending", unimplementedFunc), + /* 355 */ SyscallDesc("rt_sigtimedwait", unimplementedFunc), + /* 356 */ SyscallDesc("rt_sigqueueinfo", unimplementedFunc), + /* 357 */ SyscallDesc("rt_sigsuspend", unimplementedFunc), + /* 358 */ SyscallDesc("select", unimplementedFunc), + /* 359 */ SyscallDesc("gettimeofday", gettimeofdayFunc<AlphaLinux>), + /* 360 */ SyscallDesc("settimeofday", unimplementedFunc), + /* 361 */ SyscallDesc("getitimer", unimplementedFunc), + /* 362 */ SyscallDesc("setitimer", unimplementedFunc), + /* 363 */ SyscallDesc("utimes", utimesFunc<AlphaLinux>), + /* 364 */ SyscallDesc("getrusage", getrusageFunc<AlphaLinux>), + /* 365 */ SyscallDesc("wait4", unimplementedFunc), + /* 366 */ SyscallDesc("adjtimex", unimplementedFunc), + /* 367 */ SyscallDesc("getcwd", unimplementedFunc), + /* 368 */ SyscallDesc("capget", unimplementedFunc), + /* 369 */ SyscallDesc("capset", unimplementedFunc), + /* 370 */ SyscallDesc("sendfile", unimplementedFunc), + /* 371 */ SyscallDesc("setresgid", unimplementedFunc), + /* 372 */ SyscallDesc("getresgid", unimplementedFunc), + /* 373 */ SyscallDesc("dipc", unimplementedFunc), + /* 374 */ SyscallDesc("pivot_root", unimplementedFunc), + /* 375 */ SyscallDesc("mincore", unimplementedFunc), + /* 376 */ SyscallDesc("pciconfig_iobase", unimplementedFunc), + /* 377 */ SyscallDesc("getdents64", unimplementedFunc), + /* 378 */ SyscallDesc("gettid", unimplementedFunc), + /* 379 */ SyscallDesc("readahead", unimplementedFunc), + /* 380 */ SyscallDesc("security", unimplementedFunc), + /* 381 */ SyscallDesc("tkill", unimplementedFunc), + /* 382 */ SyscallDesc("setxattr", unimplementedFunc), + /* 383 */ SyscallDesc("lsetxattr", unimplementedFunc), + /* 384 */ SyscallDesc("fsetxattr", unimplementedFunc), + /* 385 */ SyscallDesc("getxattr", unimplementedFunc), + /* 386 */ SyscallDesc("lgetxattr", unimplementedFunc), + /* 387 */ SyscallDesc("fgetxattr", unimplementedFunc), + /* 388 */ SyscallDesc("listxattr", unimplementedFunc), + /* 389 */ SyscallDesc("llistxattr", unimplementedFunc), + /* 390 */ SyscallDesc("flistxattr", unimplementedFunc), + /* 391 */ SyscallDesc("removexattr", unimplementedFunc), + /* 392 */ SyscallDesc("lremovexattr", unimplementedFunc), + /* 393 */ SyscallDesc("fremovexattr", unimplementedFunc), + /* 394 */ SyscallDesc("futex", unimplementedFunc), + /* 395 */ SyscallDesc("sched_setaffinity", unimplementedFunc), + /* 396 */ SyscallDesc("sched_getaffinity", unimplementedFunc), + /* 397 */ SyscallDesc("tuxcall", unimplementedFunc), + /* 398 */ SyscallDesc("io_setup", unimplementedFunc), + /* 399 */ SyscallDesc("io_destroy", unimplementedFunc), + /* 400 */ SyscallDesc("io_getevents", unimplementedFunc), + /* 401 */ SyscallDesc("io_submit", unimplementedFunc), + /* 402 */ SyscallDesc("io_cancel", unimplementedFunc), + /* 403 */ SyscallDesc("unknown #403", unimplementedFunc), + /* 404 */ SyscallDesc("unknown #404", unimplementedFunc), + /* 405 */ SyscallDesc("exit_group", exitFunc), // exit all threads... + /* 406 */ SyscallDesc("lookup_dcookie", unimplementedFunc), + /* 407 */ SyscallDesc("sys_epoll_create", unimplementedFunc), + /* 408 */ SyscallDesc("sys_epoll_ctl", unimplementedFunc), + /* 409 */ SyscallDesc("sys_epoll_wait", unimplementedFunc), + /* 410 */ SyscallDesc("remap_file_pages", unimplementedFunc), + /* 411 */ SyscallDesc("set_tid_address", unimplementedFunc), + /* 412 */ SyscallDesc("restart_syscall", unimplementedFunc), + /* 413 */ SyscallDesc("fadvise64", unimplementedFunc), + /* 414 */ SyscallDesc("timer_create", unimplementedFunc), + /* 415 */ SyscallDesc("timer_settime", unimplementedFunc), + /* 416 */ SyscallDesc("timer_gettime", unimplementedFunc), + /* 417 */ SyscallDesc("timer_getoverrun", unimplementedFunc), + /* 418 */ SyscallDesc("timer_delete", unimplementedFunc), + /* 419 */ SyscallDesc("clock_settime", unimplementedFunc), + /* 420 */ SyscallDesc("clock_gettime", unimplementedFunc), + /* 421 */ SyscallDesc("clock_getres", unimplementedFunc), + /* 422 */ SyscallDesc("clock_nanosleep", unimplementedFunc), + /* 423 */ SyscallDesc("semtimedop", unimplementedFunc), + /* 424 */ SyscallDesc("tgkill", unimplementedFunc), + /* 425 */ SyscallDesc("stat64", unimplementedFunc), + /* 426 */ SyscallDesc("lstat64", lstat64Func<AlphaLinux>), + /* 427 */ SyscallDesc("fstat64", fstat64Func<AlphaLinux>), + /* 428 */ SyscallDesc("vserver", unimplementedFunc), + /* 429 */ SyscallDesc("mbind", unimplementedFunc), + /* 430 */ SyscallDesc("get_mempolicy", unimplementedFunc), + /* 431 */ SyscallDesc("set_mempolicy", unimplementedFunc), + /* 432 */ SyscallDesc("mq_open", unimplementedFunc), + /* 433 */ SyscallDesc("mq_unlink", unimplementedFunc), + /* 434 */ SyscallDesc("mq_timedsend", unimplementedFunc), + /* 435 */ SyscallDesc("mq_timedreceive", unimplementedFunc), + /* 436 */ SyscallDesc("mq_notify", unimplementedFunc), + /* 437 */ SyscallDesc("mq_getsetattr", unimplementedFunc), + /* 438 */ SyscallDesc("waitid", unimplementedFunc), + /* 439 */ SyscallDesc("add_key", unimplementedFunc), + /* 440 */ SyscallDesc("request_key", unimplementedFunc), + /* 441 */ SyscallDesc("keyctl", unimplementedFunc) +}; + +AlphaLinuxProcess::AlphaLinuxProcess(const std::string &name, + ObjectFile *objFile, + System *system, + int stdin_fd, + int stdout_fd, + int stderr_fd, + std::vector<std::string> &argv, + std::vector<std::string> &envp) + : AlphaLiveProcess(name, objFile, system, stdin_fd, stdout_fd, + stderr_fd, argv, envp), + Num_Syscall_Descs(sizeof(syscallDescs) / sizeof(SyscallDesc)) +{ + //init_regs->intRegFile[0] = 0; +} + + + +SyscallDesc* +AlphaLinuxProcess::getDesc(int callnum) +{ + if (callnum < 0 || callnum > Num_Syscall_Descs) + return NULL; + return &syscallDescs[callnum]; +} diff --git a/src/arch/alpha/linux/process.hh b/src/arch/alpha/linux/process.hh new file mode 100644 index 000000000..2e0566665 --- /dev/null +++ b/src/arch/alpha/linux/process.hh @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2003-2004 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ALPHA_LINUX_PROCESS_HH__ +#define __ALPHA_LINUX_PROCESS_HH__ + +#include "arch/alpha/process.hh" + +namespace AlphaISA { + +/// A process with emulated Alpha/Linux syscalls. +class AlphaLinuxProcess : public AlphaLiveProcess +{ + public: + /// Constructor. + AlphaLinuxProcess(const std::string &name, + ObjectFile *objFile, + System *system, + int stdin_fd, int stdout_fd, int stderr_fd, + std::vector<std::string> &argv, + std::vector<std::string> &envp); + + virtual SyscallDesc* getDesc(int callnum); + + /// The target system's hostname. + static const char *hostname; + + /// Array of syscall descriptors, indexed by call number. + static SyscallDesc syscallDescs[]; + + const int Num_Syscall_Descs; +}; + +} // namespace AlphaISA +#endif // __ALPHA_LINUX_PROCESS_HH__ diff --git a/src/arch/alpha/linux/system.cc b/src/arch/alpha/linux/system.cc new file mode 100644 index 000000000..cdb96096c --- /dev/null +++ b/src/arch/alpha/linux/system.cc @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This code loads the linux kernel, console, pal and patches certain + * functions. The symbol tables are loaded so that traces can show + * the executing function and we can skip functions. Various delay + * loops are skipped and their final values manually computed to speed + * up boot time. + */ + +#include "arch/arguments.hh" +#include "arch/vtophys.hh" +#include "arch/alpha/linux/system.hh" +#include "arch/alpha/linux/threadinfo.hh" +#include "arch/alpha/system.hh" +#include "base/loader/symtab.hh" +#include "cpu/exec_context.hh" +#include "cpu/base.hh" +#include "dev/platform.hh" +#include "kern/linux/printk.hh" +#include "kern/linux/events.hh" +#include "mem/physical.hh" +#include "mem/port.hh" +#include "sim/builder.hh" +#include "sim/byteswap.hh" + +using namespace std; +using namespace AlphaISA; +using namespace Linux; + +LinuxAlphaSystem::LinuxAlphaSystem(Params *p) + : AlphaSystem(p) +{ + Addr addr = 0; + + /** + * The symbol swapper_pg_dir marks the beginning of the kernel and + * the location of bootloader passed arguments + */ + if (!kernelSymtab->findAddress("swapper_pg_dir", KernelStart)) { + panic("Could not determine start location of kernel"); + } + + /** + * Since we aren't using a bootloader, we have to copy the + * kernel arguments directly into the kernel's memory. + */ + virtPort.writeBlob(CommandLine(), (uint8_t*)params()->boot_osflags.c_str(), + params()->boot_osflags.length()+1); + + /** + * find the address of the est_cycle_freq variable and insert it + * so we don't through the lengthly process of trying to + * calculated it by using the PIT, RTC, etc. + */ + if (kernelSymtab->findAddress("est_cycle_freq", addr)) + virtPort.write(addr, (uint64_t)(Clock::Frequency / + p->boot_cpu_frequency)); + + + /** + * EV5 only supports 127 ASNs so we are going to tell the kernel that the + * paritiuclar EV6 we have only supports 127 asns. + * @todo At some point we should change ev5.hh and the palcode to support + * 255 ASNs. + */ + if (kernelSymtab->findAddress("dp264_mv", addr)) + virtPort.write(addr + 0x18, LittleEndianGuest::htog((uint32_t)127)); + else + panic("could not find dp264_mv\n"); + +#ifndef NDEBUG + kernelPanicEvent = addKernelFuncEvent<BreakPCEvent>("panic"); + if (!kernelPanicEvent) + panic("could not find kernel symbol \'panic\'"); + +#if 0 + kernelDieEvent = addKernelFuncEvent<BreakPCEvent>("die_if_kernel"); + if (!kernelDieEvent) + panic("could not find kernel symbol \'die_if_kernel\'"); +#endif + +#endif + + /** + * Any time ide_delay_50ms, calibarte_delay or + * determine_cpu_caches is called just skip the + * function. Currently determine_cpu_caches only is used put + * information in proc, however if that changes in the future we + * will have to fill in the cache size variables appropriately. + */ + + skipIdeDelay50msEvent = + addKernelFuncEvent<SkipFuncEvent>("ide_delay_50ms"); + skipDelayLoopEvent = + addKernelFuncEvent<SkipDelayLoopEvent>("calibrate_delay"); + skipCacheProbeEvent = + addKernelFuncEvent<SkipFuncEvent>("determine_cpu_caches"); + debugPrintkEvent = addKernelFuncEvent<DebugPrintkEvent>("dprintk"); + idleStartEvent = addKernelFuncEvent<IdleStartEvent>("cpu_idle"); + + if (kernelSymtab->findAddress("alpha_switch_to", addr) && DTRACE(Thread)) { + printThreadEvent = new PrintThreadInfo(&pcEventQueue, "threadinfo", + addr + sizeof(MachInst) * 6); + } else { + printThreadEvent = NULL; + } + + if (params()->bin_int) { + intStartEvent = addPalFuncEvent<InterruptStartEvent>("sys_int_21"); + if (!intStartEvent) + panic("could not find symbol: sys_int_21\n"); + + intEndEvent = addPalFuncEvent<InterruptEndEvent>("rti_to_kern"); + if (!intEndEvent) + panic("could not find symbol: rti_to_kern\n"); + + intEndEvent2 = addPalFuncEvent<InterruptEndEvent>("rti_to_user"); + if (!intEndEvent2) + panic("could not find symbol: rti_to_user\n"); + + intEndEvent3 = addKernelFuncEvent<InterruptEndEvent>("do_softirq"); + if (!intEndEvent3) + panic("could not find symbol: do_softirq\n"); + } +} + +LinuxAlphaSystem::~LinuxAlphaSystem() +{ +#ifndef NDEBUG + delete kernelPanicEvent; +#endif + delete skipIdeDelay50msEvent; + delete skipDelayLoopEvent; + delete skipCacheProbeEvent; + delete debugPrintkEvent; + delete idleStartEvent; + delete printThreadEvent; + delete intStartEvent; + delete intEndEvent; + delete intEndEvent2; +} + + +void +LinuxAlphaSystem::setDelayLoop(ExecContext *xc) +{ + Addr addr = 0; + if (kernelSymtab->findAddress("loops_per_jiffy", addr)) { + Tick cpuFreq = xc->getCpuPtr()->frequency(); + Tick intrFreq = platform->intrFrequency(); + xc->getVirtPort(xc)->write(addr, + (uint32_t)((cpuFreq / intrFreq) * 0.9988)); + } +} + + +void +LinuxAlphaSystem::SkipDelayLoopEvent::process(ExecContext *xc) +{ + SkipFuncEvent::process(xc); + // calculate and set loops_per_jiffy + ((LinuxAlphaSystem *)xc->getSystemPtr())->setDelayLoop(xc); +} + +void +LinuxAlphaSystem::PrintThreadInfo::process(ExecContext *xc) +{ + Linux::ThreadInfo ti(xc); + + DPRINTF(Thread, "Currently Executing Thread %s, pid %d, started at: %d\n", + ti.curTaskName(), ti.curTaskPID(), ti.curTaskStart()); +} + + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(LinuxAlphaSystem) + + Param<Tick> boot_cpu_frequency; + SimObjectParam<PhysicalMemory *> physmem; + + Param<string> kernel; + Param<string> console; + Param<string> pal; + + Param<string> boot_osflags; + Param<string> readfile; + Param<unsigned int> init_param; + + Param<uint64_t> system_type; + Param<uint64_t> system_rev; + + Param<bool> bin; + VectorParam<string> binned_fns; + Param<bool> bin_int; + +END_DECLARE_SIM_OBJECT_PARAMS(LinuxAlphaSystem) + +BEGIN_INIT_SIM_OBJECT_PARAMS(LinuxAlphaSystem) + + INIT_PARAM(boot_cpu_frequency, "Frequency of the boot CPU"), + INIT_PARAM(physmem, "phsyical memory"), + INIT_PARAM(kernel, "file that contains the kernel code"), + INIT_PARAM(console, "file that contains the console code"), + INIT_PARAM(pal, "file that contains palcode"), + INIT_PARAM_DFLT(boot_osflags, "flags to pass to the kernel during boot", + "a"), + INIT_PARAM_DFLT(readfile, "file to read startup script from", ""), + INIT_PARAM_DFLT(init_param, "numerical value to pass into simulator", 0), + INIT_PARAM_DFLT(system_type, "Type of system we are emulating", 34), + INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 1<<10), + INIT_PARAM_DFLT(bin, "is this system to be binned", false), + INIT_PARAM(binned_fns, "functions to be broken down and binned"), + INIT_PARAM_DFLT(bin_int, "is interrupt code binned seperately?", true) + +END_INIT_SIM_OBJECT_PARAMS(LinuxAlphaSystem) + +CREATE_SIM_OBJECT(LinuxAlphaSystem) +{ + AlphaSystem::Params *p = new AlphaSystem::Params; + p->name = getInstanceName(); + p->boot_cpu_frequency = boot_cpu_frequency; + p->physmem = physmem; + p->kernel_path = kernel; + p->console_path = console; + p->palcode = pal; + p->boot_osflags = boot_osflags; + p->init_param = init_param; + p->readfile = readfile; + p->system_type = system_type; + p->system_rev = system_rev; + p->bin = bin; + p->binned_fns = binned_fns; + p->bin_int = bin_int; + return new LinuxAlphaSystem(p); +} + +REGISTER_SIM_OBJECT("LinuxAlphaSystem", LinuxAlphaSystem) + diff --git a/src/arch/alpha/linux/system.hh b/src/arch/alpha/linux/system.hh new file mode 100644 index 000000000..0c1fb037e --- /dev/null +++ b/src/arch/alpha/linux/system.hh @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2004-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ARCH_ALPHA_LINUX_SYSTEM_HH__ +#define __ARCH_ALPHA_LINUX_SYSTEM_HH__ + +class ExecContext; + +class BreakPCEvent; +class IdleStartEvent; + +#include "arch/alpha/system.hh" +#include "kern/linux/events.hh" + +using namespace AlphaISA; +using namespace Linux; + +/** + * This class contains linux specific system code (Loading, Events, Binning). + * It points to objects that are the system binaries to load and patches them + * appropriately to work in simulator. + */ +class LinuxAlphaSystem : public AlphaSystem +{ + private: + class SkipDelayLoopEvent : public SkipFuncEvent + { + public: + SkipDelayLoopEvent(PCEventQueue *q, const std::string &desc, Addr addr) + : SkipFuncEvent(q, desc, addr) {} + virtual void process(ExecContext *xc); + }; + + class PrintThreadInfo : public PCEvent + { + public: + PrintThreadInfo(PCEventQueue *q, const std::string &desc, Addr addr) + : PCEvent(q, desc, addr) {} + virtual void process(ExecContext *xc); + }; + + + /** + * Addresses defining where the kernel bootloader places various + * elements. Details found in include/asm-alpha/system.h + */ + Addr KernelStart; // Lookup the symbol swapper_pg_dir + + public: + Addr InitStack() const { return KernelStart + 0x02000; } + Addr EmptyPGT() const { return KernelStart + 0x04000; } + Addr EmptyPGE() const { return KernelStart + 0x08000; } + Addr ZeroPGE() const { return KernelStart + 0x0A000; } + Addr StartAddr() const { return KernelStart + 0x10000; } + + Addr Param() const { return ZeroPGE() + 0x0; } + Addr CommandLine() const { return Param() + 0x0; } + Addr InitrdStart() const { return Param() + 0x100; } + Addr InitrdSize() const { return Param() + 0x108; } + static const int CommandLineSize = 256; + + private: +#ifndef NDEBUG + /** Event to halt the simulator if the kernel calls panic() */ + BreakPCEvent *kernelPanicEvent; + + /** Event to halt the simulator if the kernel calls die_if_kernel */ + BreakPCEvent *kernelDieEvent; +#endif + + /** + * Event to skip determine_cpu_caches() because we don't support + * the IPRs that the code can access to figure out cache sizes + */ + SkipFuncEvent *skipCacheProbeEvent; + + /** PC based event to skip the ide_delay_50ms() call */ + SkipFuncEvent *skipIdeDelay50msEvent; + + /** + * PC based event to skip the dprink() call and emulate its + * functionality + */ + DebugPrintkEvent *debugPrintkEvent; + + /** + * Skip calculate_delay_loop() rather than waiting for this to be + * calculated + */ + SkipDelayLoopEvent *skipDelayLoopEvent; + + /** + * Event to print information about thread switches if the trace flag + * Thread is set + */ + PrintThreadInfo *printThreadEvent; + + /** + * Event to bin Interrupts seperately from kernel code + */ + InterruptStartEvent *intStartEvent; + + /** + * Event to bin Interrupts seperately from kernel code + */ + InterruptEndEvent *intEndEvent; + InterruptEndEvent *intEndEvent2; + InterruptEndEvent *intEndEvent3; + + /** Grab the PCBB of the idle process when it starts */ + IdleStartEvent *idleStartEvent; + + public: + LinuxAlphaSystem(Params *p); + ~LinuxAlphaSystem(); + + void setDelayLoop(ExecContext *xc); +}; + +#endif // __ARCH_ALPHA_LINUX_SYSTEM_HH__ diff --git a/arch/alpha/linux/thread_info.hh b/src/arch/alpha/linux/thread_info.hh index 88791b00d..88791b00d 100644 --- a/arch/alpha/linux/thread_info.hh +++ b/src/arch/alpha/linux/thread_info.hh diff --git a/arch/alpha/linux/threadinfo.hh b/src/arch/alpha/linux/threadinfo.hh index 8f03c9314..8f03c9314 100644 --- a/arch/alpha/linux/threadinfo.hh +++ b/src/arch/alpha/linux/threadinfo.hh diff --git a/arch/alpha/osfpal.cc b/src/arch/alpha/osfpal.cc index a48bd28d9..a48bd28d9 100644 --- a/arch/alpha/osfpal.cc +++ b/src/arch/alpha/osfpal.cc diff --git a/arch/alpha/osfpal.hh b/src/arch/alpha/osfpal.hh index f46d2bce1..f46d2bce1 100644 --- a/arch/alpha/osfpal.hh +++ b/src/arch/alpha/osfpal.hh diff --git a/src/arch/alpha/process.cc b/src/arch/alpha/process.cc new file mode 100644 index 000000000..25ee79692 --- /dev/null +++ b/src/arch/alpha/process.cc @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2003-2004 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "arch/alpha/constants.hh" +#include "arch/alpha/process.hh" +#include "arch/alpha/linux/process.hh" +#include "arch/alpha/tru64/process.hh" +#include "base/loader/object_file.hh" +#include "base/misc.hh" +#include "cpu/exec_context.hh" +#include "sim/builder.hh" +#include "sim/system.hh" + + +using namespace AlphaISA; +using namespace std; + +AlphaLiveProcess * +AlphaLiveProcess::create(const std::string &nm, System *system, int stdin_fd, + int stdout_fd, int stderr_fd, std::string executable, + std::vector<std::string> &argv, std::vector<std::string> &envp) +{ + AlphaLiveProcess *process = NULL; + + ObjectFile *objFile = createObjectFile(executable); + if (objFile == NULL) { + fatal("Can't load object file %s", executable); + } + + + if (objFile->getArch() != ObjectFile::Alpha) + fatal("Object file does not match architecture."); + switch (objFile->getOpSys()) { + case ObjectFile::Tru64: + process = new AlphaTru64Process(nm, objFile, system, + stdin_fd, stdout_fd, stderr_fd, + argv, envp); + break; + + case ObjectFile::Linux: + process = new AlphaLinuxProcess(nm, objFile, system, + stdin_fd, stdout_fd, stderr_fd, + argv, envp); + break; + + default: + fatal("Unknown/unsupported operating system."); + } + + if (process == NULL) + fatal("Unknown error creating process object."); + return process; +} + +AlphaLiveProcess::AlphaLiveProcess(const std::string &nm, ObjectFile *objFile, + System *_system, int stdin_fd, int stdout_fd, int stderr_fd, + std::vector<std::string> &argv, std::vector<std::string> &envp) + : LiveProcess(nm, objFile, _system, stdin_fd, stdout_fd, stderr_fd, + argv, envp) +{ + brk_point = objFile->dataBase() + objFile->dataSize() + objFile->bssSize(); + brk_point = roundUp(brk_point, VMPageSize); + + // Set up stack. On Alpha, stack goes below text section. This + // code should get moved to some architecture-specific spot. + stack_base = objFile->textBase() - (409600+4096); + + // Set up region for mmaps. Tru64 seems to start just above 0 and + // grow up from there. + mmap_start = mmap_end = 0x10000; + + // Set pointer for next thread stack. Reserve 8M for main stack. + next_thread_stack_base = stack_base - (8 * 1024 * 1024); + +} + +void +AlphaLiveProcess::startup() +{ + argsInit(MachineBytes, VMPageSize); + + execContexts[0]->setIntReg(GlobalPointerReg, objFile->globalPointer()); +} + + + + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaLiveProcess) + + VectorParam<string> cmd; + Param<string> executable; + Param<string> input; + Param<string> output; + VectorParam<string> env; + SimObjectParam<System *> system; + +END_DECLARE_SIM_OBJECT_PARAMS(AlphaLiveProcess) + + +BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaLiveProcess) + + INIT_PARAM(cmd, "command line (executable plus arguments)"), + INIT_PARAM(executable, "executable (overrides cmd[0] if set)"), + INIT_PARAM(input, "filename for stdin (dflt: use sim stdin)"), + INIT_PARAM(output, "filename for stdout/stderr (dflt: use sim stdout)"), + INIT_PARAM(env, "environment settings"), + INIT_PARAM(system, "system") + +END_INIT_SIM_OBJECT_PARAMS(AlphaLiveProcess) + + +CREATE_SIM_OBJECT(AlphaLiveProcess) +{ + string in = input; + string out = output; + + // initialize file descriptors to default: same as simulator + int stdin_fd, stdout_fd, stderr_fd; + + if (in == "stdin" || in == "cin") + stdin_fd = STDIN_FILENO; + else + stdin_fd = Process::openInputFile(input); + + if (out == "stdout" || out == "cout") + stdout_fd = STDOUT_FILENO; + else if (out == "stderr" || out == "cerr") + stdout_fd = STDERR_FILENO; + else + stdout_fd = Process::openOutputFile(out); + + stderr_fd = (stdout_fd != STDOUT_FILENO) ? stdout_fd : STDERR_FILENO; + + return AlphaLiveProcess::create(getInstanceName(), system, + stdin_fd, stdout_fd, stderr_fd, + (string)executable == "" ? cmd[0] : executable, + cmd, env); +} + + +REGISTER_SIM_OBJECT("AlphaLiveProcess", AlphaLiveProcess) + diff --git a/src/arch/alpha/process.hh b/src/arch/alpha/process.hh new file mode 100644 index 000000000..d97b36e2d --- /dev/null +++ b/src/arch/alpha/process.hh @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2003-2004 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ALPHA_PROCESS_HH__ +#define __ALPHA_PROCESS_HH__ + +#include <string> +#include <vector> +#include "sim/process.hh" + +class ObjectFile; +class System; + + +class AlphaLiveProcess : public LiveProcess +{ + protected: + AlphaLiveProcess(const std::string &nm, ObjectFile *objFile, + System *_system, int stdin_fd, int stdout_fd, int stderr_fd, + std::vector<std::string> &argv, + std::vector<std::string> &envp); + + void startup(); + + public: + // this function is used to create the LiveProcess object, since + // we can't tell which subclass of LiveProcess to use until we + // open and look at the object file. + static AlphaLiveProcess *create(const std::string &nm, + System *_system, + int stdin_fd, int stdout_fd, int stderr_fd, + std::string executable, + std::vector<std::string> &argv, + std::vector<std::string> &envp); + +}; + + +#endif // __ALPHA_PROCESS_HH__ diff --git a/src/arch/alpha/regfile.hh b/src/arch/alpha/regfile.hh new file mode 100644 index 000000000..af01b7829 --- /dev/null +++ b/src/arch/alpha/regfile.hh @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ARCH_ALPHA_REGFILE_HH__ +#define __ARCH_ALPHA_REGFILE_HH__ + +#include "arch/alpha/types.hh" +#include "arch/alpha/constants.hh" +#include "sim/faults.hh" + +class Checkpoint; +class ExecContext; + +namespace AlphaISA +{ + class IntRegFile + { + protected: + IntReg regs[NumIntRegs]; + + public: + + IntReg readReg(int intReg) + { + return regs[intReg]; + } + + Fault setReg(int intReg, const IntReg &val) + { + regs[intReg] = val; + return NoFault; + } + + void serialize(std::ostream &os); + + void unserialize(Checkpoint *cp, const std::string §ion); + + }; + + class FloatRegFile + { + public: + + union { + uint64_t q[NumFloatRegs]; // integer qword view + double d[NumFloatRegs]; // double-precision floating point view + }; + + void serialize(std::ostream &os); + + void unserialize(Checkpoint *cp, const std::string §ion); + + }; + + class MiscRegFile { + protected: + uint64_t fpcr; // floating point condition codes + uint64_t uniq; // process-unique register + bool lock_flag; // lock flag for LL/SC + Addr lock_addr; // lock address for LL/SC + + public: + MiscReg readReg(int misc_reg); + + MiscReg readRegWithEffect(int misc_reg, Fault &fault, + ExecContext *xc); + + //These functions should be removed once the simplescalar cpu model + //has been replaced. + int getInstAsid(); + int getDataAsid(); + + Fault setReg(int misc_reg, const MiscReg &val); + + Fault setRegWithEffect(int misc_reg, const MiscReg &val, + ExecContext *xc); + +#if FULL_SYSTEM + protected: + typedef uint64_t InternalProcReg; + + InternalProcReg ipr[NumInternalProcRegs]; // Internal processor regs + + private: + InternalProcReg readIpr(int idx, Fault &fault, ExecContext *xc); + + Fault setIpr(int idx, InternalProcReg val, ExecContext *xc); +#endif + friend class RegFile; + }; + + class RegFile { + + protected: + Addr pc; // program counter + Addr npc; // next-cycle program counter + Addr nnpc; + + public: + Addr readPC() + { + return pc; + } + + void setPC(Addr val) + { + pc = val; + } + + Addr readNextPC() + { + return npc; + } + + void setNextPC(Addr val) + { + npc = val; + } + + Addr readNextNPC() + { + return nnpc; + } + + void setNextNPC(Addr val) + { + nnpc = val; + } + + protected: + IntRegFile intRegFile; // (signed) integer register file + FloatRegFile floatRegFile; // floating point register file + MiscRegFile miscRegFile; // control register file + + public: + +#if FULL_SYSTEM + int intrflag; // interrupt flag + inline int instAsid() + { return miscRegFile.getInstAsid(); } + inline int dataAsid() + { return miscRegFile.getDataAsid(); } +#endif // FULL_SYSTEM + + void clear() + { + bzero(&intRegFile, sizeof(intRegFile)); + bzero(&floatRegFile, sizeof(floatRegFile)); + bzero(&miscRegFile, sizeof(miscRegFile)); + } + + MiscReg readMiscReg(int miscReg) + { + return miscRegFile.readReg(miscReg); + } + + MiscReg readMiscRegWithEffect(int miscReg, + Fault &fault, ExecContext *xc) + { + fault = NoFault; + return miscRegFile.readRegWithEffect(miscReg, fault, xc); + } + + Fault setMiscReg(int miscReg, const MiscReg &val) + { + return miscRegFile.setReg(miscReg, val); + } + + Fault setMiscRegWithEffect(int miscReg, const MiscReg &val, + ExecContext * xc) + { + return miscRegFile.setRegWithEffect(miscReg, val, xc); + } + + FloatReg readFloatReg(int floatReg) + { + return floatRegFile.d[floatReg]; + } + + FloatReg readFloatReg(int floatReg, int width) + { + return readFloatReg(floatReg); + } + + FloatRegBits readFloatRegBits(int floatReg) + { + return floatRegFile.q[floatReg]; + } + + FloatRegBits readFloatRegBits(int floatReg, int width) + { + return readFloatRegBits(floatReg); + } + + Fault setFloatReg(int floatReg, const FloatReg &val) + { + floatRegFile.d[floatReg] = val; + return NoFault; + } + + Fault setFloatReg(int floatReg, const FloatReg &val, int width) + { + return setFloatReg(floatReg, val); + } + + Fault setFloatRegBits(int floatReg, const FloatRegBits &val) + { + floatRegFile.q[floatReg] = val; + return NoFault; + } + + Fault setFloatRegBits(int floatReg, const FloatRegBits &val, int width) + { + return setFloatRegBits(floatReg, val); + } + + IntReg readIntReg(int intReg) + { + return intRegFile.readReg(intReg); + } + + Fault setIntReg(int intReg, const IntReg &val) + { + return intRegFile.setReg(intReg, val); + } + + void serialize(std::ostream &os); + void unserialize(Checkpoint *cp, const std::string §ion); + + enum ContextParam + { + CONTEXT_PALMODE + }; + + typedef bool ContextVal; + + void changeContext(ContextParam param, ContextVal val) + { + //This would be an alternative place to call/implement + //the swapPALShadow function + } + }; + + void copyRegs(ExecContext *src, ExecContext *dest); + + void copyMiscRegs(ExecContext *src, ExecContext *dest); + +#if FULL_SYSTEM + void copyIprs(ExecContext *src, ExecContext *dest); +#endif +} // namespace AlphaISA + +#endif diff --git a/src/arch/alpha/stacktrace.cc b/src/arch/alpha/stacktrace.cc new file mode 100644 index 000000000..8691e12dc --- /dev/null +++ b/src/arch/alpha/stacktrace.cc @@ -0,0 +1,344 @@ +/* + * Copyright (c) 2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <string> + +#include "arch/alpha/isa_traits.hh" +#include "arch/alpha/stacktrace.hh" +#include "arch/alpha/vtophys.hh" +#include "base/bitfield.hh" +#include "base/trace.hh" +#include "cpu/base.hh" +#include "cpu/exec_context.hh" +#include "sim/system.hh" + +using namespace std; +using namespace AlphaISA; + +ProcessInfo::ProcessInfo(ExecContext *_xc) + : xc(_xc) +{ + Addr addr = 0; + + if (!xc->getSystemPtr()->kernelSymtab->findAddress("thread_info_size", addr)) + panic("thread info not compiled into kernel\n"); + thread_info_size = gtoh(xc->getVirtPort()->read<int32_t>(addr)); + + if (!xc->getSystemPtr()->kernelSymtab->findAddress("task_struct_size", addr)) + panic("thread info not compiled into kernel\n"); + task_struct_size = gtoh(xc->getVirtPort()->read<int32_t>(addr)); + + if (!xc->getSystemPtr()->kernelSymtab->findAddress("thread_info_task", addr)) + panic("thread info not compiled into kernel\n"); + task_off = gtoh(xc->getVirtPort()->read<int32_t>(addr)); + + if (!xc->getSystemPtr()->kernelSymtab->findAddress("task_struct_pid", addr)) + panic("thread info not compiled into kernel\n"); + pid_off = gtoh(xc->getVirtPort()->read<int32_t>(addr)); + + if (!xc->getSystemPtr()->kernelSymtab->findAddress("task_struct_comm", addr)) + panic("thread info not compiled into kernel\n"); + name_off = gtoh(xc->getVirtPort()->read<int32_t>(addr)); +} + +Addr +ProcessInfo::task(Addr ksp) const +{ + Addr base = ksp & ~0x3fff; + if (base == ULL(0xfffffc0000000000)) + return 0; + + return gtoh(xc->getVirtPort()->read<Addr>(base + task_off)); +} + +int +ProcessInfo::pid(Addr ksp) const +{ + Addr task = this->task(ksp); + if (!task) + return -1; + + return gtoh(xc->getVirtPort()->read<uint16_t>(task + pid_off)); +} + +string +ProcessInfo::name(Addr ksp) const +{ + Addr task = this->task(ksp); + if (!task) + return "console"; + + char comm[256]; + CopyStringOut(xc, comm, task + name_off, sizeof(comm)); + if (!comm[0]) + return "startup"; + + return comm; +} + +StackTrace::StackTrace() + : xc(0), stack(64) +{ +} + +StackTrace::StackTrace(ExecContext *_xc, StaticInstPtr inst) + : xc(0), stack(64) +{ + trace(_xc, inst); +} + +StackTrace::~StackTrace() +{ +} + +void +StackTrace::trace(ExecContext *_xc, bool is_call) +{ + xc = _xc; + + bool usermode = (xc->readMiscReg(AlphaISA::IPR_DTB_CM) & 0x18) != 0; + + Addr pc = xc->readNextPC(); + bool kernel = xc->getSystemPtr()->kernelStart <= pc && + pc <= xc->getSystemPtr()->kernelEnd; + + if (usermode) { + stack.push_back(user); + return; + } + + if (!kernel) { + stack.push_back(console); + return; + } + + SymbolTable *symtab = xc->getSystemPtr()->kernelSymtab; + Addr ksp = xc->readIntReg(TheISA::StackPointerReg); + Addr bottom = ksp & ~0x3fff; + Addr addr; + + if (is_call) { + if (!symtab->findNearestAddr(pc, addr)) + panic("could not find address %#x", pc); + + stack.push_back(addr); + pc = xc->readPC(); + } + + Addr ra; + int size; + + while (ksp > bottom) { + if (!symtab->findNearestAddr(pc, addr)) + panic("could not find symbol for pc=%#x", pc); + assert(pc >= addr && "symbol botch: callpc < func"); + + stack.push_back(addr); + + if (isEntry(addr)) + return; + + if (decodePrologue(ksp, pc, addr, size, ra)) { + if (!ra) + return; + + if (size <= 0) { + stack.push_back(unknown); + return; + } + + pc = ra; + ksp += size; + } else { + stack.push_back(unknown); + return; + } + + bool kernel = xc->getSystemPtr()->kernelStart <= pc && + pc <= xc->getSystemPtr()->kernelEnd; + if (!kernel) + return; + + if (stack.size() >= 1000) + panic("unwinding too far"); + } + + panic("unwinding too far"); +} + +bool +StackTrace::isEntry(Addr addr) +{ + if (addr == xc->readMiscReg(AlphaISA::IPR_PALtemp12)) + return true; + + if (addr == xc->readMiscReg(AlphaISA::IPR_PALtemp7)) + return true; + + if (addr == xc->readMiscReg(AlphaISA::IPR_PALtemp11)) + return true; + + if (addr == xc->readMiscReg(AlphaISA::IPR_PALtemp21)) + return true; + + if (addr == xc->readMiscReg(AlphaISA::IPR_PALtemp9)) + return true; + + if (addr == xc->readMiscReg(AlphaISA::IPR_PALtemp2)) + return true; + + return false; +} + +bool +StackTrace::decodeStack(MachInst inst, int &disp) +{ + // lda $sp, -disp($sp) + // + // Opcode<31:26> == 0x08 + // RA<25:21> == 30 + // RB<20:16> == 30 + // Disp<15:0> + const MachInst mem_mask = 0xffff0000; + const MachInst lda_pattern = 0x23de0000; + const MachInst lda_disp_mask = 0x0000ffff; + + // subq $sp, disp, $sp + // addq $sp, disp, $sp + // + // Opcode<31:26> == 0x10 + // RA<25:21> == 30 + // Lit<20:13> + // One<12> = 1 + // Func<11:5> == 0x20 (addq) + // Func<11:5> == 0x29 (subq) + // RC<4:0> == 30 + const MachInst intop_mask = 0xffe01fff; + const MachInst addq_pattern = 0x43c0141e; + const MachInst subq_pattern = 0x43c0153e; + const MachInst intop_disp_mask = 0x001fe000; + const int intop_disp_shift = 13; + + if ((inst & mem_mask) == lda_pattern) + disp = -sext<16>(inst & lda_disp_mask); + else if ((inst & intop_mask) == addq_pattern) + disp = -int((inst & intop_disp_mask) >> intop_disp_shift); + else if ((inst & intop_mask) == subq_pattern) + disp = int((inst & intop_disp_mask) >> intop_disp_shift); + else + return false; + + return true; +} + +bool +StackTrace::decodeSave(MachInst inst, int ®, int &disp) +{ + // lda $stq, disp($sp) + // + // Opcode<31:26> == 0x08 + // RA<25:21> == ? + // RB<20:16> == 30 + // Disp<15:0> + const MachInst stq_mask = 0xfc1f0000; + const MachInst stq_pattern = 0xb41e0000; + const MachInst stq_disp_mask = 0x0000ffff; + const MachInst reg_mask = 0x03e00000; + const int reg_shift = 21; + + if ((inst & stq_mask) == stq_pattern) { + reg = (inst & reg_mask) >> reg_shift; + disp = sext<16>(inst & stq_disp_mask); + } else { + return false; + } + + return true; +} + +/* + * Decode the function prologue for the function we're in, and note + * which registers are stored where, and how large the stack frame is. + */ +bool +StackTrace::decodePrologue(Addr sp, Addr callpc, Addr func, + int &size, Addr &ra) +{ + size = 0; + ra = 0; + + for (Addr pc = func; pc < callpc; pc += sizeof(MachInst)) { + MachInst inst; + CopyOut(xc, (uint8_t *)&inst, pc, sizeof(MachInst)); + + int reg, disp; + if (decodeStack(inst, disp)) { + if (size) { + // panic("decoding frame size again"); + return true; + } + size += disp; + } else if (decodeSave(inst, reg, disp)) { + if (!ra && reg == ReturnAddressReg) { + CopyOut(xc, (uint8_t *)&ra, sp + disp, sizeof(Addr)); + if (!ra) { + // panic("no return address value pc=%#x\n", pc); + return false; + } + } + } + } + + return true; +} + +#if TRACING_ON +void +StackTrace::dump() +{ + StringWrap name(xc->getCpuPtr()->name()); + SymbolTable *symtab = xc->getSystemPtr()->kernelSymtab; + + DPRINTFN("------ Stack ------\n"); + + string symbol; + for (int i = 0, size = stack.size(); i < size; ++i) { + Addr addr = stack[size - i - 1]; + if (addr == user) + symbol = "user"; + else if (addr == console) + symbol = "console"; + else if (addr == unknown) + symbol = "unknown"; + else + symtab->findSymbol(addr, symbol); + + DPRINTFN("%#x: %s\n", addr, symbol); + } +} +#endif diff --git a/arch/alpha/stacktrace.hh b/src/arch/alpha/stacktrace.hh index 1d8d97a79..1d8d97a79 100644 --- a/arch/alpha/stacktrace.hh +++ b/src/arch/alpha/stacktrace.hh diff --git a/src/arch/alpha/system.cc b/src/arch/alpha/system.cc new file mode 100644 index 000000000..4234019cd --- /dev/null +++ b/src/arch/alpha/system.cc @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "arch/alpha/ev5.hh" +#include "arch/alpha/system.hh" +#include "arch/vtophys.hh" +#include "base/remote_gdb.hh" +#include "base/loader/object_file.hh" +#include "base/loader/symtab.hh" +#include "base/trace.hh" +#include "mem/physical.hh" +#include "sim/byteswap.hh" +#include "sim/builder.hh" + + +using namespace LittleEndianGuest; + +AlphaSystem::AlphaSystem(Params *p) + : System(p) +{ + consoleSymtab = new SymbolTable; + palSymtab = new SymbolTable; + + + /** + * Load the pal, and console code into memory + */ + // Load Console Code + console = createObjectFile(params()->console_path); + if (console == NULL) + fatal("Could not load console file %s", params()->console_path); + + // Load pal file + pal = createObjectFile(params()->palcode); + if (pal == NULL) + fatal("Could not load PALcode file %s", params()->palcode); + + + // Load program sections into memory + pal->loadSections(&functionalPort, AlphaISA::LoadAddrMask); + console->loadSections(&functionalPort, AlphaISA::LoadAddrMask); + + // load symbols + if (!console->loadGlobalSymbols(consoleSymtab)) + panic("could not load console symbols\n"); + + if (!pal->loadGlobalSymbols(palSymtab)) + panic("could not load pal symbols\n"); + + if (!pal->loadLocalSymbols(palSymtab)) + panic("could not load pal symbols\n"); + + if (!console->loadGlobalSymbols(debugSymbolTable)) + panic("could not load console symbols\n"); + + if (!pal->loadGlobalSymbols(debugSymbolTable)) + panic("could not load pal symbols\n"); + + if (!pal->loadLocalSymbols(debugSymbolTable)) + panic("could not load pal symbols\n"); + + Addr addr = 0; +#ifndef NDEBUG + consolePanicEvent = addConsoleFuncEvent<BreakPCEvent>("panic"); +#endif + + /** + * Copy the osflags (kernel arguments) into the consoles + * memory. (Presently Linux does not use the console service + * routine to get these command line arguments, but Tru64 and + * others do.) + */ + if (consoleSymtab->findAddress("env_booted_osflags", addr)) { + virtPort.writeBlob(addr, (uint8_t*)params()->boot_osflags.c_str(), + strlen(params()->boot_osflags.c_str())); + } + + /** + * Set the hardware reset parameter block system type and revision + * information to Tsunami. + */ + if (consoleSymtab->findAddress("m5_rpb", addr)) { + uint64_t data; + data = htog(params()->system_type); + virtPort.write(addr+0x50, data); + data = htog(params()->system_rev); + virtPort.write(addr+0x58, data); + } else + panic("could not find hwrpb\n"); + +} + +AlphaSystem::~AlphaSystem() +{ + delete consoleSymtab; + delete console; + delete pal; +#ifdef DEBUG + delete consolePanicEvent; +#endif +} + +/** + * This function fixes up addresses that are used to match PCs for + * hooking simulator events on to target function executions. + * + * Alpha binaries may have multiple global offset table (GOT) + * sections. A function that uses the GOT starts with a + * two-instruction prolog which sets the global pointer (gp == r29) to + * the appropriate GOT section. The proper gp value is calculated + * based on the function address, which must be passed by the caller + * in the procedure value register (pv aka t12 == r27). This sequence + * looks like the following: + * + * opcode Ra Rb offset + * ldah gp,X(pv) 09 29 27 X + * lda gp,Y(gp) 08 29 29 Y + * + * for some constant offsets X and Y. The catch is that the linker + * (or maybe even the compiler, I'm not sure) may recognize that the + * caller and callee are using the same GOT section, making this + * prolog redundant, and modify the call target to skip these + * instructions. If we check for execution of the first instruction + * of a function (the one the symbol points to) to detect when to skip + * it, we'll miss all these modified calls. It might work to + * unconditionally check for the third instruction, but not all + * functions have this prolog, and there's some chance that those + * first two instructions could have undesired consequences. So we do + * the Right Thing and pattern-match the first two instructions of the + * function to decide where to patch. + * + * Eventually this code should be moved into an ISA-specific file. + */ +Addr +AlphaSystem::fixFuncEventAddr(Addr addr) +{ + // mask for just the opcode, Ra, and Rb fields (not the offset) + const uint32_t inst_mask = 0xffff0000; + // ldah gp,X(pv): opcode 9, Ra = 29, Rb = 27 + const uint32_t gp_ldah_pattern = (9 << 26) | (29 << 21) | (27 << 16); + // lda gp,Y(gp): opcode 8, Ra = 29, rb = 29 + const uint32_t gp_lda_pattern = (8 << 26) | (29 << 21) | (29 << 16); + + uint32_t i1 = virtPort.read<uint32_t>(addr); + uint32_t i2 = virtPort.read<uint32_t>(addr + sizeof(AlphaISA::MachInst)); + + if ((i1 & inst_mask) == gp_ldah_pattern && + (i2 & inst_mask) == gp_lda_pattern) { + Addr new_addr = addr + 2* sizeof(AlphaISA::MachInst); + DPRINTF(Loader, "fixFuncEventAddr: %p -> %p", addr, new_addr); + return new_addr; + } else { + return addr; + } +} + + +void +AlphaSystem::setAlphaAccess(Addr access) +{ + Addr addr = 0; + if (consoleSymtab->findAddress("m5AlphaAccess", addr)) { + virtPort.write(addr, htog(EV5::Phys2K0Seg(access))); + } else + panic("could not find m5AlphaAccess\n"); +} + +bool +AlphaSystem::breakpoint() +{ + return remoteGDB[0]->trap(ALPHA_KENTRY_INT); +} + +void +AlphaSystem::serialize(std::ostream &os) +{ + System::serialize(os); + consoleSymtab->serialize("console_symtab", os); + palSymtab->serialize("pal_symtab", os); +} + + +void +AlphaSystem::unserialize(Checkpoint *cp, const std::string §ion) +{ + System::unserialize(cp,section); + consoleSymtab->unserialize("console_symtab", cp, section); + palSymtab->unserialize("pal_symtab", cp, section); +} + + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaSystem) + + Param<Tick> boot_cpu_frequency; + SimObjectParam<PhysicalMemory *> physmem; + + Param<std::string> kernel; + Param<std::string> console; + Param<std::string> pal; + + Param<std::string> boot_osflags; + Param<std::string> readfile; + Param<unsigned int> init_param; + + Param<uint64_t> system_type; + Param<uint64_t> system_rev; + + Param<bool> bin; + VectorParam<std::string> binned_fns; + Param<bool> bin_int; + +END_DECLARE_SIM_OBJECT_PARAMS(AlphaSystem) + +BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaSystem) + + INIT_PARAM(boot_cpu_frequency, "Frequency of the boot CPU"), + INIT_PARAM(physmem, "phsyical memory"), + INIT_PARAM(kernel, "file that contains the kernel code"), + INIT_PARAM(console, "file that contains the console code"), + INIT_PARAM(pal, "file that contains palcode"), + INIT_PARAM_DFLT(boot_osflags, "flags to pass to the kernel during boot", + "a"), + INIT_PARAM_DFLT(readfile, "file to read startup script from", ""), + INIT_PARAM_DFLT(init_param, "numerical value to pass into simulator", 0), + INIT_PARAM_DFLT(system_type, "Type of system we are emulating", 34), + INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 1<<10), + INIT_PARAM_DFLT(bin, "is this system to be binned", false), + INIT_PARAM(binned_fns, "functions to be broken down and binned"), + INIT_PARAM_DFLT(bin_int, "is interrupt code binned seperately?", true) + +END_INIT_SIM_OBJECT_PARAMS(AlphaSystem) + +CREATE_SIM_OBJECT(AlphaSystem) +{ + AlphaSystem::Params *p = new AlphaSystem::Params; + p->name = getInstanceName(); + p->boot_cpu_frequency = boot_cpu_frequency; + p->physmem = physmem; + p->kernel_path = kernel; + p->console_path = console; + p->palcode = pal; + p->boot_osflags = boot_osflags; + p->init_param = init_param; + p->readfile = readfile; + p->system_type = system_type; + p->system_rev = system_rev; + p->bin = bin; + p->binned_fns = binned_fns; + p->bin_int = bin_int; + return new AlphaSystem(p); +} + +REGISTER_SIM_OBJECT("AlphaSystem", AlphaSystem) + + diff --git a/src/arch/alpha/system.hh b/src/arch/alpha/system.hh new file mode 100644 index 000000000..924e16826 --- /dev/null +++ b/src/arch/alpha/system.hh @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ARCH_ALPHA_SYSTEM_HH__ +#define __ARCH_ALPHA_SYSTEM_HH__ + +#include <string> +#include <vector> + +#include "sim/system.hh" +#include "base/loader/symtab.hh" +#include "cpu/pc_event.hh" +#include "kern/system_events.hh" +#include "sim/sim_object.hh" + +class AlphaSystem : public System +{ + public: + struct Params : public System::Params + { + std::string console_path; + std::string palcode; + uint64_t system_type; + uint64_t system_rev; + }; + + AlphaSystem(Params *p); + + ~AlphaSystem(); + + virtual bool breakpoint(); + +/** + * Serialization stuff + */ + public: + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); + + /** + * Set the m5AlphaAccess pointer in the console + */ + void setAlphaAccess(Addr access); + + /** console symbol table */ + SymbolTable *consoleSymtab; + + /** pal symbol table */ + SymbolTable *palSymtab; + + /** Object pointer for the console code */ + ObjectFile *console; + + /** Object pointer for the PAL code */ + ObjectFile *pal; + +#ifndef NDEBUG + /** Event to halt the simulator if the console calls panic() */ + BreakPCEvent *consolePanicEvent; +#endif + protected: + const Params *params() const { return (const Params *)_params; } + + /** Add a function-based event to PALcode. */ + template <class T> + T *AlphaSystem::addPalFuncEvent(const char *lbl) + { + return addFuncEvent<T>(palSymtab, lbl); + } + + /** Add a function-based event to the console code. */ + template <class T> + T *AlphaSystem::addConsoleFuncEvent(const char *lbl) + { + return addFuncEvent<T>(consoleSymtab, lbl); + } + + virtual Addr fixFuncEventAddr(Addr addr); + +}; + +#endif + diff --git a/src/arch/alpha/tlb.cc b/src/arch/alpha/tlb.cc new file mode 100644 index 000000000..05b02d74b --- /dev/null +++ b/src/arch/alpha/tlb.cc @@ -0,0 +1,628 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <string> +#include <vector> + +#include "arch/alpha/tlb.hh" +#include "base/inifile.hh" +#include "base/str.hh" +#include "base/trace.hh" +#include "config/alpha_tlaser.hh" +#include "cpu/exec_context.hh" +#include "sim/builder.hh" + +using namespace std; +using namespace EV5; + +/////////////////////////////////////////////////////////////////////// +// +// Alpha TLB +// +#ifdef DEBUG +bool uncacheBit39 = false; +bool uncacheBit40 = false; +#endif + +#define MODE2MASK(X) (1 << (X)) + +AlphaTLB::AlphaTLB(const string &name, int s) + : SimObject(name), size(s), nlu(0) +{ + table = new AlphaISA::PTE[size]; + memset(table, 0, sizeof(AlphaISA::PTE[size])); +} + +AlphaTLB::~AlphaTLB() +{ + if (table) + delete [] table; +} + +// look up an entry in the TLB +AlphaISA::PTE * +AlphaTLB::lookup(Addr vpn, uint8_t asn) const +{ + // assume not found... + AlphaISA::PTE *retval = NULL; + + PageTable::const_iterator i = lookupTable.find(vpn); + if (i != lookupTable.end()) { + while (i->first == vpn) { + int index = i->second; + AlphaISA::PTE *pte = &table[index]; + assert(pte->valid); + if (vpn == pte->tag && (pte->asma || pte->asn == asn)) { + retval = pte; + break; + } + + ++i; + } + } + + DPRINTF(TLB, "lookup %#x, asn %#x -> %s ppn %#x\n", vpn, (int)asn, + retval ? "hit" : "miss", retval ? retval->ppn : 0); + return retval; +} + + +Fault +AlphaTLB::checkCacheability(RequestPtr &req) +{ + // in Alpha, cacheability is controlled by upper-level bits of the + // physical address + + /* + * We support having the uncacheable bit in either bit 39 or bit 40. + * The Turbolaser platform (and EV5) support having the bit in 39, but + * Tsunami (which Linux assumes uses an EV6) generates accesses with + * the bit in 40. So we must check for both, but we have debug flags + * to catch a weird case where both are used, which shouldn't happen. + */ + + +#if ALPHA_TLASER + if (req->getPaddr() & PAddrUncachedBit39) { +#else + if (req->getPaddr() & PAddrUncachedBit43) { +#endif + // IPR memory space not implemented + if (PAddrIprSpace(req->getPaddr())) { + return new UnimpFault("IPR memory space not implemented!"); + } else { + // mark request as uncacheable + req->setFlags(req->getFlags() | UNCACHEABLE); + +#if !ALPHA_TLASER + // Clear bits 42:35 of the physical address (10-2 in Tsunami manual) + req->setPaddr(req->getPaddr() & PAddrUncachedMask); +#endif + } + } + return NoFault; +} + + +// insert a new TLB entry +void +AlphaTLB::insert(Addr addr, AlphaISA::PTE &pte) +{ + AlphaISA::VAddr vaddr = addr; + if (table[nlu].valid) { + Addr oldvpn = table[nlu].tag; + PageTable::iterator i = lookupTable.find(oldvpn); + + if (i == lookupTable.end()) + panic("TLB entry not found in lookupTable"); + + int index; + while ((index = i->second) != nlu) { + if (table[index].tag != oldvpn) + panic("TLB entry not found in lookupTable"); + + ++i; + } + + DPRINTF(TLB, "remove @%d: %#x -> %#x\n", nlu, oldvpn, table[nlu].ppn); + + lookupTable.erase(i); + } + + DPRINTF(TLB, "insert @%d: %#x -> %#x\n", nlu, vaddr.vpn(), pte.ppn); + + table[nlu] = pte; + table[nlu].tag = vaddr.vpn(); + table[nlu].valid = true; + + lookupTable.insert(make_pair(vaddr.vpn(), nlu)); + nextnlu(); +} + +void +AlphaTLB::flushAll() +{ + DPRINTF(TLB, "flushAll\n"); + memset(table, 0, sizeof(AlphaISA::PTE[size])); + lookupTable.clear(); + nlu = 0; +} + +void +AlphaTLB::flushProcesses() +{ + PageTable::iterator i = lookupTable.begin(); + PageTable::iterator end = lookupTable.end(); + while (i != end) { + int index = i->second; + AlphaISA::PTE *pte = &table[index]; + assert(pte->valid); + + // we can't increment i after we erase it, so save a copy and + // increment it to get the next entry now + PageTable::iterator cur = i; + ++i; + + if (!pte->asma) { + DPRINTF(TLB, "flush @%d: %#x -> %#x\n", index, pte->tag, pte->ppn); + pte->valid = false; + lookupTable.erase(cur); + } + } +} + +void +AlphaTLB::flushAddr(Addr addr, uint8_t asn) +{ + AlphaISA::VAddr vaddr = addr; + + PageTable::iterator i = lookupTable.find(vaddr.vpn()); + if (i == lookupTable.end()) + return; + + while (i->first == vaddr.vpn()) { + int index = i->second; + AlphaISA::PTE *pte = &table[index]; + assert(pte->valid); + + if (vaddr.vpn() == pte->tag && (pte->asma || pte->asn == asn)) { + DPRINTF(TLB, "flushaddr @%d: %#x -> %#x\n", index, vaddr.vpn(), + pte->ppn); + + // invalidate this entry + pte->valid = false; + + lookupTable.erase(i); + } + + ++i; + } +} + + +void +AlphaTLB::serialize(ostream &os) +{ + SERIALIZE_SCALAR(size); + SERIALIZE_SCALAR(nlu); + + for (int i = 0; i < size; i++) { + nameOut(os, csprintf("%s.PTE%d", name(), i)); + table[i].serialize(os); + } +} + +void +AlphaTLB::unserialize(Checkpoint *cp, const string §ion) +{ + UNSERIALIZE_SCALAR(size); + UNSERIALIZE_SCALAR(nlu); + + for (int i = 0; i < size; i++) { + table[i].unserialize(cp, csprintf("%s.PTE%d", section, i)); + if (table[i].valid) { + lookupTable.insert(make_pair(table[i].tag, i)); + } + } +} + + +/////////////////////////////////////////////////////////////////////// +// +// Alpha ITB +// +AlphaITB::AlphaITB(const std::string &name, int size) + : AlphaTLB(name, size) +{} + + +void +AlphaITB::regStats() +{ + hits + .name(name() + ".hits") + .desc("ITB hits"); + misses + .name(name() + ".misses") + .desc("ITB misses"); + acv + .name(name() + ".acv") + .desc("ITB acv"); + accesses + .name(name() + ".accesses") + .desc("ITB accesses"); + + accesses = hits + misses; +} + + +Fault +AlphaITB::translate(RequestPtr &req, ExecContext *xc) const +{ + if (AlphaISA::PcPAL(req->getVaddr())) { + // strip off PAL PC marker (lsb is 1) + req->setPaddr((req->getVaddr() & ~3) & PAddrImplMask); + hits++; + return NoFault; + } + + if (req->getFlags() & PHYSICAL) { + req->setPaddr(req->getVaddr()); + } else { + // verify that this is a good virtual address + if (!validVirtualAddress(req->getVaddr())) { + acv++; + return new ItbAcvFault(req->getVaddr()); + } + + + // VA<42:41> == 2, VA<39:13> maps directly to PA<39:13> for EV5 + // VA<47:41> == 0x7e, VA<40:13> maps directly to PA<40:13> for EV6 +#if ALPHA_TLASER + if ((MCSR_SP(xc->readMiscReg(AlphaISA::IPR_MCSR)) & 2) && + VAddrSpaceEV5(req->getVaddr()) == 2) { +#else + if (VAddrSpaceEV6(req->getVaddr()) == 0x7e) { +#endif + // only valid in kernel mode + if (ICM_CM(xc->readMiscReg(AlphaISA::IPR_ICM)) != + AlphaISA::mode_kernel) { + acv++; + return new ItbAcvFault(req->getVaddr()); + } + + req->setPaddr(req->getVaddr() & PAddrImplMask); + +#if !ALPHA_TLASER + // sign extend the physical address properly + if (req->getPaddr() & PAddrUncachedBit40) + req->setPaddr(req->getPaddr() | ULL(0xf0000000000)); + else + req->setPaddr(req->getPaddr() & ULL(0xffffffffff)); +#endif + + } else { + // not a physical address: need to look up pte + int asn = DTB_ASN_ASN(xc->readMiscReg(AlphaISA::IPR_DTB_ASN)); + AlphaISA::PTE *pte = lookup(AlphaISA::VAddr(req->getVaddr()).vpn(), + asn); + + if (!pte) { + misses++; + return new ItbPageFault(req->getVaddr()); + } + + req->setPaddr((pte->ppn << AlphaISA::PageShift) + + (AlphaISA::VAddr(req->getVaddr()).offset() + & ~3)); + + // check permissions for this access + if (!(pte->xre & + (1 << ICM_CM(xc->readMiscReg(AlphaISA::IPR_ICM))))) { + // instruction access fault + acv++; + return new ItbAcvFault(req->getVaddr()); + } + + hits++; + } + } + + // check that the physical address is ok (catch bad physical addresses) + if (req->getPaddr() & ~PAddrImplMask) + return genMachineCheckFault(); + + return checkCacheability(req); + +} + +/////////////////////////////////////////////////////////////////////// +// +// Alpha DTB +// +AlphaDTB::AlphaDTB(const std::string &name, int size) + : AlphaTLB(name, size) +{} + +void +AlphaDTB::regStats() +{ + read_hits + .name(name() + ".read_hits") + .desc("DTB read hits") + ; + + read_misses + .name(name() + ".read_misses") + .desc("DTB read misses") + ; + + read_acv + .name(name() + ".read_acv") + .desc("DTB read access violations") + ; + + read_accesses + .name(name() + ".read_accesses") + .desc("DTB read accesses") + ; + + write_hits + .name(name() + ".write_hits") + .desc("DTB write hits") + ; + + write_misses + .name(name() + ".write_misses") + .desc("DTB write misses") + ; + + write_acv + .name(name() + ".write_acv") + .desc("DTB write access violations") + ; + + write_accesses + .name(name() + ".write_accesses") + .desc("DTB write accesses") + ; + + hits + .name(name() + ".hits") + .desc("DTB hits") + ; + + misses + .name(name() + ".misses") + .desc("DTB misses") + ; + + acv + .name(name() + ".acv") + .desc("DTB access violations") + ; + + accesses + .name(name() + ".accesses") + .desc("DTB accesses") + ; + + hits = read_hits + write_hits; + misses = read_misses + write_misses; + acv = read_acv + write_acv; + accesses = read_accesses + write_accesses; +} + +Fault +AlphaDTB::translate(RequestPtr &req, ExecContext *xc, bool write) const +{ + Addr pc = xc->readPC(); + + AlphaISA::mode_type mode = + (AlphaISA::mode_type)DTB_CM_CM(xc->readMiscReg(AlphaISA::IPR_DTB_CM)); + + + /** + * Check for alignment faults + */ + if (req->getVaddr() & (req->getSize() - 1)) { + DPRINTF(TLB, "Alignment Fault on %#x, size = %d", req->getVaddr(), + req->getSize()); + uint64_t flags = write ? MM_STAT_WR_MASK : 0; + return new DtbAlignmentFault(req->getVaddr(), req->getFlags(), flags); + } + + if (pc & 0x1) { + mode = (req->getFlags() & ALTMODE) ? + (AlphaISA::mode_type)ALT_MODE_AM( + xc->readMiscReg(AlphaISA::IPR_ALT_MODE)) + : AlphaISA::mode_kernel; + } + + if (req->getFlags() & PHYSICAL) { + req->setPaddr(req->getVaddr()); + } else { + // verify that this is a good virtual address + if (!validVirtualAddress(req->getVaddr())) { + if (write) { write_acv++; } else { read_acv++; } + uint64_t flags = (write ? MM_STAT_WR_MASK : 0) | + MM_STAT_BAD_VA_MASK | + MM_STAT_ACV_MASK; + return new DtbPageFault(req->getVaddr(), req->getFlags(), flags); + } + + // Check for "superpage" mapping +#if ALPHA_TLASER + if ((MCSR_SP(xc->readMiscReg(AlphaISA::IPR_MCSR)) & 2) && + VAddrSpaceEV5(req->getVaddr()) == 2) { +#else + if (VAddrSpaceEV6(req->getVaddr()) == 0x7e) { +#endif + + // only valid in kernel mode + if (DTB_CM_CM(xc->readMiscReg(AlphaISA::IPR_DTB_CM)) != + AlphaISA::mode_kernel) { + if (write) { write_acv++; } else { read_acv++; } + uint64_t flags = ((write ? MM_STAT_WR_MASK : 0) | + MM_STAT_ACV_MASK); + return new DtbAcvFault(req->getVaddr(), req->getFlags(), flags); + } + + req->setPaddr(req->getVaddr() & PAddrImplMask); + +#if !ALPHA_TLASER + // sign extend the physical address properly + if (req->getPaddr() & PAddrUncachedBit40) + req->setPaddr(req->getPaddr() | ULL(0xf0000000000)); + else + req->setPaddr(req->getPaddr() & ULL(0xffffffffff)); +#endif + + } else { + if (write) + write_accesses++; + else + read_accesses++; + + int asn = DTB_ASN_ASN(xc->readMiscReg(AlphaISA::IPR_DTB_ASN)); + + // not a physical address: need to look up pte + AlphaISA::PTE *pte = lookup(AlphaISA::VAddr(req->getVaddr()).vpn(), + asn); + + if (!pte) { + // page fault + if (write) { write_misses++; } else { read_misses++; } + uint64_t flags = (write ? MM_STAT_WR_MASK : 0) | + MM_STAT_DTB_MISS_MASK; + return (req->getFlags() & VPTE) ? + (Fault)(new PDtbMissFault(req->getVaddr(), req->getFlags(), + flags)) : + (Fault)(new NDtbMissFault(req->getVaddr(), req->getFlags(), + flags)); + } + + req->setPaddr((pte->ppn << AlphaISA::PageShift) + + AlphaISA::VAddr(req->getVaddr()).offset()); + + if (write) { + if (!(pte->xwe & MODE2MASK(mode))) { + // declare the instruction access fault + write_acv++; + uint64_t flags = MM_STAT_WR_MASK | + MM_STAT_ACV_MASK | + (pte->fonw ? MM_STAT_FONW_MASK : 0); + return new DtbPageFault(req->getVaddr(), req->getFlags(), flags); + } + if (pte->fonw) { + write_acv++; + uint64_t flags = MM_STAT_WR_MASK | + MM_STAT_FONW_MASK; + return new DtbPageFault(req->getVaddr(), req->getFlags(), flags); + } + } else { + if (!(pte->xre & MODE2MASK(mode))) { + read_acv++; + uint64_t flags = MM_STAT_ACV_MASK | + (pte->fonr ? MM_STAT_FONR_MASK : 0); + return new DtbAcvFault(req->getVaddr(), req->getFlags(), flags); + } + if (pte->fonr) { + read_acv++; + uint64_t flags = MM_STAT_FONR_MASK; + return new DtbPageFault(req->getVaddr(), req->getFlags(), flags); + } + } + } + + if (write) + write_hits++; + else + read_hits++; + } + + // check that the physical address is ok (catch bad physical addresses) + if (req->getPaddr() & ~PAddrImplMask) + return genMachineCheckFault(); + + return checkCacheability(req); +} + +AlphaISA::PTE & +AlphaTLB::index(bool advance) +{ + AlphaISA::PTE *pte = &table[nlu]; + + if (advance) + nextnlu(); + + return *pte; +} + +DEFINE_SIM_OBJECT_CLASS_NAME("AlphaTLB", AlphaTLB) + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaITB) + + Param<int> size; + +END_DECLARE_SIM_OBJECT_PARAMS(AlphaITB) + +BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaITB) + + INIT_PARAM_DFLT(size, "TLB size", 48) + +END_INIT_SIM_OBJECT_PARAMS(AlphaITB) + + +CREATE_SIM_OBJECT(AlphaITB) +{ + return new AlphaITB(getInstanceName(), size); +} + +REGISTER_SIM_OBJECT("AlphaITB", AlphaITB) + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaDTB) + + Param<int> size; + +END_DECLARE_SIM_OBJECT_PARAMS(AlphaDTB) + +BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaDTB) + + INIT_PARAM_DFLT(size, "TLB size", 64) + +END_INIT_SIM_OBJECT_PARAMS(AlphaDTB) + + +CREATE_SIM_OBJECT(AlphaDTB) +{ + return new AlphaDTB(getInstanceName(), size); +} + +REGISTER_SIM_OBJECT("AlphaDTB", AlphaDTB) + diff --git a/src/arch/alpha/tlb.hh b/src/arch/alpha/tlb.hh new file mode 100644 index 000000000..f6256020e --- /dev/null +++ b/src/arch/alpha/tlb.hh @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ALPHA_MEMORY_HH__ +#define __ALPHA_MEMORY_HH__ + +#include <map> + +#include "arch/alpha/ev5.hh" +#include "arch/alpha/isa_traits.hh" +#include "arch/alpha/faults.hh" +#include "base/statistics.hh" +#include "mem/request.hh" +#include "sim/sim_object.hh" + +class ExecContext; + +class AlphaTLB : public SimObject +{ + protected: + typedef std::multimap<Addr, int> PageTable; + PageTable lookupTable; // Quick lookup into page table + + AlphaISA::PTE *table; // the Page Table + int size; // TLB Size + int nlu; // not last used entry (for replacement) + + void nextnlu() { if (++nlu >= size) nlu = 0; } + AlphaISA::PTE *lookup(Addr vpn, uint8_t asn) const; + + public: + AlphaTLB(const std::string &name, int size); + virtual ~AlphaTLB(); + + int getsize() const { return size; } + + AlphaISA::PTE &index(bool advance = true); + void insert(Addr vaddr, AlphaISA::PTE &pte); + + void flushAll(); + void flushProcesses(); + void flushAddr(Addr addr, uint8_t asn); + + // static helper functions... really EV5 VM traits + static bool validVirtualAddress(Addr vaddr) { + // unimplemented bits must be all 0 or all 1 + Addr unimplBits = vaddr & EV5::VAddrUnImplMask; + return (unimplBits == 0) || (unimplBits == EV5::VAddrUnImplMask); + } + + static Fault checkCacheability(RequestPtr &req); + + // Checkpointing + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); +}; + +class AlphaITB : public AlphaTLB +{ + protected: + mutable Stats::Scalar<> hits; + mutable Stats::Scalar<> misses; + mutable Stats::Scalar<> acv; + mutable Stats::Formula accesses; + + public: + AlphaITB(const std::string &name, int size); + virtual void regStats(); + + Fault translate(RequestPtr &req, ExecContext *xc) const; +}; + +class AlphaDTB : public AlphaTLB +{ + protected: + mutable Stats::Scalar<> read_hits; + mutable Stats::Scalar<> read_misses; + mutable Stats::Scalar<> read_acv; + mutable Stats::Scalar<> read_accesses; + mutable Stats::Scalar<> write_hits; + mutable Stats::Scalar<> write_misses; + mutable Stats::Scalar<> write_acv; + mutable Stats::Scalar<> write_accesses; + Stats::Formula hits; + Stats::Formula misses; + Stats::Formula acv; + Stats::Formula accesses; + + public: + AlphaDTB(const std::string &name, int size); + virtual void regStats(); + + Fault translate(RequestPtr &req, ExecContext *xc, bool write) const; +}; + +#endif // __ALPHA_MEMORY_HH__ diff --git a/src/arch/alpha/tru64/process.cc b/src/arch/alpha/tru64/process.cc new file mode 100644 index 000000000..55f75f7d0 --- /dev/null +++ b/src/arch/alpha/tru64/process.cc @@ -0,0 +1,586 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "arch/alpha/tru64/tru64.hh" +#include "arch/alpha/isa_traits.hh" +#include "arch/alpha/tru64/process.hh" + +#include "cpu/exec_context.hh" +#include "kern/tru64/tru64.hh" + +#include "sim/process.hh" +#include "sim/syscall_emul.hh" + +using namespace std; +using namespace AlphaISA; + +/// Target uname() handler. +static SyscallReturn +unameFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + TypedBufferArg<AlphaTru64::utsname> name(xc->getSyscallArg(0)); + + strcpy(name->sysname, "OSF1"); + strcpy(name->nodename, "m5.eecs.umich.edu"); + strcpy(name->release, "V5.1"); + strcpy(name->version, "732"); + strcpy(name->machine, "alpha"); + + name.copyOut(xc->getMemPort()); + return 0; +} + +/// Target getsysyinfo() handler. +static SyscallReturn +getsysinfoFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + unsigned op = xc->getSyscallArg(0); + unsigned nbytes = xc->getSyscallArg(2); + + switch (op) { + + case AlphaTru64::GSI_MAX_CPU: { + TypedBufferArg<uint32_t> max_cpu(xc->getSyscallArg(1)); + *max_cpu = htog((uint32_t)process->numCpus()); + max_cpu.copyOut(xc->getMemPort()); + return 1; + } + + case AlphaTru64::GSI_CPUS_IN_BOX: { + TypedBufferArg<uint32_t> cpus_in_box(xc->getSyscallArg(1)); + *cpus_in_box = htog((uint32_t)process->numCpus()); + cpus_in_box.copyOut(xc->getMemPort()); + return 1; + } + + case AlphaTru64::GSI_PHYSMEM: { + TypedBufferArg<uint64_t> physmem(xc->getSyscallArg(1)); + *physmem = htog((uint64_t)1024 * 1024); // physical memory in KB + physmem.copyOut(xc->getMemPort()); + return 1; + } + + case AlphaTru64::GSI_CPU_INFO: { + TypedBufferArg<AlphaTru64::cpu_info> infop(xc->getSyscallArg(1)); + + infop->current_cpu = htog(0); + infop->cpus_in_box = htog(process->numCpus()); + infop->cpu_type = htog(57); + infop->ncpus = htog(process->numCpus()); + uint64_t cpumask = (1 << process->numCpus()) - 1; + infop->cpus_present = infop->cpus_running = htog(cpumask); + infop->cpu_binding = htog(0); + infop->cpu_ex_binding = htog(0); + infop->mhz = htog(667); + + infop.copyOut(xc->getMemPort()); + return 1; + } + + case AlphaTru64::GSI_PROC_TYPE: { + TypedBufferArg<uint64_t> proc_type(xc->getSyscallArg(1)); + *proc_type = htog((uint64_t)11); + proc_type.copyOut(xc->getMemPort()); + return 1; + } + + case AlphaTru64::GSI_PLATFORM_NAME: { + BufferArg bufArg(xc->getSyscallArg(1), nbytes); + strncpy((char *)bufArg.bufferPtr(), + "COMPAQ Professional Workstation XP1000", + nbytes); + bufArg.copyOut(xc->getMemPort()); + return 1; + } + + case AlphaTru64::GSI_CLK_TCK: { + TypedBufferArg<uint64_t> clk_hz(xc->getSyscallArg(1)); + *clk_hz = htog((uint64_t)1024); + clk_hz.copyOut(xc->getMemPort()); + return 1; + } + + default: + warn("getsysinfo: unknown op %d\n", op); + break; + } + + return 0; +} + +/// Target setsysyinfo() handler. +static SyscallReturn +setsysinfoFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + unsigned op = xc->getSyscallArg(0); + + switch (op) { + case AlphaTru64::SSI_IEEE_FP_CONTROL: + warn("setsysinfo: ignoring ieee_set_fp_control() arg 0x%x\n", + xc->getSyscallArg(1)); + break; + + default: + warn("setsysinfo: unknown op %d\n", op); + break; + } + + return 0; +} + + +/// Target table() handler. +static +SyscallReturn tableFunc(SyscallDesc *desc, int callnum,Process *process, + ExecContext *xc) +{ + using namespace std; + using namespace TheISA; + + int id = xc->getSyscallArg(0); // table ID + int index = xc->getSyscallArg(1); // index into table + // arg 2 is buffer pointer; type depends on table ID + int nel = xc->getSyscallArg(3); // number of elements + int lel = xc->getSyscallArg(4); // expected element size + + switch (id) { + case AlphaTru64::TBL_SYSINFO: { + if (index != 0 || nel != 1 || lel != sizeof(Tru64::tbl_sysinfo)) + return -EINVAL; + TypedBufferArg<Tru64::tbl_sysinfo> elp(xc->getSyscallArg(2)); + + const int clk_hz = one_million; + elp->si_user = htog(curTick / (Clock::Frequency / clk_hz)); + elp->si_nice = htog(0); + elp->si_sys = htog(0); + elp->si_idle = htog(0); + elp->wait = htog(0); + elp->si_hz = htog(clk_hz); + elp->si_phz = htog(clk_hz); + elp->si_boottime = htog(seconds_since_epoch); // seconds since epoch? + elp->si_max_procs = htog(process->numCpus()); + elp.copyOut(xc->getMemPort()); + return 0; + } + + default: + cerr << "table(): id " << id << " unknown." << endl; + return -EINVAL; + } +} + +SyscallDesc AlphaTru64Process::syscallDescs[] = { + /* 0 */ SyscallDesc("syscall (#0)", AlphaTru64::indirectSyscallFunc, + SyscallDesc::SuppressReturnValue), + /* 1 */ SyscallDesc("exit", exitFunc), + /* 2 */ SyscallDesc("fork", unimplementedFunc), + /* 3 */ SyscallDesc("read", readFunc), + /* 4 */ SyscallDesc("write", writeFunc), + /* 5 */ SyscallDesc("old_open", unimplementedFunc), + /* 6 */ SyscallDesc("close", closeFunc), + /* 7 */ SyscallDesc("wait4", unimplementedFunc), + /* 8 */ SyscallDesc("old_creat", unimplementedFunc), + /* 9 */ SyscallDesc("link", unimplementedFunc), + /* 10 */ SyscallDesc("unlink", unlinkFunc), + /* 11 */ SyscallDesc("execv", unimplementedFunc), + /* 12 */ SyscallDesc("chdir", unimplementedFunc), + /* 13 */ SyscallDesc("fchdir", unimplementedFunc), + /* 14 */ SyscallDesc("mknod", unimplementedFunc), + /* 15 */ SyscallDesc("chmod", unimplementedFunc), + /* 16 */ SyscallDesc("chown", unimplementedFunc), + /* 17 */ SyscallDesc("obreak", obreakFunc), + /* 18 */ SyscallDesc("pre_F64_getfsstat", unimplementedFunc), + /* 19 */ SyscallDesc("lseek", lseekFunc), + /* 20 */ SyscallDesc("getpid", getpidPseudoFunc), + /* 21 */ SyscallDesc("mount", unimplementedFunc), + /* 22 */ SyscallDesc("unmount", unimplementedFunc), + /* 23 */ SyscallDesc("setuid", setuidFunc), + /* 24 */ SyscallDesc("getuid", getuidPseudoFunc), + /* 25 */ SyscallDesc("exec_with_loader", unimplementedFunc), + /* 26 */ SyscallDesc("ptrace", unimplementedFunc), + /* 27 */ SyscallDesc("recvmsg", unimplementedFunc), + /* 28 */ SyscallDesc("sendmsg", unimplementedFunc), + /* 29 */ SyscallDesc("recvfrom", unimplementedFunc), + /* 30 */ SyscallDesc("accept", unimplementedFunc), + /* 31 */ SyscallDesc("getpeername", unimplementedFunc), + /* 32 */ SyscallDesc("getsockname", unimplementedFunc), + /* 33 */ SyscallDesc("access", unimplementedFunc), + /* 34 */ SyscallDesc("chflags", unimplementedFunc), + /* 35 */ SyscallDesc("fchflags", unimplementedFunc), + /* 36 */ SyscallDesc("sync", unimplementedFunc), + /* 37 */ SyscallDesc("kill", unimplementedFunc), + /* 38 */ SyscallDesc("old_stat", unimplementedFunc), + /* 39 */ SyscallDesc("setpgid", unimplementedFunc), + /* 40 */ SyscallDesc("old_lstat", unimplementedFunc), + /* 41 */ SyscallDesc("dup", unimplementedFunc), + /* 42 */ SyscallDesc("pipe", unimplementedFunc), + /* 43 */ SyscallDesc("set_program_attributes", unimplementedFunc), + /* 44 */ SyscallDesc("profil", unimplementedFunc), + /* 45 */ SyscallDesc("open", openFunc<AlphaTru64>), + /* 46 */ SyscallDesc("obsolete osigaction", unimplementedFunc), + /* 47 */ SyscallDesc("getgid", getgidPseudoFunc), + /* 48 */ SyscallDesc("sigprocmask", ignoreFunc), + /* 49 */ SyscallDesc("getlogin", unimplementedFunc), + /* 50 */ SyscallDesc("setlogin", unimplementedFunc), + /* 51 */ SyscallDesc("acct", unimplementedFunc), + /* 52 */ SyscallDesc("sigpending", unimplementedFunc), + /* 53 */ SyscallDesc("classcntl", unimplementedFunc), + /* 54 */ SyscallDesc("ioctl", ioctlFunc<AlphaTru64>), + /* 55 */ SyscallDesc("reboot", unimplementedFunc), + /* 56 */ SyscallDesc("revoke", unimplementedFunc), + /* 57 */ SyscallDesc("symlink", unimplementedFunc), + /* 58 */ SyscallDesc("readlink", unimplementedFunc), + /* 59 */ SyscallDesc("execve", unimplementedFunc), + /* 60 */ SyscallDesc("umask", unimplementedFunc), + /* 61 */ SyscallDesc("chroot", unimplementedFunc), + /* 62 */ SyscallDesc("old_fstat", unimplementedFunc), + /* 63 */ SyscallDesc("getpgrp", unimplementedFunc), + /* 64 */ SyscallDesc("getpagesize", getpagesizeFunc), + /* 65 */ SyscallDesc("mremap", unimplementedFunc), + /* 66 */ SyscallDesc("vfork", unimplementedFunc), + /* 67 */ SyscallDesc("pre_F64_stat", statFunc<AlphaTru64::PreF64>), + /* 68 */ SyscallDesc("pre_F64_lstat", lstatFunc<AlphaTru64::PreF64>), + /* 69 */ SyscallDesc("sbrk", unimplementedFunc), + /* 70 */ SyscallDesc("sstk", unimplementedFunc), + /* 71 */ SyscallDesc("mmap", mmapFunc<AlphaTru64>), + /* 72 */ SyscallDesc("ovadvise", unimplementedFunc), + /* 73 */ SyscallDesc("munmap", munmapFunc), + /* 74 */ SyscallDesc("mprotect", ignoreFunc), + /* 75 */ SyscallDesc("madvise", unimplementedFunc), + /* 76 */ SyscallDesc("old_vhangup", unimplementedFunc), + /* 77 */ SyscallDesc("kmodcall", unimplementedFunc), + /* 78 */ SyscallDesc("mincore", unimplementedFunc), + /* 79 */ SyscallDesc("getgroups", unimplementedFunc), + /* 80 */ SyscallDesc("setgroups", unimplementedFunc), + /* 81 */ SyscallDesc("old_getpgrp", unimplementedFunc), + /* 82 */ SyscallDesc("setpgrp", unimplementedFunc), + /* 83 */ SyscallDesc("setitimer", unimplementedFunc), + /* 84 */ SyscallDesc("old_wait", unimplementedFunc), + /* 85 */ SyscallDesc("table", tableFunc), + /* 86 */ SyscallDesc("getitimer", unimplementedFunc), + /* 87 */ SyscallDesc("gethostname", gethostnameFunc), + /* 88 */ SyscallDesc("sethostname", unimplementedFunc), + /* 89 */ SyscallDesc("getdtablesize", unimplementedFunc), + /* 90 */ SyscallDesc("dup2", unimplementedFunc), + /* 91 */ SyscallDesc("pre_F64_fstat", fstatFunc<AlphaTru64::PreF64>), + /* 92 */ SyscallDesc("fcntl", fcntlFunc), + /* 93 */ SyscallDesc("select", unimplementedFunc), + /* 94 */ SyscallDesc("poll", unimplementedFunc), + /* 95 */ SyscallDesc("fsync", unimplementedFunc), + /* 96 */ SyscallDesc("setpriority", unimplementedFunc), + /* 97 */ SyscallDesc("socket", unimplementedFunc), + /* 98 */ SyscallDesc("connect", unimplementedFunc), + /* 99 */ SyscallDesc("old_accept", unimplementedFunc), + /* 100 */ SyscallDesc("getpriority", unimplementedFunc), + /* 101 */ SyscallDesc("old_send", unimplementedFunc), + /* 102 */ SyscallDesc("old_recv", unimplementedFunc), + /* 103 */ SyscallDesc("sigreturn", AlphaTru64::sigreturnFunc, + SyscallDesc::SuppressReturnValue), + /* 104 */ SyscallDesc("bind", unimplementedFunc), + /* 105 */ SyscallDesc("setsockopt", unimplementedFunc), + /* 106 */ SyscallDesc("listen", unimplementedFunc), + /* 107 */ SyscallDesc("plock", unimplementedFunc), + /* 108 */ SyscallDesc("old_sigvec", unimplementedFunc), + /* 109 */ SyscallDesc("old_sigblock", unimplementedFunc), + /* 110 */ SyscallDesc("old_sigsetmask", unimplementedFunc), + /* 111 */ SyscallDesc("sigsuspend", unimplementedFunc), + /* 112 */ SyscallDesc("sigstack", ignoreFunc), + /* 113 */ SyscallDesc("old_recvmsg", unimplementedFunc), + /* 114 */ SyscallDesc("old_sendmsg", unimplementedFunc), + /* 115 */ SyscallDesc("obsolete vtrace", unimplementedFunc), + /* 116 */ SyscallDesc("gettimeofday", gettimeofdayFunc<AlphaTru64>), + /* 117 */ SyscallDesc("getrusage", getrusageFunc<AlphaTru64>), + /* 118 */ SyscallDesc("getsockopt", unimplementedFunc), + /* 119 */ SyscallDesc("numa_syscalls", unimplementedFunc), + /* 120 */ SyscallDesc("readv", unimplementedFunc), + /* 121 */ SyscallDesc("writev", unimplementedFunc), + /* 122 */ SyscallDesc("settimeofday", unimplementedFunc), + /* 123 */ SyscallDesc("fchown", unimplementedFunc), + /* 124 */ SyscallDesc("fchmod", unimplementedFunc), + /* 125 */ SyscallDesc("old_recvfrom", unimplementedFunc), + /* 126 */ SyscallDesc("setreuid", unimplementedFunc), + /* 127 */ SyscallDesc("setregid", unimplementedFunc), + /* 128 */ SyscallDesc("rename", renameFunc), + /* 129 */ SyscallDesc("truncate", truncateFunc), + /* 130 */ SyscallDesc("ftruncate", ftruncateFunc), + /* 131 */ SyscallDesc("flock", unimplementedFunc), + /* 132 */ SyscallDesc("setgid", unimplementedFunc), + /* 133 */ SyscallDesc("sendto", unimplementedFunc), + /* 134 */ SyscallDesc("shutdown", unimplementedFunc), + /* 135 */ SyscallDesc("socketpair", unimplementedFunc), + /* 136 */ SyscallDesc("mkdir", unimplementedFunc), + /* 137 */ SyscallDesc("rmdir", unimplementedFunc), + /* 138 */ SyscallDesc("utimes", unimplementedFunc), + /* 139 */ SyscallDesc("obsolete 4.2 sigreturn", unimplementedFunc), + /* 140 */ SyscallDesc("adjtime", unimplementedFunc), + /* 141 */ SyscallDesc("old_getpeername", unimplementedFunc), + /* 142 */ SyscallDesc("gethostid", unimplementedFunc), + /* 143 */ SyscallDesc("sethostid", unimplementedFunc), + /* 144 */ SyscallDesc("getrlimit", getrlimitFunc<AlphaTru64>), + /* 145 */ SyscallDesc("setrlimit", ignoreFunc), + /* 146 */ SyscallDesc("old_killpg", unimplementedFunc), + /* 147 */ SyscallDesc("setsid", unimplementedFunc), + /* 148 */ SyscallDesc("quotactl", unimplementedFunc), + /* 149 */ SyscallDesc("oldquota", unimplementedFunc), + /* 150 */ SyscallDesc("old_getsockname", unimplementedFunc), + /* 151 */ SyscallDesc("pread", unimplementedFunc), + /* 152 */ SyscallDesc("pwrite", unimplementedFunc), + /* 153 */ SyscallDesc("pid_block", unimplementedFunc), + /* 154 */ SyscallDesc("pid_unblock", unimplementedFunc), + /* 155 */ SyscallDesc("signal_urti", unimplementedFunc), + /* 156 */ SyscallDesc("sigaction", ignoreFunc), + /* 157 */ SyscallDesc("sigwaitprim", unimplementedFunc), + /* 158 */ SyscallDesc("nfssvc", unimplementedFunc), + /* 159 */ SyscallDesc("getdirentries", AlphaTru64::getdirentriesFunc), + /* 160 */ SyscallDesc("pre_F64_statfs", statfsFunc<AlphaTru64::PreF64>), + /* 161 */ SyscallDesc("pre_F64_fstatfs", fstatfsFunc<AlphaTru64::PreF64>), + /* 162 */ SyscallDesc("unknown #162", unimplementedFunc), + /* 163 */ SyscallDesc("async_daemon", unimplementedFunc), + /* 164 */ SyscallDesc("getfh", unimplementedFunc), + /* 165 */ SyscallDesc("getdomainname", unimplementedFunc), + /* 166 */ SyscallDesc("setdomainname", unimplementedFunc), + /* 167 */ SyscallDesc("unknown #167", unimplementedFunc), + /* 168 */ SyscallDesc("unknown #168", unimplementedFunc), + /* 169 */ SyscallDesc("exportfs", unimplementedFunc), + /* 170 */ SyscallDesc("unknown #170", unimplementedFunc), + /* 171 */ SyscallDesc("unknown #171", unimplementedFunc), + /* 172 */ SyscallDesc("unknown #172", unimplementedFunc), + /* 173 */ SyscallDesc("unknown #173", unimplementedFunc), + /* 174 */ SyscallDesc("unknown #174", unimplementedFunc), + /* 175 */ SyscallDesc("unknown #175", unimplementedFunc), + /* 176 */ SyscallDesc("unknown #176", unimplementedFunc), + /* 177 */ SyscallDesc("unknown #177", unimplementedFunc), + /* 178 */ SyscallDesc("unknown #178", unimplementedFunc), + /* 179 */ SyscallDesc("unknown #179", unimplementedFunc), + /* 180 */ SyscallDesc("unknown #180", unimplementedFunc), + /* 181 */ SyscallDesc("alt_plock", unimplementedFunc), + /* 182 */ SyscallDesc("unknown #182", unimplementedFunc), + /* 183 */ SyscallDesc("unknown #183", unimplementedFunc), + /* 184 */ SyscallDesc("getmnt", unimplementedFunc), + /* 185 */ SyscallDesc("unknown #185", unimplementedFunc), + /* 186 */ SyscallDesc("unknown #186", unimplementedFunc), + /* 187 */ SyscallDesc("alt_sigpending", unimplementedFunc), + /* 188 */ SyscallDesc("alt_setsid", unimplementedFunc), + /* 189 */ SyscallDesc("unknown #189", unimplementedFunc), + /* 190 */ SyscallDesc("unknown #190", unimplementedFunc), + /* 191 */ SyscallDesc("unknown #191", unimplementedFunc), + /* 192 */ SyscallDesc("unknown #192", unimplementedFunc), + /* 193 */ SyscallDesc("unknown #193", unimplementedFunc), + /* 194 */ SyscallDesc("unknown #194", unimplementedFunc), + /* 195 */ SyscallDesc("unknown #195", unimplementedFunc), + /* 196 */ SyscallDesc("unknown #196", unimplementedFunc), + /* 197 */ SyscallDesc("unknown #197", unimplementedFunc), + /* 198 */ SyscallDesc("unknown #198", unimplementedFunc), + /* 199 */ SyscallDesc("swapon", unimplementedFunc), + /* 200 */ SyscallDesc("msgctl", unimplementedFunc), + /* 201 */ SyscallDesc("msgget", unimplementedFunc), + /* 202 */ SyscallDesc("msgrcv", unimplementedFunc), + /* 203 */ SyscallDesc("msgsnd", unimplementedFunc), + /* 204 */ SyscallDesc("semctl", unimplementedFunc), + /* 205 */ SyscallDesc("semget", unimplementedFunc), + /* 206 */ SyscallDesc("semop", unimplementedFunc), + /* 207 */ SyscallDesc("uname", unameFunc), + /* 208 */ SyscallDesc("lchown", unimplementedFunc), + /* 209 */ SyscallDesc("shmat", unimplementedFunc), + /* 210 */ SyscallDesc("shmctl", unimplementedFunc), + /* 211 */ SyscallDesc("shmdt", unimplementedFunc), + /* 212 */ SyscallDesc("shmget", unimplementedFunc), + /* 213 */ SyscallDesc("mvalid", unimplementedFunc), + /* 214 */ SyscallDesc("getaddressconf", unimplementedFunc), + /* 215 */ SyscallDesc("msleep", unimplementedFunc), + /* 216 */ SyscallDesc("mwakeup", unimplementedFunc), + /* 217 */ SyscallDesc("msync", unimplementedFunc), + /* 218 */ SyscallDesc("signal", unimplementedFunc), + /* 219 */ SyscallDesc("utc_gettime", unimplementedFunc), + /* 220 */ SyscallDesc("utc_adjtime", unimplementedFunc), + /* 221 */ SyscallDesc("unknown #221", unimplementedFunc), + /* 222 */ SyscallDesc("security", unimplementedFunc), + /* 223 */ SyscallDesc("kloadcall", unimplementedFunc), + /* 224 */ SyscallDesc("stat", statFunc<AlphaTru64::F64>), + /* 225 */ SyscallDesc("lstat", lstatFunc<AlphaTru64::F64>), + /* 226 */ SyscallDesc("fstat", fstatFunc<AlphaTru64::F64>), + /* 227 */ SyscallDesc("statfs", statfsFunc<AlphaTru64::F64>), + /* 228 */ SyscallDesc("fstatfs", fstatfsFunc<AlphaTru64::F64>), + /* 229 */ SyscallDesc("getfsstat", unimplementedFunc), + /* 230 */ SyscallDesc("gettimeofday64", unimplementedFunc), + /* 231 */ SyscallDesc("settimeofday64", unimplementedFunc), + /* 232 */ SyscallDesc("unknown #232", unimplementedFunc), + /* 233 */ SyscallDesc("getpgid", unimplementedFunc), + /* 234 */ SyscallDesc("getsid", unimplementedFunc), + /* 235 */ SyscallDesc("sigaltstack", ignoreFunc), + /* 236 */ SyscallDesc("waitid", unimplementedFunc), + /* 237 */ SyscallDesc("priocntlset", unimplementedFunc), + /* 238 */ SyscallDesc("sigsendset", unimplementedFunc), + /* 239 */ SyscallDesc("set_speculative", unimplementedFunc), + /* 240 */ SyscallDesc("msfs_syscall", unimplementedFunc), + /* 241 */ SyscallDesc("sysinfo", unimplementedFunc), + /* 242 */ SyscallDesc("uadmin", unimplementedFunc), + /* 243 */ SyscallDesc("fuser", unimplementedFunc), + /* 244 */ SyscallDesc("proplist_syscall", unimplementedFunc), + /* 245 */ SyscallDesc("ntp_adjtime", unimplementedFunc), + /* 246 */ SyscallDesc("ntp_gettime", unimplementedFunc), + /* 247 */ SyscallDesc("pathconf", unimplementedFunc), + /* 248 */ SyscallDesc("fpathconf", unimplementedFunc), + /* 249 */ SyscallDesc("sync2", unimplementedFunc), + /* 250 */ SyscallDesc("uswitch", unimplementedFunc), + /* 251 */ SyscallDesc("usleep_thread", unimplementedFunc), + /* 252 */ SyscallDesc("audcntl", unimplementedFunc), + /* 253 */ SyscallDesc("audgen", unimplementedFunc), + /* 254 */ SyscallDesc("sysfs", unimplementedFunc), + /* 255 */ SyscallDesc("subsys_info", unimplementedFunc), + /* 256 */ SyscallDesc("getsysinfo", getsysinfoFunc), + /* 257 */ SyscallDesc("setsysinfo", setsysinfoFunc), + /* 258 */ SyscallDesc("afs_syscall", unimplementedFunc), + /* 259 */ SyscallDesc("swapctl", unimplementedFunc), + /* 260 */ SyscallDesc("memcntl", unimplementedFunc), + /* 261 */ SyscallDesc("fdatasync", unimplementedFunc), + /* 262 */ SyscallDesc("oflock", unimplementedFunc), + /* 263 */ SyscallDesc("F64_readv", unimplementedFunc), + /* 264 */ SyscallDesc("F64_writev", unimplementedFunc), + /* 265 */ SyscallDesc("cdslxlate", unimplementedFunc), + /* 266 */ SyscallDesc("sendfile", unimplementedFunc), +}; + + + +SyscallDesc AlphaTru64Process::machSyscallDescs[] = { + /* 0 */ SyscallDesc("kern_invalid", unimplementedFunc), + /* 1 */ SyscallDesc("m5_mutex_lock", AlphaTru64::m5_mutex_lockFunc), + /* 2 */ SyscallDesc("m5_mutex_trylock", AlphaTru64::m5_mutex_trylockFunc), + /* 3 */ SyscallDesc("m5_mutex_unlock", AlphaTru64::m5_mutex_unlockFunc), + /* 4 */ SyscallDesc("m5_cond_signal", AlphaTru64::m5_cond_signalFunc), + /* 5 */ SyscallDesc("m5_cond_broadcast", AlphaTru64::m5_cond_broadcastFunc), + /* 6 */ SyscallDesc("m5_cond_wait", AlphaTru64::m5_cond_waitFunc), + /* 7 */ SyscallDesc("m5_thread_exit", AlphaTru64::m5_thread_exitFunc), + /* 8 */ SyscallDesc("kern_invalid", unimplementedFunc), + /* 9 */ SyscallDesc("kern_invalid", unimplementedFunc), + /* 10 */ SyscallDesc("task_self", unimplementedFunc), + /* 11 */ SyscallDesc("thread_reply", unimplementedFunc), + /* 12 */ SyscallDesc("task_notify", unimplementedFunc), + /* 13 */ SyscallDesc("thread_self", unimplementedFunc), + /* 14 */ SyscallDesc("kern_invalid", unimplementedFunc), + /* 15 */ SyscallDesc("kern_invalid", unimplementedFunc), + /* 16 */ SyscallDesc("kern_invalid", unimplementedFunc), + /* 17 */ SyscallDesc("kern_invalid", unimplementedFunc), + /* 18 */ SyscallDesc("kern_invalid", unimplementedFunc), + /* 19 */ SyscallDesc("kern_invalid", unimplementedFunc), + /* 20 */ SyscallDesc("msg_send_trap", unimplementedFunc), + /* 21 */ SyscallDesc("msg_receive_trap", unimplementedFunc), + /* 22 */ SyscallDesc("msg_rpc_trap", unimplementedFunc), + /* 23 */ SyscallDesc("kern_invalid", unimplementedFunc), + /* 24 */ SyscallDesc("nxm_block", AlphaTru64::nxm_blockFunc), + /* 25 */ SyscallDesc("nxm_unblock", AlphaTru64::nxm_unblockFunc), + /* 26 */ SyscallDesc("kern_invalid", unimplementedFunc), + /* 27 */ SyscallDesc("kern_invalid", unimplementedFunc), + /* 28 */ SyscallDesc("kern_invalid", unimplementedFunc), + /* 29 */ SyscallDesc("nxm_thread_destroy", unimplementedFunc), + /* 30 */ SyscallDesc("lw_wire", unimplementedFunc), + /* 31 */ SyscallDesc("lw_unwire", unimplementedFunc), + /* 32 */ SyscallDesc("nxm_thread_create", AlphaTru64::nxm_thread_createFunc), + /* 33 */ SyscallDesc("nxm_task_init", AlphaTru64::nxm_task_initFunc), + /* 34 */ SyscallDesc("kern_invalid", unimplementedFunc), + /* 35 */ SyscallDesc("nxm_idle", AlphaTru64::nxm_idleFunc), + /* 36 */ SyscallDesc("nxm_wakeup_idle", unimplementedFunc), + /* 37 */ SyscallDesc("nxm_set_pthid", unimplementedFunc), + /* 38 */ SyscallDesc("nxm_thread_kill", unimplementedFunc), + /* 39 */ SyscallDesc("nxm_thread_block", AlphaTru64::nxm_thread_blockFunc), + /* 40 */ SyscallDesc("nxm_thread_wakeup", unimplementedFunc), + /* 41 */ SyscallDesc("init_process", unimplementedFunc), + /* 42 */ SyscallDesc("nxm_get_binding", unimplementedFunc), + /* 43 */ SyscallDesc("map_fd", unimplementedFunc), + /* 44 */ SyscallDesc("nxm_resched", unimplementedFunc), + /* 45 */ SyscallDesc("nxm_set_cancel", unimplementedFunc), + /* 46 */ SyscallDesc("nxm_set_binding", unimplementedFunc), + /* 47 */ SyscallDesc("stack_create", AlphaTru64::stack_createFunc), + /* 48 */ SyscallDesc("nxm_get_state", unimplementedFunc), + /* 49 */ SyscallDesc("nxm_thread_suspend", unimplementedFunc), + /* 50 */ SyscallDesc("nxm_thread_resume", unimplementedFunc), + /* 51 */ SyscallDesc("nxm_signal_check", unimplementedFunc), + /* 52 */ SyscallDesc("htg_unix_syscall", unimplementedFunc), + /* 53 */ SyscallDesc("kern_invalid", unimplementedFunc), + /* 54 */ SyscallDesc("kern_invalid", unimplementedFunc), + /* 55 */ SyscallDesc("host_self", unimplementedFunc), + /* 56 */ SyscallDesc("host_priv_self", unimplementedFunc), + /* 57 */ SyscallDesc("kern_invalid", unimplementedFunc), + /* 58 */ SyscallDesc("kern_invalid", unimplementedFunc), + /* 59 */ SyscallDesc("swtch_pri", AlphaTru64::swtch_priFunc), + /* 60 */ SyscallDesc("swtch", unimplementedFunc), + /* 61 */ SyscallDesc("thread_switch", unimplementedFunc), + /* 62 */ SyscallDesc("semop_fast", unimplementedFunc), + /* 63 */ SyscallDesc("nxm_pshared_init", unimplementedFunc), + /* 64 */ SyscallDesc("nxm_pshared_block", unimplementedFunc), + /* 65 */ SyscallDesc("nxm_pshared_unblock", unimplementedFunc), + /* 66 */ SyscallDesc("nxm_pshared_destroy", unimplementedFunc), + /* 67 */ SyscallDesc("nxm_swtch_pri", AlphaTru64::swtch_priFunc), + /* 68 */ SyscallDesc("lw_syscall", unimplementedFunc), + /* 69 */ SyscallDesc("kern_invalid", unimplementedFunc), + /* 70 */ SyscallDesc("mach_sctimes_0", unimplementedFunc), + /* 71 */ SyscallDesc("mach_sctimes_1", unimplementedFunc), + /* 72 */ SyscallDesc("mach_sctimes_2", unimplementedFunc), + /* 73 */ SyscallDesc("mach_sctimes_3", unimplementedFunc), + /* 74 */ SyscallDesc("mach_sctimes_4", unimplementedFunc), + /* 75 */ SyscallDesc("mach_sctimes_5", unimplementedFunc), + /* 76 */ SyscallDesc("mach_sctimes_6", unimplementedFunc), + /* 77 */ SyscallDesc("mach_sctimes_7", unimplementedFunc), + /* 78 */ SyscallDesc("mach_sctimes_8", unimplementedFunc), + /* 79 */ SyscallDesc("mach_sctimes_9", unimplementedFunc), + /* 80 */ SyscallDesc("mach_sctimes_10", unimplementedFunc), + /* 81 */ SyscallDesc("mach_sctimes_11", unimplementedFunc), + /* 82 */ SyscallDesc("mach_sctimes_port_alloc_dealloc", unimplementedFunc) +}; + +SyscallDesc* +AlphaTru64Process::getDesc(int callnum) +{ + if (callnum < -Num_Mach_Syscall_Descs || callnum > Num_Syscall_Descs) + return NULL; + + if (callnum < 0) + return &machSyscallDescs[-callnum]; + else + return &syscallDescs[callnum]; +} + + +AlphaTru64Process::AlphaTru64Process(const std::string &name, + ObjectFile *objFile, + System *system, + int stdin_fd, + int stdout_fd, + int stderr_fd, + std::vector<std::string> &argv, + std::vector<std::string> &envp) + : AlphaLiveProcess(name, objFile, system, stdin_fd, stdout_fd, + stderr_fd, argv, envp), + Num_Syscall_Descs(sizeof(syscallDescs) / sizeof(SyscallDesc)), + Num_Mach_Syscall_Descs(sizeof(machSyscallDescs) / sizeof(SyscallDesc)) +{ +} diff --git a/src/arch/alpha/tru64/process.hh b/src/arch/alpha/tru64/process.hh new file mode 100644 index 000000000..1cde4cac0 --- /dev/null +++ b/src/arch/alpha/tru64/process.hh @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2003-2004 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ALPHA_TRU64_PROCESS_HH__ +#define __ALPHA_TRU64_PROCESS_HH__ + +#include "arch/alpha/process.hh" + +namespace AlphaISA { +/// A process with emulated Alpha Tru64 syscalls. +class AlphaTru64Process : public AlphaLiveProcess +{ + public: + /// Constructor. + AlphaTru64Process(const std::string &name, + ObjectFile *objFile, + System *system, + int stdin_fd, int stdout_fd, int stderr_fd, + std::vector<std::string> &argv, + std::vector<std::string> &envp); + + /// Array of syscall descriptors, indexed by call number. + static SyscallDesc syscallDescs[]; + + /// Array of mach syscall descriptors, indexed by call number. + static SyscallDesc machSyscallDescs[]; + + const int Num_Syscall_Descs; + const int Num_Mach_Syscall_Descs; + + virtual SyscallDesc* getDesc(int callnum); +}; + +} // namespace AlphaISA + +#endif // __ALPHA_TRU64_PROCESS_HH__ diff --git a/src/arch/alpha/tru64/system.cc b/src/arch/alpha/tru64/system.cc new file mode 100644 index 000000000..2ad06d679 --- /dev/null +++ b/src/arch/alpha/tru64/system.cc @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "arch/alpha/tru64/system.hh" +#include "arch/isa_traits.hh" +#include "arch/vtophys.hh" +#include "base/loader/symtab.hh" +#include "base/trace.hh" +#include "cpu/base.hh" +#include "cpu/exec_context.hh" +#include "kern/tru64/tru64_events.hh" +#include "kern/system_events.hh" +#include "mem/physical.hh" +#include "mem/port.hh" +#include "sim/builder.hh" + +using namespace std; + +Tru64AlphaSystem::Tru64AlphaSystem(Tru64AlphaSystem::Params *p) + : AlphaSystem(p) +{ + Addr addr = 0; + if (kernelSymtab->findAddress("enable_async_printf", addr)) { + virtPort.write(addr, (uint32_t)0); + } + +#ifdef DEBUG + kernelPanicEvent = addKernelFuncEvent<BreakPCEvent>("panic"); + if (!kernelPanicEvent) + panic("could not find kernel symbol \'panic\'"); +#endif + + badaddrEvent = addKernelFuncEvent<BadAddrEvent>("badaddr"); + if (!badaddrEvent) + panic("could not find kernel symbol \'badaddr\'"); + + skipPowerStateEvent = + addKernelFuncEvent<SkipFuncEvent>("tl_v48_capture_power_state"); + skipScavengeBootEvent = + addKernelFuncEvent<SkipFuncEvent>("pmap_scavenge_boot"); + +#if TRACING_ON + printfEvent = addKernelFuncEvent<PrintfEvent>("printf"); + debugPrintfEvent = addKernelFuncEvent<DebugPrintfEvent>("m5printf"); + debugPrintfrEvent = addKernelFuncEvent<DebugPrintfrEvent>("m5printfr"); + dumpMbufEvent = addKernelFuncEvent<DumpMbufEvent>("m5_dump_mbuf"); +#endif +} + +Tru64AlphaSystem::~Tru64AlphaSystem() +{ +#ifdef DEBUG + delete kernelPanicEvent; +#endif + delete badaddrEvent; + delete skipPowerStateEvent; + delete skipScavengeBootEvent; +#if TRACING_ON + delete printfEvent; + delete debugPrintfEvent; + delete debugPrintfrEvent; + delete dumpMbufEvent; +#endif +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(Tru64AlphaSystem) + + Param<Tick> boot_cpu_frequency; + SimObjectParam<PhysicalMemory *> physmem; + + Param<string> kernel; + Param<string> console; + Param<string> pal; + + Param<string> boot_osflags; + Param<string> readfile; + Param<unsigned int> init_param; + + Param<uint64_t> system_type; + Param<uint64_t> system_rev; + + Param<bool> bin; + VectorParam<string> binned_fns; + +END_DECLARE_SIM_OBJECT_PARAMS(Tru64AlphaSystem) + +BEGIN_INIT_SIM_OBJECT_PARAMS(Tru64AlphaSystem) + + INIT_PARAM(boot_cpu_frequency, "frequency of the boot cpu"), + INIT_PARAM(physmem, "phsyical memory"), + INIT_PARAM(kernel, "file that contains the kernel code"), + INIT_PARAM(console, "file that contains the console code"), + INIT_PARAM(pal, "file that contains palcode"), + INIT_PARAM_DFLT(boot_osflags, "flags to pass to the kernel during boot", + "a"), + INIT_PARAM_DFLT(readfile, "file to read startup script from", ""), + INIT_PARAM_DFLT(init_param, "numerical value to pass into simulator", 0), + INIT_PARAM_DFLT(system_type, "Type of system we are emulating", 12), + INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 2<<1), + INIT_PARAM_DFLT(bin, "is this system to be binned", false), + INIT_PARAM(binned_fns, "functions to be broken down and binned") + +END_INIT_SIM_OBJECT_PARAMS(Tru64AlphaSystem) + +CREATE_SIM_OBJECT(Tru64AlphaSystem) +{ + AlphaSystem::Params *p = new AlphaSystem::Params; + p->name = getInstanceName(); + p->boot_cpu_frequency = boot_cpu_frequency; + p->physmem = physmem; + p->kernel_path = kernel; + p->console_path = console; + p->palcode = pal; + p->boot_osflags = boot_osflags; + p->init_param = init_param; + p->readfile = readfile; + p->system_type = system_type; + p->system_rev = system_rev; + p->bin = bin; + p->binned_fns = binned_fns; + p->bin_int = false; + + return new Tru64AlphaSystem(p); +} + +REGISTER_SIM_OBJECT("Tru64AlphaSystem", Tru64AlphaSystem) diff --git a/arch/alpha/tru64/system.hh b/src/arch/alpha/tru64/system.hh index 0e0cc1bc8..0e0cc1bc8 100644 --- a/arch/alpha/tru64/system.hh +++ b/src/arch/alpha/tru64/system.hh diff --git a/src/arch/alpha/tru64/tru64.cc b/src/arch/alpha/tru64/tru64.cc new file mode 100644 index 000000000..4a3e653c1 --- /dev/null +++ b/src/arch/alpha/tru64/tru64.cc @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "arch/alpha/tru64/tru64.hh" + +// open(2) flags translation table +OpenFlagTransTable AlphaTru64::openFlagTable[] = { +#ifdef _MSC_VER + { AlphaTru64::TGT_O_RDONLY, _O_RDONLY }, + { AlphaTru64::TGT_O_WRONLY, _O_WRONLY }, + { AlphaTru64::TGT_O_RDWR, _O_RDWR }, + { AlphaTru64::TGT_O_APPEND, _O_APPEND }, + { AlphaTru64::TGT_O_CREAT, _O_CREAT }, + { AlphaTru64::TGT_O_TRUNC, _O_TRUNC }, + { AlphaTru64::TGT_O_EXCL, _O_EXCL }, +#ifdef _O_NONBLOCK + { AlphaTru64::TGT_O_NONBLOCK, _O_NONBLOCK }, +#endif +#ifdef _O_NOCTTY + { AlphaTru64::TGT_O_NOCTTY, _O_NOCTTY }, +#endif +#ifdef _O_SYNC + { AlphaTru64::TGT_O_SYNC, _O_SYNC }, +#endif +#else /* !_MSC_VER */ + { AlphaTru64::TGT_O_RDONLY, O_RDONLY }, + { AlphaTru64::TGT_O_WRONLY, O_WRONLY }, + { AlphaTru64::TGT_O_RDWR, O_RDWR }, + { AlphaTru64::TGT_O_APPEND, O_APPEND }, + { AlphaTru64::TGT_O_CREAT, O_CREAT }, + { AlphaTru64::TGT_O_TRUNC, O_TRUNC }, + { AlphaTru64::TGT_O_EXCL, O_EXCL }, + { AlphaTru64::TGT_O_NONBLOCK, O_NONBLOCK }, + { AlphaTru64::TGT_O_NOCTTY, O_NOCTTY }, +#ifdef O_SYNC + { AlphaTru64::TGT_O_SYNC, O_SYNC }, +#endif +#endif /* _MSC_VER */ +}; + +const int AlphaTru64::NUM_OPEN_FLAGS = + (sizeof(AlphaTru64::openFlagTable)/sizeof(AlphaTru64::openFlagTable[0])); + + + diff --git a/src/arch/alpha/tru64/tru64.hh b/src/arch/alpha/tru64/tru64.hh new file mode 100644 index 000000000..19343ba23 --- /dev/null +++ b/src/arch/alpha/tru64/tru64.hh @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ALPHA_ALPHA_TRU64_HH +#define __ALPHA_ALPHA_TRU64_HH + +#include "kern/tru64/tru64.hh" + +class AlphaTru64 : public Tru64 +{ + + public: + /// This table maps the target open() flags to the corresponding + /// host open() flags. + static OpenFlagTransTable openFlagTable[]; + + /// Number of entries in openFlagTable[]. + static const int NUM_OPEN_FLAGS; + + //@{ + /// open(2) flag values. + static const int TGT_O_RDONLY = 00000000; //!< O_RDONLY + static const int TGT_O_WRONLY = 00000001; //!< O_WRONLY + static const int TGT_O_RDWR = 00000002; //!< O_RDWR + static const int TGT_O_NONBLOCK = 00000004; //!< O_NONBLOCK + static const int TGT_O_APPEND = 00000010; //!< O_APPEND + static const int TGT_O_CREAT = 00001000; //!< O_CREAT + static const int TGT_O_TRUNC = 00002000; //!< O_TRUNC + static const int TGT_O_EXCL = 00004000; //!< O_EXCL + static const int TGT_O_NOCTTY = 00010000; //!< O_NOCTTY + static const int TGT_O_SYNC = 00040000; //!< O_SYNC + static const int TGT_O_DRD = 00100000; //!< O_DRD + static const int TGT_O_DIRECTIO = 00200000; //!< O_DIRECTIO + static const int TGT_O_CACHE = 00400000; //!< O_CACHE + static const int TGT_O_DSYNC = 02000000; //!< O_DSYNC + static const int TGT_O_RSYNC = 04000000; //!< O_RSYNC + //@} + + /// For mmap(). + static const unsigned TGT_MAP_ANONYMOUS = 0x10; + + //@{ + /// For getsysinfo(). + static const unsigned GSI_PLATFORM_NAME = 103; //!< platform name as string + static const unsigned GSI_CPU_INFO = 59; //!< CPU information + static const unsigned GSI_PROC_TYPE = 60; //!< get proc_type + static const unsigned GSI_MAX_CPU = 30; //!< max # cpu's on this machine + static const unsigned GSI_CPUS_IN_BOX = 55; //!< number of CPUs in system + static const unsigned GSI_PHYSMEM = 19; //!< Physical memory in KB + static const unsigned GSI_CLK_TCK = 42; //!< clock freq in Hz + //@} + + //@{ + /// For getrusage(). + static const int TGT_RUSAGE_THREAD = 1; + static const int TGT_RUSAGE_SELF = 0; + static const int TGT_RUSAGE_CHILDREN = -1; + //@} + + //@{ + /// For setsysinfo(). + static const unsigned SSI_IEEE_FP_CONTROL = 14; //!< ieee_set_fp_control() + //@} + + //@{ + /// ioctl() command codes. + static const unsigned TIOCGETP = 0x40067408; + static const unsigned TIOCSETP = 0x80067409; + static const unsigned TIOCSETN = 0x8006740a; + static const unsigned TIOCSETC = 0x80067411; + static const unsigned TIOCGETC = 0x40067412; + static const unsigned FIONREAD = 0x4004667f; + static const unsigned TIOCISATTY = 0x2000745e; + static const unsigned TIOCGETS = 0x402c7413; + static const unsigned TIOCGETA = 0x40127417; + //@} + + //@{ + /// For table(). + static const int TBL_SYSINFO = 12; + //@} + + /// Resource enumeration for getrlimit(). + enum rlimit_resources { + TGT_RLIMIT_CPU = 0, + TGT_RLIMIT_FSIZE = 1, + TGT_RLIMIT_DATA = 2, + TGT_RLIMIT_STACK = 3, + TGT_RLIMIT_CORE = 4, + TGT_RLIMIT_RSS = 5, + TGT_RLIMIT_NOFILE = 6, + TGT_RLIMIT_AS = 7, + TGT_RLIMIT_VMEM = 7, + TGT_RLIMIT_NPROC = 8, + TGT_RLIMIT_MEMLOCK = 9, + TGT_RLIMIT_LOCKS = 10 + }; +}; + + + +#endif diff --git a/src/arch/alpha/types.hh b/src/arch/alpha/types.hh new file mode 100644 index 000000000..d4cb482d8 --- /dev/null +++ b/src/arch/alpha/types.hh @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ARCH_ALPHA_TYPES_HH__ +#define __ARCH_ALPHA_TYPES_HH__ + +#include "sim/host.hh" + +namespace AlphaISA +{ + + typedef uint32_t MachInst; + typedef uint64_t ExtMachInst; + typedef uint8_t RegIndex; + + typedef uint64_t IntReg; + + // floating point register file entry type + typedef double FloatReg; + typedef uint64_t FloatRegBits; + + // control register file contents + typedef uint64_t MiscReg; + + typedef union { + IntReg intreg; + FloatReg fpreg; + MiscReg ctrlreg; + } AnyReg; + + enum annotes { + ANNOTE_NONE = 0, + // An impossible number for instruction annotations + ITOUCH_ANNOTE = 0xffffffff, + }; + +} // namespace AlphaISA + +#endif diff --git a/src/arch/alpha/utility.hh b/src/arch/alpha/utility.hh new file mode 100644 index 000000000..6cc916307 --- /dev/null +++ b/src/arch/alpha/utility.hh @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ARCH_ALPHA_UTILITY_HH__ +#define __ARCH_ALPHA_UTILITY_HH__ + +#include "config/full_system.hh" +#include "arch/alpha/types.hh" +#include "arch/alpha/constants.hh" +#include "arch/alpha/regfile.hh" +#include "base/misc.hh" + +namespace AlphaISA +{ + + static inline ExtMachInst + makeExtMI(MachInst inst, const uint64_t &pc) { +#if FULL_SYSTEM + ExtMachInst ext_inst = inst; + if (pc && 0x1) + return ext_inst|=(static_cast<ExtMachInst>(pc & 0x1) << 32); + else + return ext_inst; +#else + return ExtMachInst(inst); +#endif + } + + inline bool isCallerSaveIntegerRegister(unsigned int reg) { + panic("register classification not implemented"); + return (reg >= 1 && reg <= 8 || reg >= 22 && reg <= 25 || reg == 27); + } + + inline bool isCalleeSaveIntegerRegister(unsigned int reg) { + panic("register classification not implemented"); + return (reg >= 9 && reg <= 15); + } + + inline bool isCallerSaveFloatRegister(unsigned int reg) { + panic("register classification not implemented"); + return false; + } + + inline bool isCalleeSaveFloatRegister(unsigned int reg) { + panic("register classification not implemented"); + return false; + } + + inline Addr alignAddress(const Addr &addr, + unsigned int nbytes) { + return (addr & ~(nbytes - 1)); + } + + // Instruction address compression hooks + inline Addr realPCToFetchPC(const Addr &addr) { + return addr; + } + + inline Addr fetchPCToRealPC(const Addr &addr) { + return addr; + } + + // the size of "fetched" instructions (not necessarily the size + // of real instructions for PISA) + inline size_t fetchInstSize() { + return sizeof(MachInst); + } + + inline MachInst makeRegisterCopy(int dest, int src) { + panic("makeRegisterCopy not implemented"); + return 0; + } + + // Machine operations + + void saveMachineReg(AnyReg &savereg, const RegFile ®_file, + int regnum); + + void restoreMachineReg(RegFile ®s, const AnyReg ®, + int regnum); + + /** + * Function to insure ISA semantics about 0 registers. + * @param xc The execution context. + */ + template <class XC> + void zeroRegisters(XC *xc); + +#if FULL_SYSTEM + // Alpha IPR register accessors + inline bool PcPAL(Addr addr) { return addr & 0x1; } + + //////////////////////////////////////////////////////////////////////// + // + // Translation stuff + // + + inline Addr PteAddr(Addr a) { return (a & PteMask) << PteShift; } + + // User Virtual + inline bool IsUSeg(Addr a) { return USegBase <= a && a <= USegEnd; } + + // Kernel Direct Mapped + inline bool IsK0Seg(Addr a) { return K0SegBase <= a && a <= K0SegEnd; } + inline Addr K0Seg2Phys(Addr addr) { return addr & ~K0SegBase; } + + // Kernel Virtual + inline bool IsK1Seg(Addr a) { return K1SegBase <= a && a <= K1SegEnd; } + + inline Addr + TruncPage(Addr addr) + { return addr & ~(PageBytes - 1); } + + inline Addr + RoundPage(Addr addr) + { return (addr + PageBytes - 1) & ~(PageBytes - 1); } + + void initCPU(ExecContext *xc, int cpuId); + void initIPRs(ExecContext *xc, int cpuId); + + /** + * Function to check for and process any interrupts. + * @param xc The execution context. + */ + template <class XC> + void processInterrupts(XC *xc); +#endif + +} // namespace AlphaISA + +#endif diff --git a/src/arch/alpha/vtophys.cc b/src/arch/alpha/vtophys.cc new file mode 100644 index 000000000..41e9b80a3 --- /dev/null +++ b/src/arch/alpha/vtophys.cc @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <string> + +#include "arch/alpha/ev5.hh" +#include "arch/alpha/vtophys.hh" +#include "base/chunk_generator.hh" +#include "base/trace.hh" +#include "cpu/exec_context.hh" +#include "mem/vport.hh" + +using namespace std; +using namespace AlphaISA; + +AlphaISA::PageTableEntry +AlphaISA::kernel_pte_lookup(FunctionalPort *mem, Addr ptbr, AlphaISA::VAddr vaddr) +{ + Addr level1_pte = ptbr + vaddr.level1(); + AlphaISA::PageTableEntry level1 = mem->read<uint64_t>(level1_pte); + if (!level1.valid()) { + DPRINTF(VtoPhys, "level 1 PTE not valid, va = %#\n", vaddr); + return 0; + } + + Addr level2_pte = level1.paddr() + vaddr.level2(); + AlphaISA::PageTableEntry level2 = mem->read<uint64_t>(level2_pte); + if (!level2.valid()) { + DPRINTF(VtoPhys, "level 2 PTE not valid, va = %#x\n", vaddr); + return 0; + } + + Addr level3_pte = level2.paddr() + vaddr.level3(); + AlphaISA::PageTableEntry level3 = mem->read<uint64_t>(level3_pte); + if (!level3.valid()) { + DPRINTF(VtoPhys, "level 3 PTE not valid, va = %#x\n", vaddr); + return 0; + } + return level3; +} + +Addr +AlphaISA::vtophys(Addr vaddr) +{ + Addr paddr = 0; + if (AlphaISA::IsUSeg(vaddr)) + DPRINTF(VtoPhys, "vtophys: invalid vaddr %#x", vaddr); + else if (AlphaISA::IsK0Seg(vaddr)) + paddr = AlphaISA::K0Seg2Phys(vaddr); + else + panic("vtophys: ptbr is not set on virtual lookup"); + + DPRINTF(VtoPhys, "vtophys(%#x) -> %#x\n", vaddr, paddr); + + return paddr; +} + +Addr +AlphaISA::vtophys(ExecContext *xc, Addr addr) +{ + AlphaISA::VAddr vaddr = addr; + Addr ptbr = xc->readMiscReg(AlphaISA::IPR_PALtemp20); + Addr paddr = 0; + //@todo Andrew couldn't remember why he commented some of this code + //so I put it back in. Perhaps something to do with gdb debugging? + if (AlphaISA::PcPAL(vaddr) && (vaddr < EV5::PalMax)) { + paddr = vaddr & ~ULL(1); + } else { + if (AlphaISA::IsK0Seg(vaddr)) { + paddr = AlphaISA::K0Seg2Phys(vaddr); + } else if (!ptbr) { + paddr = vaddr; + } else { + AlphaISA::PageTableEntry pte = + kernel_pte_lookup(xc->getPhysPort(), ptbr, vaddr); + if (pte.valid()) + paddr = pte.paddr() | vaddr.offset(); + } + } + + + DPRINTF(VtoPhys, "vtophys(%#x) -> %#x\n", vaddr, paddr); + + return paddr; +} + + +void +AlphaISA::CopyOut(ExecContext *xc, void *dest, Addr src, size_t cplen) +{ + uint8_t *dst = (uint8_t *)dest; + VirtualPort *vp = xc->getVirtPort(xc); + + vp->readBlob(src, dst, cplen); + + xc->delVirtPort(vp); + +} + +void +AlphaISA::CopyIn(ExecContext *xc, Addr dest, void *source, size_t cplen) +{ + uint8_t *src = (uint8_t *)source; + VirtualPort *vp = xc->getVirtPort(xc); + + vp->writeBlob(dest, src, cplen); + + xc->delVirtPort(vp); +} + +void +AlphaISA::CopyStringOut(ExecContext *xc, char *dst, Addr vaddr, size_t maxlen) +{ + int len = 0; + VirtualPort *vp = xc->getVirtPort(xc); + + do { + vp->readBlob(vaddr++, (uint8_t*)dst++, 1); + len++; + } while (len < maxlen && dst[len] != 0 ); + + xc->delVirtPort(vp); + dst[len] = 0; +} + +void +AlphaISA::CopyStringIn(ExecContext *xc, char *src, Addr vaddr) +{ + VirtualPort *vp = xc->getVirtPort(xc); + for (ChunkGenerator gen(vaddr, strlen(src), AlphaISA::PageBytes); !gen.done(); + gen.next()) + { + vp->writeBlob(gen.addr(), (uint8_t*)src, gen.size()); + src += gen.size(); + } + xc->delVirtPort(vp); +} diff --git a/src/arch/alpha/vtophys.hh b/src/arch/alpha/vtophys.hh new file mode 100644 index 000000000..7ab14bc5b --- /dev/null +++ b/src/arch/alpha/vtophys.hh @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ARCH_ALPHA_VTOPHYS_H__ +#define __ARCH_ALPHA_VTOPHYS_H__ + +#include "arch/alpha/isa_traits.hh" + +class ExecContext; +class FunctionalPort; + +namespace AlphaISA { + +PageTableEntry +kernel_pte_lookup(FunctionalPort *mem, Addr ptbr, AlphaISA::VAddr vaddr); + +Addr vtophys(Addr vaddr); +Addr vtophys(ExecContext *xc, Addr vaddr); + +void CopyOut(ExecContext *xc, void *dst, Addr src, size_t len); +void CopyIn(ExecContext *xc, Addr dst, void *src, size_t len); +void CopyStringOut(ExecContext *xc, char *dst, Addr vaddr, size_t maxlen); +void CopyStringIn(ExecContext *xc, char *src, Addr vaddr); + +}; +#endif // __ARCH_ALPHA_VTOPHYS_H__ + diff --git a/src/arch/isa_parser.py b/src/arch/isa_parser.py new file mode 100755 index 000000000..c0758da50 --- /dev/null +++ b/src/arch/isa_parser.py @@ -0,0 +1,1810 @@ +# Copyright (c) 2003-2005 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +import os +import sys +import re +import string +import traceback +# get type names +from types import * + +# Prepend the directory where the PLY lex & yacc modules are found +# to the search path. Assumes we're compiling in a subdirectory +# of 'build' in the current tree. +sys.path[0:0] = [os.environ['M5_PLY']] + +import lex +import yacc + +##################################################################### +# +# Lexer +# +# The PLY lexer module takes two things as input: +# - A list of token names (the string list 'tokens') +# - A regular expression describing a match for each token. The +# regexp for token FOO can be provided in two ways: +# - as a string variable named t_FOO +# - as the doc string for a function named t_FOO. In this case, +# the function is also executed, allowing an action to be +# associated with each token match. +# +##################################################################### + +# Reserved words. These are listed separately as they are matched +# using the same regexp as generic IDs, but distinguished in the +# t_ID() function. The PLY documentation suggests this approach. +reserved = ( + 'BITFIELD', 'DECODE', 'DECODER', 'DEFAULT', 'DEF', 'EXEC', 'FORMAT', + 'HEADER', 'LET', 'NAMESPACE', 'OPERAND_TYPES', 'OPERANDS', + 'OUTPUT', 'SIGNED', 'TEMPLATE' + ) + +# List of tokens. The lex module requires this. +tokens = reserved + ( + # identifier + 'ID', + + # integer literal + 'INTLIT', + + # string literal + 'STRLIT', + + # code literal + 'CODELIT', + + # ( ) [ ] { } < > , ; : :: * + 'LPAREN', 'RPAREN', + 'LBRACKET', 'RBRACKET', + 'LBRACE', 'RBRACE', + 'LESS', 'GREATER', 'EQUALS', + 'COMMA', 'SEMI', 'COLON', 'DBLCOLON', + 'ASTERISK', + + # C preprocessor directives + 'CPPDIRECTIVE' + +# The following are matched but never returned. commented out to +# suppress PLY warning + # newfile directive +# 'NEWFILE', + + # endfile directive +# 'ENDFILE' +) + +# Regular expressions for token matching +t_LPAREN = r'\(' +t_RPAREN = r'\)' +t_LBRACKET = r'\[' +t_RBRACKET = r'\]' +t_LBRACE = r'\{' +t_RBRACE = r'\}' +t_LESS = r'\<' +t_GREATER = r'\>' +t_EQUALS = r'=' +t_COMMA = r',' +t_SEMI = r';' +t_COLON = r':' +t_DBLCOLON = r'::' +t_ASTERISK = r'\*' + +# Identifiers and reserved words +reserved_map = { } +for r in reserved: + reserved_map[r.lower()] = r + +def t_ID(t): + r'[A-Za-z_]\w*' + t.type = reserved_map.get(t.value,'ID') + return t + +# Integer literal +def t_INTLIT(t): + r'(0x[\da-fA-F]+)|\d+' + try: + t.value = int(t.value,0) + except ValueError: + error(t.lineno, 'Integer value "%s" too large' % t.value) + t.value = 0 + return t + +# String literal. Note that these use only single quotes, and +# can span multiple lines. +def t_STRLIT(t): + r"(?m)'([^'])+'" + # strip off quotes + t.value = t.value[1:-1] + t.lineno += t.value.count('\n') + return t + + +# "Code literal"... like a string literal, but delimiters are +# '{{' and '}}' so they get formatted nicely under emacs c-mode +def t_CODELIT(t): + r"(?m)\{\{([^\}]|}(?!\}))+\}\}" + # strip off {{ & }} + t.value = t.value[2:-2] + t.lineno += t.value.count('\n') + return t + +def t_CPPDIRECTIVE(t): + r'^\#[^\#].*\n' + t.lineno += t.value.count('\n') + return t + +def t_NEWFILE(t): + r'^\#\#newfile\s+"[\w/.-]*"' + fileNameStack.push((t.value[11:-1], t.lineno)) + t.lineno = 0 + +def t_ENDFILE(t): + r'^\#\#endfile' + (old_filename, t.lineno) = fileNameStack.pop() + +# +# The functions t_NEWLINE, t_ignore, and t_error are +# special for the lex module. +# + +# Newlines +def t_NEWLINE(t): + r'\n+' + t.lineno += t.value.count('\n') + +# Comments +def t_comment(t): + r'//.*' + +# Completely ignored characters +t_ignore = ' \t\x0c' + +# Error handler +def t_error(t): + error(t.lineno, "illegal character '%s'" % t.value[0]) + t.skip(1) + +# Build the lexer +lex.lex() + +##################################################################### +# +# Parser +# +# Every function whose name starts with 'p_' defines a grammar rule. +# The rule is encoded in the function's doc string, while the +# function body provides the action taken when the rule is matched. +# The argument to each function is a list of the values of the +# rule's symbols: t[0] for the LHS, and t[1..n] for the symbols +# on the RHS. For tokens, the value is copied from the t.value +# attribute provided by the lexer. For non-terminals, the value +# is assigned by the producing rule; i.e., the job of the grammar +# rule function is to set the value for the non-terminal on the LHS +# (by assigning to t[0]). +##################################################################### + +# The LHS of the first grammar rule is used as the start symbol +# (in this case, 'specification'). Note that this rule enforces +# that there will be exactly one namespace declaration, with 0 or more +# global defs/decls before and after it. The defs & decls before +# the namespace decl will be outside the namespace; those after +# will be inside. The decoder function is always inside the namespace. +def p_specification(t): + 'specification : opt_defs_and_outputs name_decl opt_defs_and_outputs decode_block' + global_code = t[1] + isa_name = t[2] + namespace = isa_name + "Inst" + # wrap the decode block as a function definition + t[4].wrap_decode_block(''' +StaticInstPtr +%(isa_name)s::decodeInst(%(isa_name)s::ExtMachInst machInst) +{ + using namespace %(namespace)s; +''' % vars(), '}') + # both the latter output blocks and the decode block are in the namespace + namespace_code = t[3] + t[4] + # pass it all back to the caller of yacc.parse() + t[0] = (isa_name, namespace, global_code, namespace_code) + +# ISA name declaration looks like "namespace <foo>;" +def p_name_decl(t): + 'name_decl : NAMESPACE ID SEMI' + t[0] = t[2] + +# 'opt_defs_and_outputs' is a possibly empty sequence of +# def and/or output statements. +def p_opt_defs_and_outputs_0(t): + 'opt_defs_and_outputs : empty' + t[0] = GenCode() + +def p_opt_defs_and_outputs_1(t): + 'opt_defs_and_outputs : defs_and_outputs' + t[0] = t[1] + +def p_defs_and_outputs_0(t): + 'defs_and_outputs : def_or_output' + t[0] = t[1] + +def p_defs_and_outputs_1(t): + 'defs_and_outputs : defs_and_outputs def_or_output' + t[0] = t[1] + t[2] + +# The list of possible definition/output statements. +def p_def_or_output(t): + '''def_or_output : def_format + | def_bitfield + | def_template + | def_operand_types + | def_operands + | output_header + | output_decoder + | output_exec + | global_let''' + t[0] = t[1] + +# Output blocks 'output <foo> {{...}}' (C++ code blocks) are copied +# directly to the appropriate output section. + + +# Protect any non-dict-substitution '%'s in a format string +# (i.e. those not followed by '(') +def protect_non_subst_percents(s): + return re.sub(r'%(?!\()', '%%', s) + +# Massage output block by substituting in template definitions and bit +# operators. We handle '%'s embedded in the string that don't +# indicate template substitutions (or CPU-specific symbols, which get +# handled in GenCode) by doubling them first so that the format +# operation will reduce them back to single '%'s. +def process_output(s): + s = protect_non_subst_percents(s) + # protects cpu-specific symbols too + s = protect_cpu_symbols(s) + return substBitOps(s % templateMap) + +def p_output_header(t): + 'output_header : OUTPUT HEADER CODELIT SEMI' + t[0] = GenCode(header_output = process_output(t[3])) + +def p_output_decoder(t): + 'output_decoder : OUTPUT DECODER CODELIT SEMI' + t[0] = GenCode(decoder_output = process_output(t[3])) + +def p_output_exec(t): + 'output_exec : OUTPUT EXEC CODELIT SEMI' + t[0] = GenCode(exec_output = process_output(t[3])) + +# global let blocks 'let {{...}}' (Python code blocks) are executed +# directly when seen. Note that these execute in a special variable +# context 'exportContext' to prevent the code from polluting this +# script's namespace. +def p_global_let(t): + 'global_let : LET CODELIT SEMI' + updateExportContext() + try: + exec fixPythonIndentation(t[2]) in exportContext + except Exception, exc: + error(t.lineno(1), + 'error: %s in global let block "%s".' % (exc, t[2])) + t[0] = GenCode() # contributes nothing to the output C++ file + +# Define the mapping from operand type extensions to C++ types and bit +# widths (stored in operandTypeMap). +def p_def_operand_types(t): + 'def_operand_types : DEF OPERAND_TYPES CODELIT SEMI' + try: + userDict = eval('{' + t[3] + '}') + except Exception, exc: + error(t.lineno(1), + 'error: %s in def operand_types block "%s".' % (exc, t[3])) + buildOperandTypeMap(userDict, t.lineno(1)) + t[0] = GenCode() # contributes nothing to the output C++ file + +# Define the mapping from operand names to operand classes and other +# traits. Stored in operandNameMap. +def p_def_operands(t): + 'def_operands : DEF OPERANDS CODELIT SEMI' + if not globals().has_key('operandTypeMap'): + error(t.lineno(1), + 'error: operand types must be defined before operands') + try: + userDict = eval('{' + t[3] + '}') + except Exception, exc: + error(t.lineno(1), + 'error: %s in def operands block "%s".' % (exc, t[3])) + buildOperandNameMap(userDict, t.lineno(1)) + t[0] = GenCode() # contributes nothing to the output C++ file + +# A bitfield definition looks like: +# 'def [signed] bitfield <ID> [<first>:<last>]' +# This generates a preprocessor macro in the output file. +def p_def_bitfield_0(t): + 'def_bitfield : DEF opt_signed BITFIELD ID LESS INTLIT COLON INTLIT GREATER SEMI' + expr = 'bits(machInst, %2d, %2d)' % (t[6], t[8]) + if (t[2] == 'signed'): + expr = 'sext<%d>(%s)' % (t[6] - t[8] + 1, expr) + hash_define = '#undef %s\n#define %s\t%s\n' % (t[4], t[4], expr) + t[0] = GenCode(header_output = hash_define) + +# alternate form for single bit: 'def [signed] bitfield <ID> [<bit>]' +def p_def_bitfield_1(t): + 'def_bitfield : DEF opt_signed BITFIELD ID LESS INTLIT GREATER SEMI' + expr = 'bits(machInst, %2d, %2d)' % (t[6], t[6]) + if (t[2] == 'signed'): + expr = 'sext<%d>(%s)' % (1, expr) + hash_define = '#undef %s\n#define %s\t%s\n' % (t[4], t[4], expr) + t[0] = GenCode(header_output = hash_define) + +def p_opt_signed_0(t): + 'opt_signed : SIGNED' + t[0] = t[1] + +def p_opt_signed_1(t): + 'opt_signed : empty' + t[0] = '' + +# Global map variable to hold templates +templateMap = {} + +def p_def_template(t): + 'def_template : DEF TEMPLATE ID CODELIT SEMI' + templateMap[t[3]] = Template(t[4]) + t[0] = GenCode() + +# An instruction format definition looks like +# "def format <fmt>(<params>) {{...}};" +def p_def_format(t): + 'def_format : DEF FORMAT ID LPAREN param_list RPAREN CODELIT SEMI' + (id, params, code) = (t[3], t[5], t[7]) + defFormat(id, params, code, t.lineno(1)) + t[0] = GenCode() + +# The formal parameter list for an instruction format is a possibly +# empty list of comma-separated parameters. Positional (standard, +# non-keyword) parameters must come first, followed by keyword +# parameters, followed by a '*foo' parameter that gets excess +# positional arguments (as in Python). Each of these three parameter +# categories is optional. +# +# Note that we do not support the '**foo' parameter for collecting +# otherwise undefined keyword args. Otherwise the parameter list is +# (I believe) identical to what is supported in Python. +# +# The param list generates a tuple, where the first element is a list of +# the positional params and the second element is a dict containing the +# keyword params. +def p_param_list_0(t): + 'param_list : positional_param_list COMMA nonpositional_param_list' + t[0] = t[1] + t[3] + +def p_param_list_1(t): + '''param_list : positional_param_list + | nonpositional_param_list''' + t[0] = t[1] + +def p_positional_param_list_0(t): + 'positional_param_list : empty' + t[0] = [] + +def p_positional_param_list_1(t): + 'positional_param_list : ID' + t[0] = [t[1]] + +def p_positional_param_list_2(t): + 'positional_param_list : positional_param_list COMMA ID' + t[0] = t[1] + [t[3]] + +def p_nonpositional_param_list_0(t): + 'nonpositional_param_list : keyword_param_list COMMA excess_args_param' + t[0] = t[1] + t[3] + +def p_nonpositional_param_list_1(t): + '''nonpositional_param_list : keyword_param_list + | excess_args_param''' + t[0] = t[1] + +def p_keyword_param_list_0(t): + 'keyword_param_list : keyword_param' + t[0] = [t[1]] + +def p_keyword_param_list_1(t): + 'keyword_param_list : keyword_param_list COMMA keyword_param' + t[0] = t[1] + [t[3]] + +def p_keyword_param(t): + 'keyword_param : ID EQUALS expr' + t[0] = t[1] + ' = ' + t[3].__repr__() + +def p_excess_args_param(t): + 'excess_args_param : ASTERISK ID' + # Just concatenate them: '*ID'. Wrap in list to be consistent + # with positional_param_list and keyword_param_list. + t[0] = [t[1] + t[2]] + +# End of format definition-related rules. +############## + +# +# A decode block looks like: +# decode <field1> [, <field2>]* [default <inst>] { ... } +# +def p_decode_block(t): + 'decode_block : DECODE ID opt_default LBRACE decode_stmt_list RBRACE' + default_defaults = defaultStack.pop() + codeObj = t[5] + # use the "default defaults" only if there was no explicit + # default statement in decode_stmt_list + if not codeObj.has_decode_default: + codeObj += default_defaults + codeObj.wrap_decode_block('switch (%s) {\n' % t[2], '}\n') + t[0] = codeObj + +# The opt_default statement serves only to push the "default defaults" +# onto defaultStack. This value will be used by nested decode blocks, +# and used and popped off when the current decode_block is processed +# (in p_decode_block() above). +def p_opt_default_0(t): + 'opt_default : empty' + # no default specified: reuse the one currently at the top of the stack + defaultStack.push(defaultStack.top()) + # no meaningful value returned + t[0] = None + +def p_opt_default_1(t): + 'opt_default : DEFAULT inst' + # push the new default + codeObj = t[2] + codeObj.wrap_decode_block('\ndefault:\n', 'break;\n') + defaultStack.push(codeObj) + # no meaningful value returned + t[0] = None + +def p_decode_stmt_list_0(t): + 'decode_stmt_list : decode_stmt' + t[0] = t[1] + +def p_decode_stmt_list_1(t): + 'decode_stmt_list : decode_stmt decode_stmt_list' + if (t[1].has_decode_default and t[2].has_decode_default): + error(t.lineno(1), 'Two default cases in decode block') + t[0] = t[1] + t[2] + +# +# Decode statement rules +# +# There are four types of statements allowed in a decode block: +# 1. Format blocks 'format <foo> { ... }' +# 2. Nested decode blocks +# 3. Instruction definitions. +# 4. C preprocessor directives. + + +# Preprocessor directives found in a decode statement list are passed +# through to the output, replicated to all of the output code +# streams. This works well for ifdefs, so we can ifdef out both the +# declarations and the decode cases generated by an instruction +# definition. Handling them as part of the grammar makes it easy to +# keep them in the right place with respect to the code generated by +# the other statements. +def p_decode_stmt_cpp(t): + 'decode_stmt : CPPDIRECTIVE' + t[0] = GenCode(t[1], t[1], t[1], t[1]) + +# A format block 'format <foo> { ... }' sets the default instruction +# format used to handle instruction definitions inside the block. +# This format can be overridden by using an explicit format on the +# instruction definition or with a nested format block. +def p_decode_stmt_format(t): + 'decode_stmt : FORMAT push_format_id LBRACE decode_stmt_list RBRACE' + # The format will be pushed on the stack when 'push_format_id' is + # processed (see below). Once the parser has recognized the full + # production (though the right brace), we're done with the format, + # so now we can pop it. + formatStack.pop() + t[0] = t[4] + +# This rule exists so we can set the current format (& push the stack) +# when we recognize the format name part of the format block. +def p_push_format_id(t): + 'push_format_id : ID' + try: + formatStack.push(formatMap[t[1]]) + t[0] = ('', '// format %s' % t[1]) + except KeyError: + error(t.lineno(1), 'instruction format "%s" not defined.' % t[1]) + +# Nested decode block: if the value of the current field matches the +# specified constant, do a nested decode on some other field. +def p_decode_stmt_decode(t): + 'decode_stmt : case_label COLON decode_block' + label = t[1] + codeObj = t[3] + # just wrap the decoding code from the block as a case in the + # outer switch statement. + codeObj.wrap_decode_block('\n%s:\n' % label) + codeObj.has_decode_default = (label == 'default') + t[0] = codeObj + +# Instruction definition (finally!). +def p_decode_stmt_inst(t): + 'decode_stmt : case_label COLON inst SEMI' + label = t[1] + codeObj = t[3] + codeObj.wrap_decode_block('\n%s:' % label, 'break;\n') + codeObj.has_decode_default = (label == 'default') + t[0] = codeObj + +# The case label is either a list of one or more constants or 'default' +def p_case_label_0(t): + 'case_label : intlit_list' + t[0] = ': '.join(map(lambda a: 'case %#x' % a, t[1])) + +def p_case_label_1(t): + 'case_label : DEFAULT' + t[0] = 'default' + +# +# The constant list for a decode case label must be non-empty, but may have +# one or more comma-separated integer literals in it. +# +def p_intlit_list_0(t): + 'intlit_list : INTLIT' + t[0] = [t[1]] + +def p_intlit_list_1(t): + 'intlit_list : intlit_list COMMA INTLIT' + t[0] = t[1] + t[0].append(t[3]) + +# Define an instruction using the current instruction format (specified +# by an enclosing format block). +# "<mnemonic>(<args>)" +def p_inst_0(t): + 'inst : ID LPAREN arg_list RPAREN' + # Pass the ID and arg list to the current format class to deal with. + currentFormat = formatStack.top() + codeObj = currentFormat.defineInst(t[1], t[3], t.lineno(1)) + args = ','.join(map(str, t[3])) + args = re.sub('(?m)^', '//', args) + args = re.sub('^//', '', args) + comment = '\n// %s::%s(%s)\n' % (currentFormat.id, t[1], args) + codeObj.prepend_all(comment) + t[0] = codeObj + +# Define an instruction using an explicitly specified format: +# "<fmt>::<mnemonic>(<args>)" +def p_inst_1(t): + 'inst : ID DBLCOLON ID LPAREN arg_list RPAREN' + try: + format = formatMap[t[1]] + except KeyError: + error(t.lineno(1), 'instruction format "%s" not defined.' % t[1]) + codeObj = format.defineInst(t[3], t[5], t.lineno(1)) + comment = '\n// %s::%s(%s)\n' % (t[1], t[3], t[5]) + codeObj.prepend_all(comment) + t[0] = codeObj + +# The arg list generates a tuple, where the first element is a list of +# the positional args and the second element is a dict containing the +# keyword args. +def p_arg_list_0(t): + 'arg_list : positional_arg_list COMMA keyword_arg_list' + t[0] = ( t[1], t[3] ) + +def p_arg_list_1(t): + 'arg_list : positional_arg_list' + t[0] = ( t[1], {} ) + +def p_arg_list_2(t): + 'arg_list : keyword_arg_list' + t[0] = ( [], t[1] ) + +def p_positional_arg_list_0(t): + 'positional_arg_list : empty' + t[0] = [] + +def p_positional_arg_list_1(t): + 'positional_arg_list : expr' + t[0] = [t[1]] + +def p_positional_arg_list_2(t): + 'positional_arg_list : positional_arg_list COMMA expr' + t[0] = t[1] + [t[3]] + +def p_keyword_arg_list_0(t): + 'keyword_arg_list : keyword_arg' + t[0] = t[1] + +def p_keyword_arg_list_1(t): + 'keyword_arg_list : keyword_arg_list COMMA keyword_arg' + t[0] = t[1] + t[0].update(t[3]) + +def p_keyword_arg(t): + 'keyword_arg : ID EQUALS expr' + t[0] = { t[1] : t[3] } + +# +# Basic expressions. These constitute the argument values of +# "function calls" (i.e. instruction definitions in the decode block) +# and default values for formal parameters of format functions. +# +# Right now, these are either strings, integers, or (recursively) +# lists of exprs (using Python square-bracket list syntax). Note that +# bare identifiers are trated as string constants here (since there +# isn't really a variable namespace to refer to). +# +def p_expr_0(t): + '''expr : ID + | INTLIT + | STRLIT + | CODELIT''' + t[0] = t[1] + +def p_expr_1(t): + '''expr : LBRACKET list_expr RBRACKET''' + t[0] = t[2] + +def p_list_expr_0(t): + 'list_expr : expr' + t[0] = [t[1]] + +def p_list_expr_1(t): + 'list_expr : list_expr COMMA expr' + t[0] = t[1] + [t[3]] + +def p_list_expr_2(t): + 'list_expr : empty' + t[0] = [] + +# +# Empty production... use in other rules for readability. +# +def p_empty(t): + 'empty :' + pass + +# Parse error handler. Note that the argument here is the offending +# *token*, not a grammar symbol (hence the need to use t.value) +def p_error(t): + if t: + error(t.lineno, "syntax error at '%s'" % t.value) + else: + error(0, "unknown syntax error", True) + +# END OF GRAMMAR RULES +# +# Now build the parser. +yacc.yacc() + + +##################################################################### +# +# Support Classes +# +##################################################################### + +# Expand template with CPU-specific references into a dictionary with +# an entry for each CPU model name. The entry key is the model name +# and the corresponding value is the template with the CPU-specific +# refs substituted for that model. +def expand_cpu_symbols_to_dict(template): + # Protect '%'s that don't go with CPU-specific terms + t = re.sub(r'%(?!\(CPU_)', '%%', template) + result = {} + for cpu in cpu_models: + result[cpu.name] = t % cpu.strings + return result + +# *If* the template has CPU-specific references, return a single +# string containing a copy of the template for each CPU model with the +# corresponding values substituted in. If the template has no +# CPU-specific references, it is returned unmodified. +def expand_cpu_symbols_to_string(template): + if template.find('%(CPU_') != -1: + return reduce(lambda x,y: x+y, + expand_cpu_symbols_to_dict(template).values()) + else: + return template + +# Protect CPU-specific references by doubling the corresponding '%'s +# (in preparation for substituting a different set of references into +# the template). +def protect_cpu_symbols(template): + return re.sub(r'%(?=\(CPU_)', '%%', template) + +############### +# GenCode class +# +# The GenCode class encapsulates generated code destined for various +# output files. The header_output and decoder_output attributes are +# strings containing code destined for decoder.hh and decoder.cc +# respectively. The decode_block attribute contains code to be +# incorporated in the decode function itself (that will also end up in +# decoder.cc). The exec_output attribute is a dictionary with a key +# for each CPU model name; the value associated with a particular key +# is the string of code for that CPU model's exec.cc file. The +# has_decode_default attribute is used in the decode block to allow +# explicit default clauses to override default default clauses. + +class GenCode: + # Constructor. At this point we substitute out all CPU-specific + # symbols. For the exec output, these go into the per-model + # dictionary. For all other output types they get collapsed into + # a single string. + def __init__(self, + header_output = '', decoder_output = '', exec_output = '', + decode_block = '', has_decode_default = False): + self.header_output = expand_cpu_symbols_to_string(header_output) + self.decoder_output = expand_cpu_symbols_to_string(decoder_output) + if isinstance(exec_output, dict): + self.exec_output = exec_output + elif isinstance(exec_output, str): + # If the exec_output arg is a single string, we replicate + # it for each of the CPU models, substituting and + # %(CPU_foo)s params appropriately. + self.exec_output = expand_cpu_symbols_to_dict(exec_output) + self.decode_block = expand_cpu_symbols_to_string(decode_block) + self.has_decode_default = has_decode_default + + # Override '+' operator: generate a new GenCode object that + # concatenates all the individual strings in the operands. + def __add__(self, other): + exec_output = {} + for cpu in cpu_models: + n = cpu.name + exec_output[n] = self.exec_output[n] + other.exec_output[n] + return GenCode(self.header_output + other.header_output, + self.decoder_output + other.decoder_output, + exec_output, + self.decode_block + other.decode_block, + self.has_decode_default or other.has_decode_default) + + # Prepend a string (typically a comment) to all the strings. + def prepend_all(self, pre): + self.header_output = pre + self.header_output + self.decoder_output = pre + self.decoder_output + self.decode_block = pre + self.decode_block + for cpu in cpu_models: + self.exec_output[cpu.name] = pre + self.exec_output[cpu.name] + + # Wrap the decode block in a pair of strings (e.g., 'case foo:' + # and 'break;'). Used to build the big nested switch statement. + def wrap_decode_block(self, pre, post = ''): + self.decode_block = pre + indent(self.decode_block) + post + +################ +# Format object. +# +# A format object encapsulates an instruction format. It must provide +# a defineInst() method that generates the code for an instruction +# definition. + +exportContextSymbols = ('InstObjParams', 'CodeBlock', + 'makeList', 're', 'string') + +exportContext = {} + +def updateExportContext(): + exportContext.update(exportDict(*exportContextSymbols)) + exportContext.update(templateMap) + +def exportDict(*symNames): + return dict([(s, eval(s)) for s in symNames]) + + +class Format: + def __init__(self, id, params, code): + # constructor: just save away arguments + self.id = id + self.params = params + label = 'def format ' + id + self.user_code = compile(fixPythonIndentation(code), label, 'exec') + param_list = string.join(params, ", ") + f = '''def defInst(_code, _context, %s): + my_locals = vars().copy() + exec _code in _context, my_locals + return my_locals\n''' % param_list + c = compile(f, label + ' wrapper', 'exec') + exec c + self.func = defInst + + def defineInst(self, name, args, lineno): + context = {} + updateExportContext() + context.update(exportContext) + context.update({ 'name': name, 'Name': string.capitalize(name) }) + try: + vars = self.func(self.user_code, context, *args[0], **args[1]) + except Exception, exc: + error(lineno, 'error defining "%s": %s.' % (name, exc)) + for k in vars.keys(): + if k not in ('header_output', 'decoder_output', + 'exec_output', 'decode_block'): + del vars[k] + return GenCode(**vars) + +# Special null format to catch an implicit-format instruction +# definition outside of any format block. +class NoFormat: + def __init__(self): + self.defaultInst = '' + + def defineInst(self, name, args, lineno): + error(lineno, + 'instruction definition "%s" with no active format!' % name) + +# This dictionary maps format name strings to Format objects. +formatMap = {} + +# Define a new format +def defFormat(id, params, code, lineno): + # make sure we haven't already defined this one + if formatMap.get(id, None) != None: + error(lineno, 'format %s redefined.' % id) + # create new object and store in global map + formatMap[id] = Format(id, params, code) + + +############## +# Stack: a simple stack object. Used for both formats (formatStack) +# and default cases (defaultStack). Simply wraps a list to give more +# stack-like syntax and enable initialization with an argument list +# (as opposed to an argument that's a list). + +class Stack(list): + def __init__(self, *items): + list.__init__(self, items) + + def push(self, item): + self.append(item); + + def top(self): + return self[-1] + +# The global format stack. +formatStack = Stack(NoFormat()) + +# The global default case stack. +defaultStack = Stack( None ) + +# Global stack that tracks current file and line number. +# Each element is a tuple (filename, lineno) that records the +# *current* filename and the line number in the *previous* file where +# it was included. +fileNameStack = Stack() + +################### +# Utility functions + +# +# Indent every line in string 's' by two spaces +# (except preprocessor directives). +# Used to make nested code blocks look pretty. +# +def indent(s): + return re.sub(r'(?m)^(?!#)', ' ', s) + +# +# Munge a somewhat arbitrarily formatted piece of Python code +# (e.g. from a format 'let' block) into something whose indentation +# will get by the Python parser. +# +# The two keys here are that Python will give a syntax error if +# there's any whitespace at the beginning of the first line, and that +# all lines at the same lexical nesting level must have identical +# indentation. Unfortunately the way code literals work, an entire +# let block tends to have some initial indentation. Rather than +# trying to figure out what that is and strip it off, we prepend 'if +# 1:' to make the let code the nested block inside the if (and have +# the parser automatically deal with the indentation for us). +# +# We don't want to do this if (1) the code block is empty or (2) the +# first line of the block doesn't have any whitespace at the front. + +def fixPythonIndentation(s): + # get rid of blank lines first + s = re.sub(r'(?m)^\s*\n', '', s); + if (s != '' and re.match(r'[ \t]', s[0])): + s = 'if 1:\n' + s + return s + +# Error handler. Just call exit. Output formatted to work under +# Emacs compile-mode. Optional 'print_traceback' arg, if set to True, +# prints a Python stack backtrace too (can be handy when trying to +# debug the parser itself). +def error(lineno, string, print_traceback = False): + spaces = "" + for (filename, line) in fileNameStack[0:-1]: + print spaces + "In file included from " + filename + ":" + spaces += " " + # Print a Python stack backtrace if requested. + if (print_traceback): + traceback.print_exc() + if lineno != 0: + line_str = "%d:" % lineno + else: + line_str = "" + sys.exit(spaces + "%s:%s %s" % (fileNameStack[-1][0], line_str, string)) + + +##################################################################### +# +# Bitfield Operator Support +# +##################################################################### + +bitOp1ArgRE = re.compile(r'<\s*(\w+)\s*:\s*>') + +bitOpWordRE = re.compile(r'(?<![\w\.])([\w\.]+)<\s*(\w+)\s*:\s*(\w+)\s*>') +bitOpExprRE = re.compile(r'\)<\s*(\w+)\s*:\s*(\w+)\s*>') + +def substBitOps(code): + # first convert single-bit selectors to two-index form + # i.e., <n> --> <n:n> + code = bitOp1ArgRE.sub(r'<\1:\1>', code) + # simple case: selector applied to ID (name) + # i.e., foo<a:b> --> bits(foo, a, b) + code = bitOpWordRE.sub(r'bits(\1, \2, \3)', code) + # if selector is applied to expression (ending in ')'), + # we need to search backward for matching '(' + match = bitOpExprRE.search(code) + while match: + exprEnd = match.start() + here = exprEnd - 1 + nestLevel = 1 + while nestLevel > 0: + if code[here] == '(': + nestLevel -= 1 + elif code[here] == ')': + nestLevel += 1 + here -= 1 + if here < 0: + sys.exit("Didn't find '('!") + exprStart = here+1 + newExpr = r'bits(%s, %s, %s)' % (code[exprStart:exprEnd+1], + match.group(1), match.group(2)) + code = code[:exprStart] + newExpr + code[match.end():] + match = bitOpExprRE.search(code) + return code + + +#################### +# Template objects. +# +# Template objects are format strings that allow substitution from +# the attribute spaces of other objects (e.g. InstObjParams instances). + +class Template: + def __init__(self, t): + self.template = t + + def subst(self, d): + # Start with the template namespace. Make a copy since we're + # going to modify it. + myDict = templateMap.copy() + # if the argument is a dictionary, we just use it. + if isinstance(d, dict): + myDict.update(d) + # if the argument is an object, we use its attribute map. + elif hasattr(d, '__dict__'): + myDict.update(d.__dict__) + else: + raise TypeError, "Template.subst() arg must be or have dictionary" + # Protect non-Python-dict substitutions (e.g. if there's a printf + # in the templated C++ code) + template = protect_non_subst_percents(self.template) + # CPU-model-specific substitutions are handled later (in GenCode). + template = protect_cpu_symbols(template) + return template % myDict + + # Convert to string. This handles the case when a template with a + # CPU-specific term gets interpolated into another template or into + # an output block. + def __str__(self): + return expand_cpu_symbols_to_string(self.template) + +##################################################################### +# +# Code Parser +# +# The remaining code is the support for automatically extracting +# instruction characteristics from pseudocode. +# +##################################################################### + +# Force the argument to be a list. Useful for flags, where a caller +# can specify a singleton flag or a list of flags. Also usful for +# converting tuples to lists so they can be modified. +def makeList(arg): + if isinstance(arg, list): + return arg + elif isinstance(arg, tuple): + return list(arg) + elif not arg: + return [] + else: + return [ arg ] + +# Generate operandTypeMap from the user's 'def operand_types' +# statement. +def buildOperandTypeMap(userDict, lineno): + global operandTypeMap + operandTypeMap = {} + for (ext, (desc, size)) in userDict.iteritems(): + if desc == 'signed int': + ctype = 'int%d_t' % size + is_signed = 1 + elif desc == 'unsigned int': + ctype = 'uint%d_t' % size + is_signed = 0 + elif desc == 'float': + is_signed = 1 # shouldn't really matter + if size == 32: + ctype = 'float' + elif size == 64: + ctype = 'double' + if ctype == '': + error(lineno, 'Unrecognized type description "%s" in userDict') + operandTypeMap[ext] = (size, ctype, is_signed) + +# +# +# +# Base class for operand descriptors. An instance of this class (or +# actually a class derived from this one) represents a specific +# operand for a code block (e.g, "Rc.sq" as a dest). Intermediate +# derived classes encapsulates the traits of a particular operand type +# (e.g., "32-bit integer register"). +# +class Operand(object): + def __init__(self, full_name, ext, is_src, is_dest): + self.full_name = full_name + self.ext = ext + self.is_src = is_src + self.is_dest = is_dest + # The 'effective extension' (eff_ext) is either the actual + # extension, if one was explicitly provided, or the default. + if ext: + self.eff_ext = ext + else: + self.eff_ext = self.dflt_ext + + (self.size, self.ctype, self.is_signed) = operandTypeMap[self.eff_ext] + + # note that mem_acc_size is undefined for non-mem operands... + # template must be careful not to use it if it doesn't apply. + if self.isMem(): + self.mem_acc_size = self.makeAccSize() + self.mem_acc_type = self.ctype + + # Finalize additional fields (primarily code fields). This step + # is done separately since some of these fields may depend on the + # register index enumeration that hasn't been performed yet at the + # time of __init__(). + def finalize(self): + self.flags = self.getFlags() + self.constructor = self.makeConstructor() + self.op_decl = self.makeDecl() + + if self.is_src: + self.op_rd = self.makeRead() + self.op_src_decl = self.makeDecl() + else: + self.op_rd = '' + self.op_src_decl = '' + + if self.is_dest: + self.op_wb = self.makeWrite() + self.op_dest_decl = self.makeDecl() + else: + self.op_wb = '' + self.op_dest_decl = '' + + def isMem(self): + return 0 + + def isReg(self): + return 0 + + def isFloatReg(self): + return 0 + + def isIntReg(self): + return 0 + + def isControlReg(self): + return 0 + + def getFlags(self): + # note the empty slice '[:]' gives us a copy of self.flags[0] + # instead of a reference to it + my_flags = self.flags[0][:] + if self.is_src: + my_flags += self.flags[1] + if self.is_dest: + my_flags += self.flags[2] + return my_flags + + def makeDecl(self): + # Note that initializations in the declarations are solely + # to avoid 'uninitialized variable' errors from the compiler. + return self.ctype + ' ' + self.base_name + ' = 0;\n'; + +class IntRegOperand(Operand): + def isReg(self): + return 1 + + def isIntReg(self): + return 1 + + def makeConstructor(self): + c = '' + if self.is_src: + c += '\n\t_srcRegIdx[%d] = %s;' % \ + (self.src_reg_idx, self.reg_spec) + if self.is_dest: + c += '\n\t_destRegIdx[%d] = %s;' % \ + (self.dest_reg_idx, self.reg_spec) + return c + + def makeRead(self): + if (self.ctype == 'float' or self.ctype == 'double'): + error(0, 'Attempt to read integer register as FP') + if (self.size == self.dflt_size): + return '%s = xc->readIntReg(this, %d);\n' % \ + (self.base_name, self.src_reg_idx) + else: + return '%s = bits(xc->readIntReg(this, %d), %d, 0);\n' % \ + (self.base_name, self.src_reg_idx, self.size-1) + + def makeWrite(self): + if (self.ctype == 'float' or self.ctype == 'double'): + error(0, 'Attempt to write integer register as FP') + if (self.size != self.dflt_size and self.is_signed): + final_val = 'sext<%d>(%s)' % (self.size, self.base_name) + else: + final_val = self.base_name + wb = ''' + { + %s final_val = %s; + xc->setIntReg(this, %d, final_val);\n + if (traceData) { traceData->setData(final_val); } + }''' % (self.dflt_ctype, final_val, self.dest_reg_idx) + return wb + +class FloatRegOperand(Operand): + def isReg(self): + return 1 + + def isFloatReg(self): + return 1 + + def makeConstructor(self): + c = '' + if self.is_src: + c += '\n\t_srcRegIdx[%d] = %s + FP_Base_DepTag;' % \ + (self.src_reg_idx, self.reg_spec) + if self.is_dest: + c += '\n\t_destRegIdx[%d] = %s + FP_Base_DepTag;' % \ + (self.dest_reg_idx, self.reg_spec) + return c + + def makeRead(self): + bit_select = 0 + width = 0; + if (self.ctype == 'float'): + func = 'readFloatReg' + width = 32; + elif (self.ctype == 'double'): + func = 'readFloatReg' + width = 64; + else: + func = 'readFloatRegBits' + if (self.ctype == 'uint32_t'): + width = 32; + elif (self.ctype == 'uint64_t'): + width = 64; + if (self.size != self.dflt_size): + bit_select = 1 + if width: + base = 'xc->%s(this, %d, %d)' % \ + (func, self.src_reg_idx, width) + else: + base = 'xc->%s(this, %d)' % \ + (func, self.src_reg_idx) + if bit_select: + return '%s = bits(%s, %d, 0);\n' % \ + (self.base_name, base, self.size-1) + else: + return '%s = %s;\n' % (self.base_name, base) + + def makeWrite(self): + final_val = self.base_name + final_ctype = self.ctype + widthSpecifier = '' + width = 0 + if (self.ctype == 'float'): + width = 32 + func = 'setFloatReg' + elif (self.ctype == 'double'): + width = 64 + func = 'setFloatReg' + elif (self.ctype == 'uint32_t'): + func = 'setFloatRegBits' + width = 32 + elif (self.ctype == 'uint64_t'): + func = 'setFloatRegBits' + width = 64 + else: + func = 'setFloatRegBits' + final_ctype = 'uint%d_t' % self.dflt_size + if (self.size != self.dflt_size and self.is_signed): + final_val = 'sext<%d>(%s)' % (self.size, self.base_name) + if width: + widthSpecifier = ', %d' % width + wb = ''' + { + %s final_val = %s; + xc->%s(this, %d, final_val%s);\n + if (traceData) { traceData->setData(final_val); } + }''' % (final_ctype, final_val, func, self.dest_reg_idx, + widthSpecifier) + return wb + +class ControlRegOperand(Operand): + def isReg(self): + return 1 + + def isControlReg(self): + return 1 + + def makeConstructor(self): + c = '' + if self.is_src: + c += '\n\t_srcRegIdx[%d] = %s;' % \ + (self.src_reg_idx, self.reg_spec) + if self.is_dest: + c += '\n\t_destRegIdx[%d] = %s;' % \ + (self.dest_reg_idx, self.reg_spec) + return c + + def makeRead(self): + bit_select = 0 + if (self.ctype == 'float' or self.ctype == 'double'): + error(0, 'Attempt to read control register as FP') + base = 'xc->readMiscReg(%s)' % self.reg_spec + if self.size == self.dflt_size: + return '%s = %s;\n' % (self.base_name, base) + else: + return '%s = bits(%s, %d, 0);\n' % \ + (self.base_name, base, self.size-1) + + def makeWrite(self): + if (self.ctype == 'float' or self.ctype == 'double'): + error(0, 'Attempt to write control register as FP') + wb = 'xc->setMiscReg(%s, %s);\n' % (self.reg_spec, self.base_name) + wb += 'if (traceData) { traceData->setData(%s); }' % \ + self.base_name + return wb + +class MemOperand(Operand): + def isMem(self): + return 1 + + def makeConstructor(self): + return '' + + def makeDecl(self): + # Note that initializations in the declarations are solely + # to avoid 'uninitialized variable' errors from the compiler. + # Declare memory data variable. + c = '%s %s = 0;\n' % (self.ctype, self.base_name) + return c + + def makeRead(self): + return '' + + def makeWrite(self): + return '' + + # Return the memory access size *in bits*, suitable for + # forming a type via "uint%d_t". Divide by 8 if you want bytes. + def makeAccSize(self): + return self.size + + +class NPCOperand(Operand): + def makeConstructor(self): + return '' + + def makeRead(self): + return '%s = xc->readNextPC();\n' % self.base_name + + def makeWrite(self): + return 'xc->setNextPC(%s);\n' % self.base_name + +class NNPCOperand(Operand): + def makeConstructor(self): + return '' + + def makeRead(self): + return '%s = xc->readNextNPC();\n' % self.base_name + + def makeWrite(self): + return 'xc->setNextNPC(%s);\n' % self.base_name + +def buildOperandNameMap(userDict, lineno): + global operandNameMap + operandNameMap = {} + for (op_name, val) in userDict.iteritems(): + (base_cls_name, dflt_ext, reg_spec, flags, sort_pri) = val + (dflt_size, dflt_ctype, dflt_is_signed) = operandTypeMap[dflt_ext] + # Canonical flag structure is a triple of lists, where each list + # indicates the set of flags implied by this operand always, when + # used as a source, and when used as a dest, respectively. + # For simplicity this can be initialized using a variety of fairly + # obvious shortcuts; we convert these to canonical form here. + if not flags: + # no flags specified (e.g., 'None') + flags = ( [], [], [] ) + elif isinstance(flags, str): + # a single flag: assumed to be unconditional + flags = ( [ flags ], [], [] ) + elif isinstance(flags, list): + # a list of flags: also assumed to be unconditional + flags = ( flags, [], [] ) + elif isinstance(flags, tuple): + # it's a tuple: it should be a triple, + # but each item could be a single string or a list + (uncond_flags, src_flags, dest_flags) = flags + flags = (makeList(uncond_flags), + makeList(src_flags), makeList(dest_flags)) + # Accumulate attributes of new operand class in tmp_dict + tmp_dict = {} + for attr in ('dflt_ext', 'reg_spec', 'flags', 'sort_pri', + 'dflt_size', 'dflt_ctype', 'dflt_is_signed'): + tmp_dict[attr] = eval(attr) + tmp_dict['base_name'] = op_name + # New class name will be e.g. "IntReg_Ra" + cls_name = base_cls_name + '_' + op_name + # Evaluate string arg to get class object. Note that the + # actual base class for "IntReg" is "IntRegOperand", i.e. we + # have to append "Operand". + try: + base_cls = eval(base_cls_name + 'Operand') + except NameError: + error(lineno, + 'error: unknown operand base class "%s"' % base_cls_name) + # The following statement creates a new class called + # <cls_name> as a subclass of <base_cls> with the attributes + # in tmp_dict, just as if we evaluated a class declaration. + operandNameMap[op_name] = type(cls_name, (base_cls,), tmp_dict) + + # Define operand variables. + operands = userDict.keys() + + operandsREString = (r''' + (?<![\w\.]) # neg. lookbehind assertion: prevent partial matches + ((%s)(?:\.(\w+))?) # match: operand with optional '.' then suffix + (?![\w\.]) # neg. lookahead assertion: prevent partial matches + ''' + % string.join(operands, '|')) + + global operandsRE + operandsRE = re.compile(operandsREString, re.MULTILINE|re.VERBOSE) + + # Same as operandsREString, but extension is mandatory, and only two + # groups are returned (base and ext, not full name as above). + # Used for subtituting '_' for '.' to make C++ identifiers. + operandsWithExtREString = (r'(?<![\w\.])(%s)\.(\w+)(?![\w\.])' + % string.join(operands, '|')) + + global operandsWithExtRE + operandsWithExtRE = re.compile(operandsWithExtREString, re.MULTILINE) + + +class OperandList: + + # Find all the operands in the given code block. Returns an operand + # descriptor list (instance of class OperandList). + def __init__(self, code): + self.items = [] + self.bases = {} + # delete comments so we don't match on reg specifiers inside + code = commentRE.sub('', code) + # search for operands + next_pos = 0 + while 1: + match = operandsRE.search(code, next_pos) + if not match: + # no more matches: we're done + break + op = match.groups() + # regexp groups are operand full name, base, and extension + (op_full, op_base, op_ext) = op + # if the token following the operand is an assignment, this is + # a destination (LHS), else it's a source (RHS) + is_dest = (assignRE.match(code, match.end()) != None) + is_src = not is_dest + # see if we've already seen this one + op_desc = self.find_base(op_base) + if op_desc: + if op_desc.ext != op_ext: + error(0, 'Inconsistent extensions for operand %s' % \ + op_base) + op_desc.is_src = op_desc.is_src or is_src + op_desc.is_dest = op_desc.is_dest or is_dest + else: + # new operand: create new descriptor + op_desc = operandNameMap[op_base](op_full, op_ext, + is_src, is_dest) + self.append(op_desc) + # start next search after end of current match + next_pos = match.end() + self.sort() + # enumerate source & dest register operands... used in building + # constructor later + self.numSrcRegs = 0 + self.numDestRegs = 0 + self.numFPDestRegs = 0 + self.numIntDestRegs = 0 + self.memOperand = None + for op_desc in self.items: + if op_desc.isReg(): + if op_desc.is_src: + op_desc.src_reg_idx = self.numSrcRegs + self.numSrcRegs += 1 + if op_desc.is_dest: + op_desc.dest_reg_idx = self.numDestRegs + self.numDestRegs += 1 + if op_desc.isFloatReg(): + self.numFPDestRegs += 1 + elif op_desc.isIntReg(): + self.numIntDestRegs += 1 + elif op_desc.isMem(): + if self.memOperand: + error(0, "Code block has more than one memory operand.") + self.memOperand = op_desc + # now make a final pass to finalize op_desc fields that may depend + # on the register enumeration + for op_desc in self.items: + op_desc.finalize() + + def __len__(self): + return len(self.items) + + def __getitem__(self, index): + return self.items[index] + + def append(self, op_desc): + self.items.append(op_desc) + self.bases[op_desc.base_name] = op_desc + + def find_base(self, base_name): + # like self.bases[base_name], but returns None if not found + # (rather than raising exception) + return self.bases.get(base_name) + + # internal helper function for concat[Some]Attr{Strings|Lists} + def __internalConcatAttrs(self, attr_name, filter, result): + for op_desc in self.items: + if filter(op_desc): + result += getattr(op_desc, attr_name) + return result + + # return a single string that is the concatenation of the (string) + # values of the specified attribute for all operands + def concatAttrStrings(self, attr_name): + return self.__internalConcatAttrs(attr_name, lambda x: 1, '') + + # like concatAttrStrings, but only include the values for the operands + # for which the provided filter function returns true + def concatSomeAttrStrings(self, filter, attr_name): + return self.__internalConcatAttrs(attr_name, filter, '') + + # return a single list that is the concatenation of the (list) + # values of the specified attribute for all operands + def concatAttrLists(self, attr_name): + return self.__internalConcatAttrs(attr_name, lambda x: 1, []) + + # like concatAttrLists, but only include the values for the operands + # for which the provided filter function returns true + def concatSomeAttrLists(self, filter, attr_name): + return self.__internalConcatAttrs(attr_name, filter, []) + + def sort(self): + self.items.sort(lambda a, b: a.sort_pri - b.sort_pri) + +# Regular expression object to match C++ comments +# (used in findOperands()) +commentRE = re.compile(r'//.*\n') + +# Regular expression object to match assignment statements +# (used in findOperands()) +assignRE = re.compile(r'\s*=(?!=)', re.MULTILINE) + +# Munge operand names in code string to make legal C++ variable names. +# This means getting rid of the type extension if any. +# (Will match base_name attribute of Operand object.) +def substMungedOpNames(code): + return operandsWithExtRE.sub(r'\1', code) + +def joinLists(t): + return map(string.join, t) + +def makeFlagConstructor(flag_list): + if len(flag_list) == 0: + return '' + # filter out repeated flags + flag_list.sort() + i = 1 + while i < len(flag_list): + if flag_list[i] == flag_list[i-1]: + del flag_list[i] + else: + i += 1 + pre = '\n\tflags[' + post = '] = true;' + code = pre + string.join(flag_list, post + pre) + post + return code + +class CodeBlock: + def __init__(self, code): + self.orig_code = code + self.operands = OperandList(code) + self.code = substMungedOpNames(substBitOps(code)) + self.constructor = self.operands.concatAttrStrings('constructor') + self.constructor += \ + '\n\t_numSrcRegs = %d;' % self.operands.numSrcRegs + self.constructor += \ + '\n\t_numDestRegs = %d;' % self.operands.numDestRegs + self.constructor += \ + '\n\t_numFPDestRegs = %d;' % self.operands.numFPDestRegs + self.constructor += \ + '\n\t_numIntDestRegs = %d;' % self.operands.numIntDestRegs + + self.op_decl = self.operands.concatAttrStrings('op_decl') + + is_src = lambda op: op.is_src + is_dest = lambda op: op.is_dest + + self.op_src_decl = \ + self.operands.concatSomeAttrStrings(is_src, 'op_src_decl') + self.op_dest_decl = \ + self.operands.concatSomeAttrStrings(is_dest, 'op_dest_decl') + + self.op_rd = self.operands.concatAttrStrings('op_rd') + self.op_wb = self.operands.concatAttrStrings('op_wb') + + self.flags = self.operands.concatAttrLists('flags') + + if self.operands.memOperand: + self.mem_acc_size = self.operands.memOperand.mem_acc_size + self.mem_acc_type = self.operands.memOperand.mem_acc_type + + # Make a basic guess on the operand class (function unit type). + # These are good enough for most cases, and will be overridden + # later otherwise. + if 'IsStore' in self.flags: + self.op_class = 'MemWriteOp' + elif 'IsLoad' in self.flags or 'IsPrefetch' in self.flags: + self.op_class = 'MemReadOp' + elif 'IsFloating' in self.flags: + self.op_class = 'FloatAddOp' + else: + self.op_class = 'IntAluOp' + +# Assume all instruction flags are of the form 'IsFoo' +instFlagRE = re.compile(r'Is.*') + +# OpClass constants end in 'Op' except No_OpClass +opClassRE = re.compile(r'.*Op|No_OpClass') + +class InstObjParams: + def __init__(self, mnem, class_name, base_class = '', + code = None, opt_args = [], *extras): + self.mnemonic = mnem + self.class_name = class_name + self.base_class = base_class + if code: + #If the user already made a CodeBlock, pick the parts from it + if isinstance(code, CodeBlock): + origCode = code.orig_code + codeBlock = code + else: + origCode = code + codeBlock = CodeBlock(code) + compositeCode = '\n'.join([origCode] + + [pair[1] for pair in extras]) + compositeBlock = CodeBlock(compositeCode) + for code_attr in compositeBlock.__dict__.keys(): + setattr(self, code_attr, getattr(compositeBlock, code_attr)) + for (key, snippet) in extras: + setattr(self, key, CodeBlock(snippet).code) + self.code = codeBlock.code + self.orig_code = origCode + else: + self.constructor = '' + self.flags = [] + # Optional arguments are assumed to be either StaticInst flags + # or an OpClass value. To avoid having to import a complete + # list of these values to match against, we do it ad-hoc + # with regexps. + for oa in opt_args: + if instFlagRE.match(oa): + self.flags.append(oa) + elif opClassRE.match(oa): + self.op_class = oa + else: + error(0, 'InstObjParams: optional arg "%s" not recognized ' + 'as StaticInst::Flag or OpClass.' % oa) + + # add flag initialization to contructor here to include + # any flags added via opt_args + self.constructor += makeFlagConstructor(self.flags) + + # if 'IsFloating' is set, add call to the FP enable check + # function (which should be provided by isa_desc via a declare) + if 'IsFloating' in self.flags: + self.fp_enable_check = 'fault = checkFpEnableFault(xc);' + else: + self.fp_enable_check = '' + +####################### +# +# Output file template +# + +file_template = ''' +/* + * DO NOT EDIT THIS FILE!!! + * + * It was automatically generated from the ISA description in %(filename)s + */ + +%(includes)s + +%(global_output)s + +namespace %(namespace)s { + +%(namespace_output)s + +} // namespace %(namespace)s + +%(decode_function)s +''' + + +# Update the output file only if the new contents are different from +# the current contents. Minimizes the files that need to be rebuilt +# after minor changes. +def update_if_needed(file, contents): + update = False + if os.access(file, os.R_OK): + f = open(file, 'r') + old_contents = f.read() + f.close() + if contents != old_contents: + print 'Updating', file + os.remove(file) # in case it's write-protected + update = True + else: + print 'File', file, 'is unchanged' + else: + print 'Generating', file + update = True + if update: + f = open(file, 'w') + f.write(contents) + f.close() + +# This regular expression matches '##include' directives +includeRE = re.compile(r'^\s*##include\s+"(?P<filename>[\w/.-]*)".*$', + re.MULTILINE) + +# Function to replace a matched '##include' directive with the +# contents of the specified file (with nested ##includes replaced +# recursively). 'matchobj' is an re match object (from a match of +# includeRE) and 'dirname' is the directory relative to which the file +# path should be resolved. +def replace_include(matchobj, dirname): + fname = matchobj.group('filename') + full_fname = os.path.normpath(os.path.join(dirname, fname)) + contents = '##newfile "%s"\n%s\n##endfile\n' % \ + (full_fname, read_and_flatten(full_fname)) + return contents + +# Read a file and recursively flatten nested '##include' files. +def read_and_flatten(filename): + current_dir = os.path.dirname(filename) + try: + contents = open(filename).read() + except IOError: + error(0, 'Error including file "%s"' % filename) + fileNameStack.push((filename, 0)) + # Find any includes and include them + contents = includeRE.sub(lambda m: replace_include(m, current_dir), + contents) + fileNameStack.pop() + return contents + +# +# Read in and parse the ISA description. +# +def parse_isa_desc(isa_desc_file, output_dir): + # Read file and (recursively) all included files into a string. + # PLY requires that the input be in a single string so we have to + # do this up front. + isa_desc = read_and_flatten(isa_desc_file) + + # Initialize filename stack with outer file. + fileNameStack.push((isa_desc_file, 0)) + + # Parse it. + (isa_name, namespace, global_code, namespace_code) = yacc.parse(isa_desc) + + # grab the last three path components of isa_desc_file to put in + # the output + filename = '/'.join(isa_desc_file.split('/')[-3:]) + + # generate decoder.hh + includes = '#include "base/bitfield.hh" // for bitfield support' + global_output = global_code.header_output + namespace_output = namespace_code.header_output + decode_function = '' + update_if_needed(output_dir + '/decoder.hh', file_template % vars()) + + # generate decoder.cc + includes = '#include "decoder.hh"' + global_output = global_code.decoder_output + namespace_output = namespace_code.decoder_output + # namespace_output += namespace_code.decode_block + decode_function = namespace_code.decode_block + update_if_needed(output_dir + '/decoder.cc', file_template % vars()) + + # generate per-cpu exec files + for cpu in cpu_models: + includes = '#include "decoder.hh"\n' + includes += cpu.includes + global_output = global_code.exec_output[cpu.name] + namespace_output = namespace_code.exec_output[cpu.name] + decode_function = '' + update_if_needed(output_dir + '/' + cpu.filename, + file_template % vars()) + +# global list of CpuModel objects (see cpu_models.py) +cpu_models = [] + +# Called as script: get args from command line. +# Args are: <path to cpu_models.py> <isa desc file> <output dir> <cpu models> +if __name__ == '__main__': + execfile(sys.argv[1]) # read in CpuModel definitions + cpu_models = [CpuModel.dict[cpu] for cpu in sys.argv[4:]] + parse_isa_desc(sys.argv[2], sys.argv[3]) diff --git a/src/arch/isa_specific.hh b/src/arch/isa_specific.hh new file mode 100644 index 000000000..91c9ffb68 --- /dev/null +++ b/src/arch/isa_specific.hh @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ARCH_ISA_SPECIFIC_HH__ +#define __ARCH_ISA_SPECIFIC_HH__ + +//This file provides a mechanism for other source code to bring in +//files from the ISA being compiled with + +//These are constants so you can selective compile code based on the isa +//To use them, do something like +// +//#if THE_ISA == YOUR_FAVORITE_ISA +// conditional_code +//#endif +// +//Note that this is how this file sets up the other isa "hooks" + +//These macros have numerical values because otherwise the preprocessor +//would treat them as 0 in comparisons. +#define ALPHA_ISA 21064 +#define SPARC_ISA 42 +#define MIPS_ISA 34000 + +//These tell the preprocessor where to find the files of a particular +//ISA, and set the "TheISA" macro for use elsewhere. +#if THE_ISA == ALPHA_ISA + #define TheISA AlphaISA +#elif THE_ISA == SPARC_ISA + #define TheISA SparcISA +#elif THE_ISA == MIPS_ISA + #define TheISA MipsISA +#else + #error "THE_ISA not set" +#endif + +#endif diff --git a/src/arch/mips/SConscript b/src/arch/mips/SConscript new file mode 100644 index 000000000..ef1ef25d6 --- /dev/null +++ b/src/arch/mips/SConscript @@ -0,0 +1,83 @@ +# -*- mode:python -*- + +# Copyright (c) 2004-2005 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +import os +import sys +from os.path import isdir + +# Import build environment variable from SConstruct. +Import('env') + +################################################### +# +# Define needed sources. +# +################################################### + +# Base sources used by all configurations. +base_sources = Split(''' + faults.cc + isa_traits.cc + ''') + +# Full-system sources +full_system_sources = Split(''' + memory.cc + arguments.cc + mips34k.cc + osfpal.cc + stacktrace.cc + vtophys.cc + ''') + +# Syscall emulation (non-full-system) sources +syscall_emulation_sources = Split(''' + linux/linux.cc + linux/process.cc + process.cc + ''') + +# Set up complete list of sources based on configuration. +sources = base_sources + +if env['FULL_SYSTEM']: + sources += full_system_sources +else: + sources += syscall_emulation_sources + +# Convert file names to SCons File objects. This takes care of the +# path relative to the top of the directory tree. +sources = [File(s) for s in sources] + +# Add in files generated by the ISA description. +isa_desc_files = env.ISADesc('isa/main.isa') +# Only non-header files need to be compiled. +isa_desc_sources = [f for f in isa_desc_files if not f.path.endswith('.hh')] +sources += isa_desc_sources + +Return('sources') diff --git a/src/arch/mips/faults.cc b/src/arch/mips/faults.cc new file mode 100644 index 000000000..1b31dfa69 --- /dev/null +++ b/src/arch/mips/faults.cc @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "arch/mips/faults.hh" +#include "cpu/exec_context.hh" +#include "cpu/base.hh" +#include "base/trace.hh" + +namespace MipsISA +{ + +FaultName MachineCheckFault::_name = "Machine Check"; +FaultVect MachineCheckFault::_vect = 0x0401; +FaultStat MachineCheckFault::_count; + +FaultName AlignmentFault::_name = "Alignment"; +FaultVect AlignmentFault::_vect = 0x0301; +FaultStat AlignmentFault::_count; + +FaultName ResetFault::_name = "reset"; +FaultVect ResetFault::_vect = 0x0001; +FaultStat ResetFault::_count; + +FaultName ArithmeticFault::_name = "arith"; +FaultVect ArithmeticFault::_vect = 0x0501; +FaultStat ArithmeticFault::_count; + +FaultName InterruptFault::_name = "interrupt"; +FaultVect InterruptFault::_vect = 0x0101; +FaultStat InterruptFault::_count; + +FaultName NDtbMissFault::_name = "dtb_miss_single"; +FaultVect NDtbMissFault::_vect = 0x0201; +FaultStat NDtbMissFault::_count; + +FaultName PDtbMissFault::_name = "dtb_miss_double"; +FaultVect PDtbMissFault::_vect = 0x0281; +FaultStat PDtbMissFault::_count; + +FaultName DtbPageFault::_name = "dfault"; +FaultVect DtbPageFault::_vect = 0x0381; +FaultStat DtbPageFault::_count; + +FaultName DtbAcvFault::_name = "dfault"; +FaultVect DtbAcvFault::_vect = 0x0381; +FaultStat DtbAcvFault::_count; + +FaultName ItbMissFault::_name = "itbmiss"; +FaultVect ItbMissFault::_vect = 0x0181; +FaultStat ItbMissFault::_count; + +FaultName ItbPageFault::_name = "itbmiss"; +FaultVect ItbPageFault::_vect = 0x0181; +FaultStat ItbPageFault::_count; + +FaultName ItbAcvFault::_name = "iaccvio"; +FaultVect ItbAcvFault::_vect = 0x0081; +FaultStat ItbAcvFault::_count; + +FaultName UnimplementedOpcodeFault::_name = "opdec"; +FaultVect UnimplementedOpcodeFault::_vect = 0x0481; +FaultStat UnimplementedOpcodeFault::_count; + +FaultName FloatEnableFault::_name = "fen"; +FaultVect FloatEnableFault::_vect = 0x0581; +FaultStat FloatEnableFault::_count; + +FaultName PalFault::_name = "pal"; +FaultVect PalFault::_vect = 0x2001; +FaultStat PalFault::_count; + +FaultName IntegerOverflowFault::_name = "intover"; +FaultVect IntegerOverflowFault::_vect = 0x0501; +FaultStat IntegerOverflowFault::_count; + +#if FULL_SYSTEM + +void MipsFault::invoke(ExecContext * xc) +{ + FaultBase::invoke(xc); + countStat()++; + + // exception restart address + if (setRestartAddress() || !xc->inPalMode()) + xc->setMiscReg(MipsISA::IPR_EXC_ADDR, xc->readPC()); + + if (skipFaultingInstruction()) { + // traps... skip faulting instruction. + xc->setMiscReg(MipsISA::IPR_EXC_ADDR, + xc->readMiscReg(MipsISA::IPR_EXC_ADDR) + 4); + } + + xc->setPC(xc->readMiscReg(MipsISA::IPR_PAL_BASE) + vect()); + xc->setNextPC(xc->readPC() + sizeof(MachInst)); +} + +void ArithmeticFault::invoke(ExecContext * xc) +{ + FaultBase::invoke(xc); + panic("Arithmetic traps are unimplemented!"); +} + +#endif + +} // namespace MipsISA + diff --git a/src/arch/mips/faults.hh b/src/arch/mips/faults.hh new file mode 100644 index 000000000..0bdabe29e --- /dev/null +++ b/src/arch/mips/faults.hh @@ -0,0 +1,269 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MIPS_FAULTS_HH__ +#define __MIPS_FAULTS_HH__ + +#include "sim/faults.hh" + +// The design of the "name" and "vect" functions is in sim/faults.hh + +namespace MipsISA +{ + +typedef const Addr FaultVect; + +class MipsFault : public FaultBase +{ + protected: + virtual bool skipFaultingInstruction() {return false;} + virtual bool setRestartAddress() {return true;} + public: +#if FULL_SYSTEM + void invoke(ExecContext * xc); +#endif + virtual FaultVect vect() = 0; + virtual FaultStat & countStat() = 0; +}; + +class MachineCheckFault : public MipsFault +{ + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} + bool isMachineCheckFault() {return true;} +}; + +class AlignmentFault : public MipsFault +{ + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} + bool isAlignmentFault() {return true;} +}; + +static inline Fault genMachineCheckFault() +{ + return new MachineCheckFault; +} + +static inline Fault genAlignmentFault() +{ + return new AlignmentFault; +} + +class ResetFault : public MipsFault +{ + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} +}; + +class ArithmeticFault : public MipsFault +{ + protected: + bool skipFaultingInstruction() {return true;} + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} +#if FULL_SYSTEM + void invoke(ExecContext * xc); +#endif +}; + +class InterruptFault : public MipsFault +{ + protected: + bool setRestartAddress() {return false;} + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} +}; + +class NDtbMissFault : public MipsFault +{ + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} +}; + +class PDtbMissFault : public MipsFault +{ + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} +}; + +class DtbPageFault : public MipsFault +{ + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} +}; + +class DtbAcvFault : public MipsFault +{ + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} +}; + +class ItbMissFault : public MipsFault +{ + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} +}; + +class ItbPageFault : public MipsFault +{ + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} +}; + +class ItbAcvFault : public MipsFault +{ + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} +}; + +class UnimplementedOpcodeFault : public MipsFault +{ + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} +}; + +class FloatEnableFault : public MipsFault +{ + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} +}; + +class PalFault : public MipsFault +{ + protected: + bool skipFaultingInstruction() {return true;} + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} +}; + +class IntegerOverflowFault : public MipsFault +{ + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} +}; + +} // MipsISA namespace + +#endif // __FAULTS_HH__ diff --git a/src/arch/mips/isa/base.isa b/src/arch/mips/isa/base.isa new file mode 100644 index 000000000..b2a31c018 --- /dev/null +++ b/src/arch/mips/isa/base.isa @@ -0,0 +1,88 @@ +// -*- mode:c++ -*- + +//////////////////////////////////////////////////////////////////// +// +// Base class for MIPS instructions, and some support functions +// + +//Outputs to decoder.hh +output header {{ + + using namespace MipsISA; + + + /** + * Base class for all MIPS static instructions. + */ + class MipsStaticInst : public StaticInst + { + protected: + + /// Make MipsISA register dependence tags directly visible in + /// this class and derived classes. Maybe these should really + /// live here and not in the MipsISA namespace. + /*enum DependenceTags { + FP_Base_DepTag = MipsISA::FP_Base_DepTag, + Fpcr_DepTag = MipsISA::Fpcr_DepTag, + Uniq_DepTag = MipsISA::Uniq_DepTag, + IPR_Base_DepTag = MipsISA::IPR_Base_DepTag + };*/ + + // Constructor + MipsStaticInst(const char *mnem, MachInst _machInst, OpClass __opClass) + : StaticInst(mnem, _machInst, __opClass) + { + } + + /// Print a register name for disassembly given the unique + /// dependence tag number (FP or int). + void printReg(std::ostream &os, int reg) const; + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; + +}}; + +//Ouputs to decoder.cc +output decoder {{ + + void MipsStaticInst::printReg(std::ostream &os, int reg) const + { + if (reg < FP_Base_DepTag) { + ccprintf(os, "r%d", reg); + } + else { + ccprintf(os, "f%d", reg - FP_Base_DepTag); + } + } + + std::string MipsStaticInst::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + std::stringstream ss; + + ccprintf(ss, "%-10s ", mnemonic); + + if(_numDestRegs > 0){ + printReg(ss, _destRegIdx[0]); + } + + if(_numSrcRegs > 0) { + ss << ","; + printReg(ss, _srcRegIdx[0]); + } + + if(_numSrcRegs > 1) { + ss << ","; + printReg(ss, _srcRegIdx[1]); + } + + + if(mnemonic == "sll" || mnemonic == "sra"){ + ccprintf(ss,", %d",SA); + } + + return ss.str(); + } + +}}; + diff --git a/src/arch/mips/isa/bitfields.isa b/src/arch/mips/isa/bitfields.isa new file mode 100644 index 000000000..e1124a591 --- /dev/null +++ b/src/arch/mips/isa/bitfields.isa @@ -0,0 +1,71 @@ +// -*- mode:c++ -*- + +//////////////////////////////////////////////////////////////////// +// +// Bitfield definitions. +// + +def bitfield OPCODE <31:26>; +def bitfield OPCODE_HI <31:29>; +def bitfield OPCODE_LO <28:26>; + +def bitfield REGIMM <20:16>; +def bitfield REGIMM_HI <20:19>; +def bitfield REGIMM_LO <18:16>; + +def bitfield FUNCTION < 5: 0>; +def bitfield FUNCTION_HI < 5: 3>; +def bitfield FUNCTION_LO < 2: 0>; + +// Integer operate format +def bitfield RT <20:16>; +def bitfield RT_HI <20:19>; +def bitfield RT_LO <18:16>; + +def bitfield RS <25:21>; +def bitfield RS_MSB <25:25>; +def bitfield RS_HI <25:24>; +def bitfield RS_LO <23:21>; +def bitfield RS_SRL <25:22>; + +def bitfield RD <15:11>; + +def bitfield INTIMM <15: 0>; // integer immediate (literal) + +// Floating-point operate format +def bitfield FMT <25:21>; +def bitfield FR <25:21>; +def bitfield FT <20:16>; +def bitfield FS <15:11>; +def bitfield FD <10:6>; + +def bitfield ND <17:17>; +def bitfield TF <16:16>; +def bitfield MOVCI <16:16>; +def bitfield MOVCF <16:16>; +def bitfield SRL <21:21>; +def bitfield SRLV < 6: 6>; +def bitfield SA <10: 6>; + +// Floating Point Condition Codes +def bitfield CC <10:8>; +def bitfield BRANCH_CC <20:18>; + +// CP0 Register Select +def bitfield SEL < 2: 0>; + +// Interrupts +def bitfield SC < 5: 5>; + +// Branch format +def bitfield OFFSET <15: 0>; // displacement + +// Jmp format +def bitfield JMPTARG <25: 0>; +def bitfield HINT <10: 6>; + +def bitfield SYSCALLCODE <25: 6>; +def bitfield TRAPCODE <15:13>; + +// M5 instructions +def bitfield M5FUNC <7:0>; diff --git a/src/arch/mips/isa/decoder.isa b/src/arch/mips/isa/decoder.isa new file mode 100644 index 000000000..1454aba39 --- /dev/null +++ b/src/arch/mips/isa/decoder.isa @@ -0,0 +1,1688 @@ + // -*- mode:c++ -*- + +//////////////////////////////////////////////////////////////////// +// +// The actual MIPS32 ISA decoder +// ----------------------------- +// The following instructions are specified in the MIPS32 ISA +// Specification. Decoding closely follows the style specified +// in the MIPS32 ISAthe specification document starting with Table +// A-2 (document available @ www.mips.com) +// +//@todo: Distinguish "unknown/future" use insts from "reserved" +// ones +decode OPCODE_HI default Unknown::unknown() { + + // Derived From ... Table A-2 MIPS32 ISA Manual + 0x0: decode OPCODE_LO { + + 0x0: decode FUNCTION_HI { + 0x0: decode FUNCTION_LO { + 0x1: decode MOVCI { + format BasicOp { + 0: movf({{ if (getFPConditionCode(FCSR, CC) == 0) Rd = Rs}}); + 1: movt({{ if (getFPConditionCode(FCSR, CC) == 1) Rd = Rs}}); + } + } + + format BasicOp { + + //Table A-3 Note: "1. Specific encodings of the rt, rd, and sa fields + //are used to distinguish among the SLL, NOP, SSNOP and EHB functions. + 0x0: decode RS { + 0x0: decode RT { //fix Nop traditional vs. Nop converted disassembly later + 0x0: decode RD default Nop::nop(){ + 0x0: decode SA { + 0x1: ssnop({{ ; }}); //really sll r0,r0,1 + 0x3: ehb({{ ; }}); //really sll r0,r0,3 + } + } + + default: sll({{ Rd = Rt.uw << SA; }}); + } + + } + + 0x2: decode RS_SRL { + 0x0:decode SRL { + 0: srl({{ Rd = Rt.uw >> SA; }}); + + //Hardcoded assuming 32-bit ISA, probably need parameter here + 1: rotr({{ Rd = (Rt.uw << (32 - SA)) | (Rt.uw >> SA);}}); + } + } + + 0x3: decode RS { + 0x0: sra({{ + uint32_t temp = Rt >> SA; + + if ( (Rt & 0x80000000) > 0 ) { + uint32_t mask = 0x80000000; + for(int i=0; i < SA; i++) { + temp |= mask; + mask = mask >> 1; + } + } + + Rd = temp; + }}); + } + + 0x4: sllv({{ Rd = Rt.uw << Rs<4:0>; }}); + + 0x6: decode SRLV { + 0: srlv({{ Rd = Rt.uw >> Rs<4:0>; }}); + + //Hardcoded assuming 32-bit ISA, probably need parameter here + 1: rotrv({{ Rd = (Rt.uw << (32 - Rs<4:0>)) | (Rt.uw >> Rs<4:0>);}}); + } + + 0x7: srav({{ + int shift_amt = Rs<4:0>; + + uint32_t temp = Rt >> shift_amt; + + if ( (Rt & 0x80000000) > 0 ) { + uint32_t mask = 0x80000000; + for(int i=0; i < shift_amt; i++) { + temp |= mask; + mask = mask >> 1; + } + } + + Rd = temp; + }}); + } + } + + 0x1: decode FUNCTION_LO { + + //Table A-3 Note: "Specific encodings of the hint field are used + //to distinguish JR from JR.HB and JALR from JALR.HB" + format Jump { + 0x0: decode HINT { + 0:jr({{ NNPC = Rs & ~1; }},IsReturn); + + 1:jr_hb({{ NNPC = Rs & ~1; clear_exe_inst_hazards(); }},IsReturn); + } + + 0x1: decode HINT { + 0: jalr({{ Rd = NNPC; NNPC = Rs; }},IsCall,IsReturn); + + 1: jalr_hb({{ Rd = NNPC; NNPC = Rs; clear_exe_inst_hazards();}},IsCall,IsReturn); + } + } + + format BasicOp { + 0x2: movz({{ if (Rt == 0) Rd = Rs; }}); + 0x3: movn({{ if (Rt != 0) Rd = Rs; }}); + } + + format BasicOp { + 0x4: syscall({{ xc->syscall(R2); }},IsNonSpeculative); + 0x5: break({{ panic("Not implemented break yet"); }},IsNonSpeculative); + 0x7: sync({{ panic("Not implemented sync yet"); }},IsNonSpeculative); + } + } + + 0x2: decode FUNCTION_LO { + format BasicOp { + 0x0: mfhi({{ Rd = HI; }}); + 0x1: mthi({{ HI = Rs; }}); + 0x2: mflo({{ Rd = LO; }}); + 0x3: mtlo({{ LO = Rs; }}); + } + } + + 0x3: decode FUNCTION_LO { + format IntOp { + 0x0: mult({{ + int64_t temp1 = Rs.sd * Rt.sd; + HI = temp1<63:32>; + LO = temp1<31:0>; + }}); + + 0x1: multu({{ + uint64_t temp1 = Rs.ud * Rt.ud; + HI = temp1<63:32>; + LO = temp1<31:0>; + }}); + + 0x2: div({{ + HI = Rs.sd % Rt.sd; + LO = Rs.sd / Rt.sd; + }}); + + 0x3: divu({{ + HI = Rs.ud % Rt.ud; + LO = Rs.ud / Rt.ud; + }}); + } + } + + 0x4: decode HINT { + 0x0: decode FUNCTION_LO { + format IntOp { + 0x0: add({{ Rd.sw = Rs.sw + Rt.sw; /*Trap on Overflow*/}}); + 0x1: addu({{ Rd.sw = Rs.sw + Rt.sw;}}); + 0x2: sub({{ Rd.sw = Rs.sw - Rt.sw; /*Trap on Overflow*/}}); + 0x3: subu({{ Rd.sw = Rs.sw - Rt.sw;}}); + 0x4: and({{ Rd = Rs & Rt;}}); + 0x5: or({{ Rd = Rs | Rt;}}); + 0x6: xor({{ Rd = Rs ^ Rt;}}); + 0x7: nor({{ Rd = ~(Rs | Rt);}}); + } + } + } + + 0x5: decode HINT { + 0x0: decode FUNCTION_LO { + format IntOp{ + 0x2: slt({{ Rd.sw = ( Rs.sw < Rt.sw ) ? 1 : 0}}); + 0x3: sltu({{ Rd.uw = ( Rs.uw < Rt.uw ) ? 1 : 0}}); + } + } + } + + 0x6: decode FUNCTION_LO { + format Trap { + 0x0: tge({{ cond = (Rs.sw >= Rt.sw); }}); + 0x1: tgeu({{ cond = (Rs.uw >= Rt.uw); }}); + 0x2: tlt({{ cond = (Rs.sw < Rt.sw); }}); + 0x3: tltu({{ cond = (Rs.uw >= Rt.uw); }}); + 0x4: teq({{ cond = (Rs.sw == Rt.sw); }}); + 0x6: tne({{ cond = (Rs.sw != Rt.sw); }}); + } + } + } + + 0x1: decode REGIMM_HI { + 0x0: decode REGIMM_LO { + format Branch { + 0x0: bltz({{ cond = (Rs.sw < 0); }}); + 0x1: bgez({{ cond = (Rs.sw >= 0); }}); + } + + format BranchLikely { + 0x2: bltzl({{ cond = (Rs.sw < 0); }}); + 0x3: bgezl({{ cond = (Rs.sw >= 0); }}); + } + } + + 0x1: decode REGIMM_LO { + format Trap { + 0x0: tgei( {{ cond = (Rs.sw >= INTIMM); }}); + 0x1: tgeiu({{ cond = (Rs.uw >= INTIMM); }}); + 0x2: tlti( {{ cond = (Rs.sw < INTIMM); }}); + 0x3: tltiu({{ cond = (Rs.uw < INTIMM); }}); + 0x4: teqi( {{ cond = (Rs.sw == INTIMM);}}); + 0x6: tnei( {{ cond = (Rs.sw != INTIMM);}}); + } + } + + 0x2: decode REGIMM_LO { + format Branch { + 0x0: bltzal({{ cond = (Rs.sw < 0); }}, IsCall,IsReturn); + 0x1: bgezal({{ cond = (Rs.sw >= 0); }}, IsCall,IsReturn); + } + + format BranchLikely { + 0x2: bltzall({{ cond = (Rs.sw < 0); }}, IsCall, IsReturn); + 0x3: bgezall({{ cond = (Rs.sw >= 0); }}, IsCall, IsReturn); + } + } + + 0x3: decode REGIMM_LO { + format WarnUnimpl { + 0x7: synci(); + } + } + } + + format Jump { + 0x2: j({{ NNPC = (NPC & 0xF0000000) | (JMPTARG << 2);}}); + + 0x3: jal({{ NNPC = (NPC & 0xF0000000) | (JMPTARG << 2); }},IsCall,IsReturn); + } + + format Branch { + 0x4: beq({{ cond = (Rs.sw == Rt.sw); }}); + 0x5: bne({{ cond = (Rs.sw != Rt.sw); }}); + 0x6: decode RT { + 0x0: blez({{ cond = (Rs.sw <= 0); }}); + } + + 0x7: decode RT { + 0x0: bgtz({{ cond = (Rs.sw > 0); }}); + } + } + } + + 0x1: decode OPCODE_LO { + format IntOp { + 0x0: addi({{ Rt.sw = Rs.sw + imm; /*Trap If Overflow*/}}); + 0x1: addiu({{ Rt.sw = Rs.sw + imm;}}); + 0x2: slti({{ Rt.sw = ( Rs.sw < imm) ? 1 : 0 }}); + 0x3: sltiu({{ Rt.uw = ( Rs.uw < (uint32_t)sextImm ) ? 1 : 0 }}); + 0x4: andi({{ Rt.sw = Rs.sw & zextImm;}}); + 0x5: ori({{ Rt.sw = Rs.sw | zextImm;}}); + 0x6: xori({{ Rt.sw = Rs.sw ^ zextImm;}}); + + 0x7: decode RS { + 0x0: lui({{ Rt = imm << 16}}); + } + } + } + + 0x2: decode OPCODE_LO { + + //Table A-11 MIPS32 COP0 Encoding of rs Field + 0x0: decode RS_MSB { + 0x0: decode RS { + format System { + 0x0: mfc0({{ + //uint64_t reg_num = Rd.uw; + + Rt = xc->readMiscReg(RD << 5 | SEL); + }}); + + 0x4: mtc0({{ + //uint64_t reg_num = Rd.uw; + + xc->setMiscReg(RD << 5 | SEL,Rt); + }}); + + 0x8: mftr({{ + //The contents of the coprocessor 0 register specified by the + //combination of rd and sel are loaded into general register + //rt. Note that not all coprocessor 0 registers support the + //sel field. In those instances, the sel field must be zero. + + //MT Code Needed Here + + }}); + + 0xC: mttr({{ + //The contents of the coprocessor 0 register specified by the + //combination of rd and sel are loaded into general register + //rt. Note that not all coprocessor 0 registers support the + //sel field. In those instances, the sel field must be zero. + + //MT Code Needed Here + }}); + + + 0xA: rdpgpr({{ + //Accessing Previous Shadow Set Register Number + //uint64_t prev = xc->readMiscReg(SRSCtl)/*[PSS]*/; + //uint64_t reg_num = Rt.uw; + + //Rd = xc->regs.IntRegFile[prev]; + //Rd = xc->shadowIntRegFile[prev][reg_num]; + }}); + + 0xB: decode RD { + + 0x0: decode SC { + 0x0: dvpe({{ + Rt.sw = xc->readMiscReg(MVPControl); + xc->setMiscReg(MVPControl,0); + }}); + + 0x1: evpe({{ + Rt.sw = xc->readMiscReg(MVPControl); + xc->setMiscReg(MVPControl,1); + }}); + } + + 0x1: decode SC { + 0x0: dmt({{ + Rt.sw = xc->readMiscReg(VPEControl); + xc->setMiscReg(VPEControl,0); + }}); + + 0x1: emt({{ + Rt.sw = xc->readMiscReg(VPEControl); + xc->setMiscReg(VPEControl,1); + }}); + } + + 0xC: decode SC { + 0x0: di({{ + Rt.sw = xc->readMiscReg(Status); + xc->setMiscReg(Status,0); + }}); + + 0x1: ei({{ + Rt.sw = xc->readMiscReg(Status); + xc->setMiscReg(Status,1); + }}); + } + } + + 0xE: wrpgpr({{ + //Accessing Previous Shadow Set Register Number + //uint64_t prev = xc->readMiscReg(SRSCtl/*[PSS]*/); + //uint64_t reg_num = Rd.uw; + + //xc->regs.IntRegFile[prev]; + //xc->shadowIntRegFile[prev][reg_num] = Rt; + }}); + } + } + + //Table A-12 MIPS32 COP0 Encoding of Function Field When rs=CO + 0x1: decode FUNCTION { + format System { + 0x01: tlbr({{ }}); + 0x02: tlbwi({{ }}); + 0x06: tlbwr({{ }}); + 0x08: tlbp({{ }}); + } + + format WarnUnimpl { + 0x18: eret(); + 0x1F: deret(); + 0x20: wait(); + } + } + } + + //Table A-13 MIPS32 COP1 Encoding of rs Field + 0x1: decode RS_MSB { + + 0x0: decode RS_HI { + 0x0: decode RS_LO { + format FloatOp { + 0x0: mfc1 ({{ Rt.uw = Fs.uw<31:0>; }}); + 0x3: mfhc1({{ Rt.uw = Fs.ud<63:32>;}}); + 0x4: mtc1 ({{ Fs.uw = Rt.uw; }}); + 0x7: mthc1({{ + uint64_t fs_hi = Rt.uw; + uint64_t fs_lo = Fs.ud & 0x0000FFFF; + Fs.ud = fs_hi << 32 | fs_lo; + }}); + } + + format System { + 0x2: cfc1({{ + switch (FS) + { + case 0: + Rt = FIR; + break; + case 25: + Rt = 0 | (FCSR & 0xFE000000) >> 24 | (FCSR & 0x00800000) >> 23; + break; + case 26: + Rt = 0 | (FCSR & 0x0003F07C); + break; + case 28: + Rt = 0 | (FCSR & 0x00000F80) | (FCSR & 0x01000000) >> 21 | (FCSR & 0x00000003); + break; + case 31: + Rt = FCSR; + break; + default: + panic("FP Control Value (%d) Not Available. Ignoring Access to" + "Floating Control Status Register",FS); + } + }}); + + 0x6: ctc1({{ + switch (FS) + { + case 25: + FCSR = 0 | (Rt.uw<7:1> << 25) // move 31...25 + | (FCSR & 0x01000000) // bit 24 + | (FCSR & 0x004FFFFF);// bit 22...0 + break; + + case 26: + FCSR = 0 | (FCSR & 0xFFFC0000) // move 31...18 + | Rt.uw<17:12> << 12 // bit 17...12 + | (FCSR & 0x00000F80) << 7// bit 11...7 + | Rt.uw<6:2> << 2 // bit 6...2 + | (FCSR & 0x00000002); // bit 1...0 + break; + + case 28: + FCSR = 0 | (FCSR & 0xFE000000) // move 31...25 + | Rt.uw<2:2> << 24 // bit 24 + | (FCSR & 0x00FFF000) << 23// bit 23...12 + | Rt.uw<11:7> << 7 // bit 24 + | (FCSR & 0x000007E) + | Rt.uw<1:0>;// bit 22...0 + break; + + case 31: + FCSR = Rt.uw; + break; + + default: + panic("FP Control Value (%d) Not Available. Ignoring Access to" + "Floating Control Status Register", FS); + } + }}); + } + } + + 0x1: decode ND { + 0x0: decode TF { + format Branch { + 0x0: bc1f({{ cond = (getFPConditionCode(FCSR,CC) == 0); }}); + 0x1: bc1t({{ cond = (getFPConditionCode(FCSR,CC) == 1); }}); + } + } + + 0x1: decode TF { + format BranchLikely { + 0x0: bc1fl({{ cond = (getFPConditionCode(FCSR,CC) == 0); }}); + 0x1: bc1tl({{ cond = (getFPConditionCode(FCSR,CC) == 1); }}); + } + } + } + } + + 0x1: decode RS_HI { + 0x2: decode RS_LO { + + //Table A-14 MIPS32 COP1 Encoding of Function Field When rs=S + //(( single-word )) + 0x0: decode FUNCTION_HI { + 0x0: decode FUNCTION_LO { + format FloatOp { + 0x0: add_s({{ Fd.sf = Fs.sf + Ft.sf;}}); + 0x1: sub_s({{ Fd.sf = Fs.sf - Ft.sf;}}); + 0x2: mul_s({{ Fd.sf = Fs.sf * Ft.sf;}}); + 0x3: div_s({{ Fd.sf = Fs.sf / Ft.sf;}}); + 0x4: sqrt_s({{ Fd.sf = sqrt(Fs.sf);}}); + 0x5: abs_s({{ Fd.sf = fabs(Fs.sf);}}); + 0x6: mov_s({{ Fd.sf = Fs.sf;}}); + 0x7: neg_s({{ Fd.sf = -1 * Fs.sf;}}); + } + } + + 0x1: decode FUNCTION_LO { + format Float64Op { + 0x0: round_l_s({{ + Fd.ud = fpConvert(roundFP(Fs.sf,0), SINGLE_TO_LONG); + }}); + + 0x1: trunc_l_s({{ + Fd.ud = fpConvert(truncFP(Fs.sf), SINGLE_TO_LONG); + }}); + + 0x2: ceil_l_s({{ + Fd.ud = fpConvert(ceil(Fs.sf), SINGLE_TO_LONG); + }}); + + 0x3: floor_l_s({{ + Fd.ud = fpConvert(floor(Fs.sf), SINGLE_TO_LONG); + }}); + } + + format FloatOp { + 0x4: round_w_s({{ + Fd.uw = fpConvert(roundFP(Fs.sf,0), SINGLE_TO_WORD); + }}); + + 0x5: trunc_w_s({{ + Fd.uw = fpConvert(truncFP(Fs.sf), SINGLE_TO_WORD); + }}); + + 0x6: ceil_w_s({{ + Fd.uw = fpConvert(ceil(Fs.sf), SINGLE_TO_WORD); + }}); + + 0x7: floor_w_s({{ + Fd.uw = fpConvert(floor(Fs.sf), SINGLE_TO_WORD); + }}); + } + } + + 0x2: decode FUNCTION_LO { + 0x1: decode MOVCF { + format FloatOp { + 0x0: movf_s({{if (getFPConditionCode(FCSR,CC) == 0) Fd = Fs;}}); + 0x1: movt_s({{if (getFPConditionCode(FCSR,CC) == 1) Fd = Fs;}}); + } + } + + format FloatOp { + 0x2: movz_s({{ if (Rt == 0) Fd = Fs; }}); + 0x3: movn_s({{ if (Rt != 0) Fd = Fs; }}); + 0x5: recip_s({{ Fd = 1 / Fs; }}); + 0x6: rsqrt_s({{ Fd = 1 / sqrt(Fs);}}); + } + } + + 0x4: decode FUNCTION_LO { + + format FloatConvertOp { + 0x1: cvt_d_s({{ + Fd.ud = fpConvert(Fs.sf, SINGLE_TO_DOUBLE); + }}); + + 0x4: cvt_w_s({{ + Fd.uw = fpConvert(Fs.sf, SINGLE_TO_WORD); + }}); + } + + format FloatConvertOp { + 0x5: cvt_l_s({{ + Fd.ud = fpConvert(Fs.sf, SINGLE_TO_LONG); + }}); + + 0x6: cvt_ps_st({{ + Fd.ud = (uint64_t)Fs.uw << 32 | (uint64_t)Ft.uw; + }}); + } + } + + 0x6: decode FUNCTION_LO { + format FloatCompareOp { + 0x0: c_f_s({{ cond = 0; }}); + + 0x1: c_un_s({{ + if (isnan(Fs.sf) || isnan(Ft.sf)) + cond = 1; + else + cond = 0; + }}); + + 0x2: c_eq_s({{ + if (isnan(Fs.sf) || isnan(Ft.sf)) + cond = 0; + else + cond = (Fs.sf == Ft.sf); + }}); + + 0x3: c_ueq_s({{ + if (isnan(Fs.sf) || isnan(Ft.sf)) + cond = 1; + else + cond = (Fs.sf == Ft.sf); + }}); + + 0x4: c_olt_s({{ + if (isnan(Fs.sf) || isnan(Ft.sf)) + cond = 0; + else + cond = (Fs.sf < Ft.sf); + }}); + + 0x5: c_ult_s({{ + if (isnan(Fs.sf) || isnan(Ft.sf)) + cond = 1; + else + cond = (Fs.sf < Ft.sf); + }}); + + 0x6: c_ole_s({{ + if (isnan(Fs.sf) || isnan(Ft.sf)) + cond = 0; + else + cond = (Fs.sf <= Ft.sf); + }}); + + 0x7: c_ule_s({{ + if (isnan(Fs.sf) || isnan(Ft.sf)) + cond = 1; + else + cond = (Fs.sf <= Ft.sf); + }}); + } + } + + 0x7: decode FUNCTION_LO { + format FloatCompareWithXcptOp { + 0x0: c_sf_s({{ cond = 0; }}); + + 0x1: c_ngle_s({{ + if (isnan(Fs.sf) || isnan(Ft.sf)) + cond = 1; + else + cond = 0; + }}); + + 0x2: c_seq_s({{ + if (isnan(Fs.sf) || isnan(Ft.sf)) + cond = 0; + else + cond = (Fs.sf == Ft.sf); + }}); + + 0x3: c_ngl_s({{ + if (isnan(Fs.sf) || isnan(Ft.sf)) + cond = 1; + else + cond = (Fs.sf == Ft.sf); + }}); + + 0x4: c_lt_s({{ + if (isnan(Fs.sf) || isnan(Ft.sf)) + cond = 0; + else + cond = (Fs.sf < Ft.sf); + }}); + + 0x5: c_nge_s({{ + if (isnan(Fs.sf) || isnan(Ft.sf)) + cond = 1; + else + cond = (Fs.sf < Ft.sf); + }}); + + 0x6: c_le_s({{ + if (isnan(Fs.sf) || isnan(Ft.sf)) + cond = 0; + else + cond = (Fs.sf <= Ft.sf); + }}); + + 0x7: c_ngt_s({{ + if (isnan(Fs.sf) || isnan(Ft.sf)) + cond = 1; + else + cond = (Fs.sf <= Ft.sf); + }}); + } + } + } + + //Table A-15 MIPS32 COP1 Encoding of Function Field When rs=D + 0x1: decode FUNCTION_HI { + 0x0: decode FUNCTION_LO { + format FloatOp { + 0x0: add_d({{ Fd.df = Fs.df + Ft.df;}}); + 0x1: sub_d({{ Fd.df = Fs.df - Ft.df;}}); + 0x2: mul_d({{ Fd.df = Fs.df * Ft.df;}}); + 0x3: div_d({{ Fd.df = Fs.df / Ft.df;}}); + 0x4: sqrt_d({{ Fd.df = sqrt(Fs.df);}}); + 0x5: abs_d({{ Fd.df = fabs(Fs.df);}}); + 0x6: mov_d({{ Fd.ud = Fs.ud;}}); + 0x7: neg_d({{ Fd.df = -1 * Fs.df;}}); + } + } + + 0x1: decode FUNCTION_LO { + format FloatOp { + 0x0: round_l_d({{ + Fd.ud = fpConvert(roundFP(Fs.df,0), DOUBLE_TO_LONG); + }}); + + 0x1: trunc_l_d({{ + Fd.ud = fpConvert(truncFP(Fs.df), DOUBLE_TO_LONG); + }}); + + 0x2: ceil_l_d({{ + Fd.ud = fpConvert(ceil(Fs.df), DOUBLE_TO_LONG); + }}); + + 0x3: floor_l_d({{ + Fd.ud = fpConvert(floor(Fs.df), DOUBLE_TO_LONG); + }}); + } + + format FloatOp { + 0x4: round_w_d({{ + Fd.uw = fpConvert(roundFP(Fs.df,0), DOUBLE_TO_WORD); + }}); + + 0x5: trunc_w_d({{ + Fd.uw = fpConvert(truncFP(Fs.df), DOUBLE_TO_WORD); + }}); + + 0x6: ceil_w_d({{ + Fd.uw = fpConvert(ceil(Fs.df), DOUBLE_TO_WORD); + }}); + + 0x7: floor_w_d({{ + Fd.uw = fpConvert(floor(Fs.df), DOUBLE_TO_WORD); + }}); + } + } + + 0x2: decode FUNCTION_LO { + 0x1: decode MOVCF { + format FloatOp { + 0x0: movf_d({{if (getFPConditionCode(FCSR,CC) == 0) Fd.df = Fs.df; }}); + 0x1: movt_d({{if (getFPConditionCode(FCSR,CC) == 1) Fd.df = Fs.df; }}); + } + } + + format BasicOp { + 0x2: movz_d({{ if (Rt == 0) Fd.df = Fs.df; }}); + 0x3: movn_d({{ if (Rt != 0) Fd.df = Fs.df; }}); + } + + format FloatOp { + 0x5: recip_d({{ Fd.df = 1 / Fs.df}}); + 0x6: rsqrt_d({{ Fd.df = 1 / sqrt(Fs.df) }}); + } + } + + 0x4: decode FUNCTION_LO { + format FloatOp { + 0x0: cvt_s_d({{ + Fd.uw = fpConvert(Fs.df, DOUBLE_TO_SINGLE); + }}); + + 0x4: cvt_w_d({{ + Fd.uw = fpConvert(Fs.df, DOUBLE_TO_WORD); + }}); + + 0x5: cvt_l_d({{ + Fd.ud = fpConvert(Fs.df, DOUBLE_TO_LONG); + }}); + } + } + + 0x6: decode FUNCTION_LO { + format FloatCompareOp { + 0x0: c_f_d({{ cond = 0; }}); + + 0x1: c_un_d({{ + if (isnan(Fs.df) || isnan(Ft.df)) + cond = 1; + else + cond = 0; + }}); + + 0x2: c_eq_d({{ + if (isnan(Fs.df) || isnan(Ft.df)) + cond = 0; + else + cond = (Fs.df == Ft.df); + }}); + + 0x3: c_ueq_d({{ + if (isnan(Fs.df) || isnan(Ft.df)) + cond = 1; + else + cond = (Fs.df == Ft.df); + }}); + + 0x4: c_olt_d({{ + if (isnan(Fs.df) || isnan(Ft.df)) + cond = 0; + else + cond = (Fs.df < Ft.df); + }}); + + 0x5: c_ult_d({{ + if (isnan(Fs.df) || isnan(Ft.df)) + cond = 1; + else + cond = (Fs.df < Ft.df); + }}); + + 0x6: c_ole_d({{ + if (isnan(Fs.df) || isnan(Ft.df)) + cond = 0; + else + cond = (Fs.df <= Ft.df); + }}); + + 0x7: c_ule_d({{ + if (isnan(Fs.df) || isnan(Ft.df)) + cond = 1; + else + cond = (Fs.df <= Ft.df); + }}); + } + } + + 0x7: decode FUNCTION_LO { + format FloatCompareWithXcptOp { + 0x0: c_sf_d({{ cond = 0; }}); + + 0x1: c_ngle_d({{ + if (isnan(Fs.df) || isnan(Ft.df)) + cond = 1; + else + cond = 0; + }}); + + 0x2: c_seq_d({{ + if (isnan(Fs.df) || isnan(Ft.df)) + cond = 0; + else + cond = (Fs.df == Ft.df); + }}); + + 0x3: c_ngl_d({{ + if (isnan(Fs.df) || isnan(Ft.df)) + cond = 1; + else + cond = (Fs.df == Ft.df); + }}); + + 0x4: c_lt_d({{ + if (isnan(Fs.df) || isnan(Ft.df)) + cond = 0; + else + cond = (Fs.df < Ft.df); + }}); + + 0x5: c_nge_d({{ + if (isnan(Fs.df) || isnan(Ft.df)) + cond = 1; + else + cond = (Fs.df < Ft.df); + }}); + + 0x6: c_le_d({{ + if (isnan(Fs.df) || isnan(Ft.df)) + cond = 0; + else + cond = (Fs.df <= Ft.df); + }}); + + 0x7: c_ngt_d({{ + if (isnan(Fs.df) || isnan(Ft.df)) + cond = 1; + else + cond = (Fs.df <= Ft.df); + }}); + } + } + } + + //Table A-16 MIPS32 COP1 Encoding of Function Field When rs=W + 0x4: decode FUNCTION { + format FloatConvertOp { + 0x20: cvt_s_w({{ + Fd.uw = fpConvert(Fs.sf, WORD_TO_SINGLE); + }}); + + 0x21: cvt_d_w({{ + Fd.ud = fpConvert(Fs.sf, WORD_TO_DOUBLE); + }}); + } + + format Float64ConvertOp { + 0x26: cvt_ps_pw({{ + Fd.ud = fpConvert(Fs.ud, WORD_TO_PS); + }}); + } + } + + //Table A-16 MIPS32 COP1 Encoding of Function Field When rs=L1 + //Note: "1. Format type L is legal only if 64-bit floating point operations + //are enabled." + 0x5: decode FUNCTION_HI { + format Float64ConvertOp { + 0x20: cvt_s_l({{ + Fd.uw = fpConvert(Fs.ud, LONG_TO_SINGLE); + }}); + + 0x21: cvt_d_l({{ + Fd.ud = fpConvert(Fs.ud, LONG_TO_DOUBLE); + }}); + + 0x26: cvt_ps_l({{ + Fd.ud = fpConvert(Fs.ud, LONG_TO_PS); + }}); + } + } + + //Table A-17 MIPS64 COP1 Encoding of Function Field When rs=PS1 + //Note: "1. Format type PS is legal only if 64-bit floating point operations + //are enabled. " + 0x6: decode FUNCTION_HI { + 0x0: decode FUNCTION_LO { + format Float64Op { + 0x0: add_ps({{ + Fd1.sf = Fs1.sf + Ft2.sf; + Fd2.sf = Fs2.sf + Ft2.sf; + }}); + + 0x1: sub_ps({{ + Fd1.sf = Fs1.sf - Ft2.sf; + Fd2.sf = Fs2.sf - Ft2.sf; + }}); + + 0x2: mul_ps({{ + Fd1.sf = Fs1.sf * Ft2.sf; + Fd2.sf = Fs2.sf * Ft2.sf; + }}); + + 0x5: abs_ps({{ + Fd1.sf = fabs(Fs1.sf); + Fd2.sf = fabs(Fs2.sf); + }}); + + 0x6: mov_ps({{ + Fd1.sf = Fs1.sf; + Fd2.sf = Fs2.sf; + }}); + + 0x7: neg_ps({{ + Fd1.sf = -1 * Fs1.sf; + Fd2.sf = -1 * Fs2.sf; + }}); + } + } + + 0x2: decode FUNCTION_LO { + 0x1: decode MOVCF { + format Float64Op { + 0x0: movf_ps({{ + if (getFPConditionCode(FCSR, CC) == 0) + Fd1 = Fs1; + if (getFPConditionCode(FCSR, CC+1) == 0) + Fd2 = Fs2; + }}); + + 0x1: movt_ps({{ + if (getFPConditionCode(FCSR, CC) == 1) + Fd1 = Fs1; + if (getFPConditionCode(FCSR, CC+1) == 1) + Fd2 = Fs2; + }}); + } + } + + format Float64Op { + 0x2: movz_ps({{ + if (getFPConditionCode(FCSR, CC) == 0) + Fd1 = Fs1; + if (getFPConditionCode(FCSR, CC) == 0) + Fd2 = Fs2; + }}); + + 0x3: movn_ps({{ + if (getFPConditionCode(FCSR, CC) == 1) + Fd1 = Fs1; + if (getFPConditionCode(FCSR, CC) == 1) + Fd2 = Fs2; + }}); + } + + } + + 0x4: decode FUNCTION_LO { + 0x0: Float64Op::cvt_s_pu({{ + Fd.uw = fpConvert(Fs2.uw, PU_TO_SINGLE); + }}); + } + + 0x5: decode FUNCTION_LO { + format Float64Op { + 0x0: cvt_s_pl({{ + Fd.uw = fpConvert(Fs1.uw, PL_TO_SINGLE); + }}); + + 0x4: pll({{ Fd.ud = (uint64_t) Fs1.uw << 32 | Ft1.uw; }}); + 0x5: plu({{ Fd.ud = (uint64_t) Fs1.uw << 32 | Ft2.uw; }}); + 0x6: pul({{ Fd.ud = (uint64_t) Fs2.uw << 32 | Ft1.uw; }}); + 0x7: puu({{ Fd.ud = (uint64_t) Fs2.uw << 32 | Ft2.uw; }}); + } + } + + 0x6: decode FUNCTION_LO { + format FloatPSCompareOp { + 0x0: c_f_ps({{ cond1 = 0; cond2 = 0; }}); + + 0x1: c_un_ps({{ + if (isnan(Fs1.sf) || isnan(Ft1.sf)) + cond1 = 1; + else + cond1 = 0; + + if (isnan(Fs2.sf) || isnan(Ft2.sf)) + cond2 = 1; + else + cond2 = 0; + + }}); + + 0x2: c_eq_ps({{ + if (isnan(Fs1.sf) || isnan(Ft1.sf)) + cond1 = 0; + else + cond1 = (Fs1.sf == Ft1.sf); + + if (isnan(Fs2.sf) || isnan(Ft2.sf)) + cond2 = 0; + else + cond2 = (Fs2.sf == Ft2.sf); + }}); + + 0x3: c_ueq_ps({{ + if (isnan(Fs1.sf) || isnan(Ft1.sf)) + cond1 = 1; + else + cond1 = (Fs1.sf == Ft1.sf); + + if (isnan(Fs2.sf) || isnan(Ft2.sf)) + cond2 = 1; + else + cond2 = (Fs2.sf == Ft2.sf); + }}); + + 0x4: c_olt_ps({{ + if (isnan(Fs1.sf) || isnan(Ft1.sf)) + cond1 = 0; + else + cond1 = (Fs1.sf < Ft1.sf); + + if (isnan(Fs2.sf) || isnan(Ft2.sf)) + cond2 = 0; + else + cond2 = (Fs2.sf < Ft2.sf); + }}); + + 0x5: c_ult_ps({{ + if (isnan(Fs1.sf) || isnan(Ft1.sf)) + cond1 = 1; + else + cond1 = (Fs.sf < Ft.sf); + + if (isnan(Fs2.sf) || isnan(Ft2.sf)) + cond2 = 1; + else + cond2 = (Fs2.sf < Ft2.sf); + }}); + + 0x6: c_ole_ps({{ + if (isnan(Fs.sf) || isnan(Ft.sf)) + cond1 = 0; + else + cond1 = (Fs.sf <= Ft.sf); + + if (isnan(Fs2.sf) || isnan(Ft2.sf)) + cond2 = 0; + else + cond2 = (Fs2.sf <= Ft2.sf); + }}); + + 0x7: c_ule_ps({{ + if (isnan(Fs1.sf) || isnan(Ft1.sf)) + cond1 = 1; + else + cond1 = (Fs1.sf <= Ft1.sf); + + if (isnan(Fs2.sf) || isnan(Ft2.sf)) + cond2 = 1; + else + cond2 = (Fs2.sf <= Ft2.sf); + }}); + } + } + + 0x7: decode FUNCTION_LO { + format FloatPSCompareWithXcptOp { + 0x0: c_sf_ps({{ cond1 = 0; cond2 = 0; }}); + + 0x1: c_ngle_ps({{ + if (isnan(Fs1.sf) || isnan(Ft1.sf)) + cond1 = 1; + else + cond1 = 0; + + if (isnan(Fs2.sf) || isnan(Ft2.sf)) + cond2 = 1; + else + cond2 = 0; + }}); + + 0x2: c_seq_ps({{ + if (isnan(Fs1.sf) || isnan(Ft1.sf)) + cond1 = 0; + else + cond1 = (Fs1.sf == Ft1.sf); + + if (isnan(Fs2.sf) || isnan(Ft2.sf)) + cond2 = 0; + else + cond2 = (Fs2.sf == Ft2.sf); + }}); + + 0x3: c_ngl_ps({{ + if (isnan(Fs1.sf) || isnan(Ft1.sf)) + cond1 = 1; + else + cond1 = (Fs1.sf == Ft1.sf); + + if (isnan(Fs2.sf) || isnan(Ft2.sf)) + cond2 = 1; + else + cond2 = (Fs2.sf == Ft2.sf); + }}); + + 0x4: c_lt_ps({{ + if (isnan(Fs1.sf) || isnan(Ft1.sf)) + cond1 = 0; + else + cond1 = (Fs1.sf < Ft1.sf); + + if (isnan(Fs2.sf) || isnan(Ft2.sf)) + cond2 = 0; + else + cond2 = (Fs2.sf < Ft2.sf); + }}); + + 0x5: c_nge_ps({{ + if (isnan(Fs1.sf) || isnan(Ft1.sf)) + cond1 = 1; + else + cond1 = (Fs1.sf < Ft1.sf); + + if (isnan(Fs2.sf) || isnan(Ft2.sf)) + cond2 = 1; + else + cond2 = (Fs2.sf < Ft2.sf); + }}); + + 0x6: c_le_ps({{ + if (isnan(Fs1.sf) || isnan(Ft1.sf)) + cond1 = 0; + else + cond1 = (Fs1.sf <= Ft1.sf); + + if (isnan(Fs2.sf) || isnan(Ft2.sf)) + cond2 = 0; + else + cond2 = (Fs2.sf <= Ft2.sf); + }}); + + 0x7: c_ngt_ps({{ + if (isnan(Fs1.sf) || isnan(Ft1.sf)) + cond1 = 1; + else + cond1 = (Fs1.sf <= Ft1.sf); + + if (isnan(Fs2.sf) || isnan(Ft2.sf)) + cond2 = 1; + else + cond2 = (Fs2.sf <= Ft2.sf); + }}); + } + } + } + } + } + } + + //Table A-19 MIPS32 COP2 Encoding of rs Field + 0x2: decode RS_MSB { + 0x0: decode RS_HI { + 0x0: decode RS_LO { + format WarnUnimpl { + 0x0: mfc2(); + 0x2: cfc2(); + 0x3: mfhc2(); + 0x4: mtc2(); + 0x6: ctc2(); + 0x7: mftc2(); + } + } + + 0x1: decode ND { + 0x0: decode TF { + format WarnUnimpl { + 0x0: bc2f(); + 0x1: bc2t(); + } + } + + 0x1: decode TF { + format WarnUnimpl { + 0x0: bc2fl(); + 0x1: bc2tl(); + } + } + } + } + } + + //Table A-20 MIPS64 COP1X Encoding of Function Field 1 + //Note: "COP1X instructions are legal only if 64-bit floating point + //operations are enabled." + 0x3: decode FUNCTION_HI { + 0x0: decode FUNCTION_LO { + format LoadFloatMemory { + 0x0: lwxc1({{ Ft.uw = Mem.uw;}}, {{ EA = Rs + Rt; }}); + 0x1: ldxc1({{ Ft.ud = Mem.ud;}}, {{ EA = Rs + Rt; }}); + 0x5: luxc1({{ Ft.uw = Mem.ud;}}, {{ EA = Rs + Rt; }}); + } + } + + 0x1: decode FUNCTION_LO { + format StoreFloatMemory { + 0x0: swxc1({{ Mem.uw = Ft.uw;}}, {{ EA = Rs + Rt; }}); + 0x1: sdxc1({{ Mem.ud = Ft.ud;}}, {{ EA = Rs + Rt; }}); + 0x5: suxc1({{ Mem.ud = Ft.ud;}}, {{ EA = Rs + Rt; }}); + } + + 0x7: WarnUnimpl::prefx(); + } + + format FloatOp { + 0x3: WarnUnimpl::alnv_ps(); + + format BasicOp { + 0x4: decode FUNCTION_LO { + 0x0: madd_s({{ Fd.sf = (Fs.sf * Ft.sf) + Fr.sf; }}); + 0x1: madd_d({{ Fd.df = (Fs.df * Ft.df) + Fr.df; }}); + 0x6: madd_ps({{ + Fd1.sf = (Fs1.df * Ft1.df) + Fr1.df; + Fd2.sf = (Fs2.df * Ft2.df) + Fr2.df; + }}); + } + + 0x5: decode FUNCTION_LO { + 0x0: msub_s({{ Fd.sf = (Fs.sf * Ft.sf) - Fr.sf; }}); + 0x1: msub_d({{ Fd.df = (Fs.df * Ft.df) - Fr.df; }}); + 0x6: msub_ps({{ + Fd1.sf = (Fs1.df * Ft1.df) - Fr1.df; + Fd2.sf = (Fs2.df * Ft2.df) - Fr2.df; + }}); + } + + 0x6: decode FUNCTION_LO { + 0x0: nmadd_s({{ Fd.sf = (-1 * Fs.sf * Ft.sf) - Fr.sf; }}); + 0x1: nmadd_d({{ Fd.df = (-1 * Fs.df * Ft.df) + Fr.df; }}); + 0x6: nmadd_ps({{ + Fd1.sf = -1 * ((Fs1.df * Ft1.df) + Fr1.df); + Fd2.sf = -1 * ((Fs2.df * Ft2.df) + Fr2.df); + }}); + } + + 0x7: decode FUNCTION_LO { + 0x0: nmsub_s({{ Fd.sf = (-1 * Fs.sf * Ft.sf) - Fr.sf; }}); + 0x1: nmsub_d({{ Fd.df = (-1 * Fs.df * Ft.df) - Fr.df; }}); + 0x6: nmsub_ps({{ + Fd1.sf = -1 * ((Fs1.df * Ft1.df) - Fr1.df); + Fd2.sf = -1 * ((Fs2.df * Ft2.df) - Fr2.df); + }}); + } + } + } + } + + format BranchLikely { + 0x4: beql({{ cond = (Rs.sw == 0); }}); + 0x5: bnel({{ cond = (Rs.sw != 0); }}); + 0x6: blezl({{ cond = (Rs.sw <= 0); }}); + 0x7: bgtzl({{ cond = (Rs.sw > 0); }}); + } + } + + 0x3: decode OPCODE_LO default FailUnimpl::reserved() { + + //Table A-5 MIPS32 SPECIAL2 Encoding of Function Field + 0x4: decode FUNCTION_HI { + + 0x0: decode FUNCTION_LO { + format IntOp { + 0x0: madd({{ + int64_t temp1 = (int64_t) HI << 32 | LO; + temp1 = temp1 + (Rs.sw * Rt.sw); + HI = temp1<63:32>; + LO = temp1<31:0>; + }}); + + 0x1: maddu({{ + int64_t temp1 = (int64_t) HI << 32 | LO; + temp1 = temp1 + (Rs.uw * Rt.uw); + HI = temp1<63:32>; + LO = temp1<31:0>; + }}); + + 0x2: mul({{ Rd.sw = Rs.sw * Rt.sw; }}); + + 0x4: msub({{ + int64_t temp1 = (int64_t) HI << 32 | LO; + temp1 = temp1 - (Rs.sw * Rt.sw); + HI = temp1<63:32>; + LO = temp1<31:0>; + }}); + + 0x5: msubu({{ + int64_t temp1 = (int64_t) HI << 32 | LO; + temp1 = temp1 - (Rs.uw * Rt.uw); + HI = temp1<63:32>; + LO = temp1<31:0>; + }}); + } + } + + 0x4: decode FUNCTION_LO { + format BasicOp { + 0x0: clz({{ + int cnt = 0; + uint32_t mask = 0x80000000; + for (int i=0; i < 32; i++) { + if( (Rs & mask) == 0) { + cnt++; + } else { + break; + } + } + Rd.uw = cnt; + }}); + + 0x1: clo({{ + int cnt = 0; + uint32_t mask = 0x80000000; + for (int i=0; i < 32; i++) { + if( (Rs & mask) != 0) { + cnt++; + } else { + break; + } + } + Rd.uw = cnt; + }}); + } + } + + 0x7: decode FUNCTION_LO { + 0x7: WarnUnimpl::sdbbp(); + } + } + + //Table A-6 MIPS32 SPECIAL3 Encoding of Function Field for Release 2 of the Architecture + 0x7: decode FUNCTION_HI { + + 0x0: decode FUNCTION_LO { + format FailUnimpl { + 0x1: ext(); + 0x4: ins(); + } + } + + 0x1: decode FUNCTION_LO { + format FailUnimpl { + 0x0: fork(); + 0x1: yield(); + } + } + + + //Table A-10 MIPS32 BSHFL Encoding of sa Field + 0x4: decode SA { + + 0x02: FailUnimpl::wsbh(); + + format BasicOp { + 0x10: seb({{ Rd.sw = Rt.sw<7:0>}}); + 0x18: seh({{ Rd.sw = Rt.sw<15:0>}}); + } + } + + 0x6: decode FUNCTION_LO { + 0x7: FailUnimpl::rdhwr();//{{ /*Rt = xc->hwRegs[RD];*/ }} + } + } + } + + 0x4: decode OPCODE_LO default FailUnimpl::reserved() { + format LoadMemory { + 0x0: lb({{ Rt.sw = Mem.sb; }}); + 0x1: lh({{ Rt.sw = Mem.sh; }}); + + 0x2: lwl({{ + uint32_t mem_word = Mem.uw; + uint32_t unalign_addr = Rs + disp; + uint32_t offset = unalign_addr & 0x00000003; +#if BYTE_ORDER == BIG_ENDIAN + switch(offset) + { + case 0: + Rt = mem_word; + break; + + case 1: + Rt &= 0x000F; + Rt |= (mem_word << 4); + break; + + case 2: + Rt &= 0x00FF; + Rt |= (mem_word << 8); + break; + + case 3: + Rt &= 0x0FFF; + Rt |= (mem_word << 12); + break; + + default: + panic("lwl: bad offset"); + } +#elif BYTE_ORDER == LITTLE_ENDIAN + switch(offset) + { + case 0: + Rt &= 0x0FFF; + Rt |= (mem_word << 12); + break; + + case 1: + Rt &= 0x00FF; + Rt |= (mem_word << 8); + break; + + case 2: + Rt &= 0x000F; + Rt |= (mem_word << 4); + break; + + case 3: + Rt = mem_word; + break; + + default: + panic("lwl: bad offset"); + } +#endif + }}, {{ EA = (Rs + disp) & ~3; }}); + + 0x3: lw({{ Rt.sw = Mem.sw; }}); + 0x4: lbu({{ Rt.uw = Mem.ub; }}); + 0x5: lhu({{ Rt.uw = Mem.uh; }}); + 0x6: lwr({{ + uint32_t mem_word = Mem.uw; + uint32_t unalign_addr = Rs + disp; + uint32_t offset = unalign_addr & 0x00000003; + +#if BYTE_ORDER == BIG_ENDIAN + switch(offset) + { + case 0: Rt &= 0xFFF0; Rt |= (mem_word >> 12); break; + case 1: Rt &= 0xFF00; Rt |= (mem_word >> 8); break; + case 2: Rt &= 0xF000; Rt |= (mem_word >> 4); break; + case 3: Rt = mem_word; break; + default: panic("lwr: bad offset"); + } +#elif BYTE_ORDER == LITTLE_ENDIAN + switch(offset) + { + case 0: Rt = mem_word; break; + case 1: Rt &= 0xF000; Rt |= (mem_word >> 4); break; + case 2: Rt &= 0xFF00; Rt |= (mem_word >> 8); break; + case 3: Rt &= 0xFFF0; Rt |= (mem_word >> 12); break; + default: panic("lwr: bad offset"); + } +#endif + }}, + {{ EA = (Rs + disp) & ~3; }}); + } + } + + 0x5: decode OPCODE_LO default FailUnimpl::reserved() { + format StoreMemory { + 0x0: sb({{ Mem.ub = Rt<7:0>; }}); + 0x1: sh({{ Mem.uh = Rt<15:0>; }}); + 0x2: swl({{ + uint32_t mem_word = 0; + uint32_t aligned_addr = (Rs + disp) & ~3; + uint32_t unalign_addr = Rs + disp; + uint32_t offset = unalign_addr & 0x00000003; + + DPRINTF(IEW,"Execute: aligned=0x%x unaligned=0x%x\n offset=0x%x", + aligned_addr,unalign_addr,offset); + + fault = xc->read(aligned_addr, (uint32_t&)mem_word, memAccessFlags); + +#if BYTE_ORDER == BIG_ENDIAN + switch(offset) + { + case 0: + Mem = Rt; + break; + + case 1: + mem_word &= 0xF000; + mem_word |= (Rt >> 4); + Mem = mem_word; + break; + + case 2: + mem_word &= 0xFF00; + mem_word |= (Rt >> 8); + Mem = mem_word; + break; + + case 3: + mem_word &= 0xFFF0; + mem_word |= (Rt >> 12); + Mem = mem_word; + break; + + default: + panic("swl: bad offset"); + } +#elif BYTE_ORDER == LITTLE_ENDIAN + switch(offset) + { + case 0: + mem_word &= 0xFFF0; + mem_word |= (Rt >> 12); + Mem = mem_word; + break; + + case 1: + mem_word &= 0xFF00; + mem_word |= (Rt >> 8); + Mem = mem_word; + break; + + case 2: + mem_word &= 0xF000; + mem_word |= (Rt >> 4); + Mem = mem_word; + break; + + case 3: + Mem = Rt; + break; + + default: + panic("swl: bad offset"); + } +#endif + }},{{ EA = (Rs + disp) & ~3; }},mem_flags = NO_ALIGN_FAULT); + + 0x3: sw({{ Mem.uw = Rt<31:0>; }}); + + 0x6: swr({{ + uint32_t mem_word = 0; + uint32_t aligned_addr = (Rs + disp) & ~3; + uint32_t unalign_addr = Rs + disp; + uint32_t offset = unalign_addr & 0x00000003; + + fault = xc->read(aligned_addr, (uint32_t&)mem_word, memAccessFlags); + +#if BYTE_ORDER == BIG_ENDIAN + switch(offset) + { + case 0: + mem_word &= 0x0FFF; + mem_word |= (Rt << 12); + Mem = mem_word; + break; + + case 1: + mem_word &= 0x00FF; + mem_word |= (Rt << 8); + Mem = mem_word; + break; + + case 2: + mem_word &= 0x000F; + mem_word |= (Rt << 4); + Mem = mem_word; + break; + + case 3: + Mem = Rt; + break; + + default: + panic("swr: bad offset"); + } +#elif BYTE_ORDER == LITTLE_ENDIAN + switch(offset) + { + case 0: + Mem = Rt; + break; + + case 1: + mem_word &= 0x000F; + mem_word |= (Rt << 4); + Mem = mem_word; + break; + + case 2: + mem_word &= 0x00FF; + mem_word |= (Rt << 8); + Mem = mem_word; + break; + + case 3: + mem_word &= 0x0FFF; + mem_word |= (Rt << 12); + Mem = mem_word; + break; + + default: + panic("swr: bad offset"); + } +#endif + }},{{ EA = (Rs + disp) & ~3;}},mem_flags = NO_ALIGN_FAULT); + } + + format WarnUnimpl { + 0x7: cache(); + } + + } + + 0x6: decode OPCODE_LO default FailUnimpl::reserved() { + 0x0: LoadMemory::ll({{Rt.uw = Mem.uw}},mem_flags=LOCKED); + + format LoadFloatMemory { + 0x1: lwc1({{ Ft.uw = Mem.uw; }}); + 0x5: ldc1({{ Ft.ud = Mem.ud; }}); + } + } + + + 0x7: decode OPCODE_LO default FailUnimpl::reserved() { + 0x0: StoreMemory::sc({{ Mem.uw = Rt.uw; Rt.uw = 1; }}); + + format StoreFloatMemory { + 0x1: swc1({{ Mem.uw = Ft.uw; }}); + 0x5: sdc1({{ Mem.ud = Ft.ud; }}); + } + } +} + + diff --git a/arch/mips/isa/formats/basic.isa b/src/arch/mips/isa/formats/basic.isa index c02af7ddc..c02af7ddc 100644 --- a/arch/mips/isa/formats/basic.isa +++ b/src/arch/mips/isa/formats/basic.isa diff --git a/src/arch/mips/isa/formats/branch.isa b/src/arch/mips/isa/formats/branch.isa new file mode 100644 index 000000000..8cfa37a20 --- /dev/null +++ b/src/arch/mips/isa/formats/branch.isa @@ -0,0 +1,324 @@ +// -*- mode:c++ -*- + +//////////////////////////////////////////////////////////////////// +// +// Control transfer instructions +// + +output header {{ + +#include <iostream> + using namespace std; + + /** + * Base class for instructions whose disassembly is not purely a + * function of the machine instruction (i.e., it depends on the + * PC). This class overrides the disassemble() method to check + * the PC and symbol table values before re-using a cached + * disassembly string. This is necessary for branches and jumps, + * where the disassembly string includes the target address (which + * may depend on the PC and/or symbol table). + */ + class PCDependentDisassembly : public MipsStaticInst + { + protected: + /// Cached program counter from last disassembly + mutable Addr cachedPC; + + /// Cached symbol table pointer from last disassembly + mutable const SymbolTable *cachedSymtab; + + /// Constructor + PCDependentDisassembly(const char *mnem, MachInst _machInst, + OpClass __opClass) + : MipsStaticInst(mnem, _machInst, __opClass), + cachedPC(0), cachedSymtab(0) + { + } + + const std::string & + disassemble(Addr pc, const SymbolTable *symtab) const; + }; + + /** + * Base class for branches (PC-relative control transfers), + * conditional or unconditional. + */ + class Branch : public PCDependentDisassembly + { + protected: + /// target address (signed) Displacement . + int32_t disp; + + /// Constructor. + Branch(const char *mnem, MachInst _machInst, OpClass __opClass) + : PCDependentDisassembly(mnem, _machInst, __opClass), + disp(OFFSET << 2) + { + //If Bit 17 is 1 then Sign Extend + if ( (disp & 0x00020000) > 0 ) { + disp |= 0xFFFE0000; + } + } + + Addr branchTarget(Addr branchPC) const; + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; + + /** + * Base class for branch likely branches (PC-relative control transfers), + */ + class BranchLikely : public PCDependentDisassembly + { + protected: + /// target address (signed) Displacement . + int32_t disp; + + /// Constructor. + BranchLikely(const char *mnem, MachInst _machInst, OpClass __opClass) + : PCDependentDisassembly(mnem, _machInst, __opClass), + disp(OFFSET << 2) + { + + } + + Addr branchTarget(Addr branchPC) const; + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; + + /** + * Base class for jumps (register-indirect control transfers). In + * the Mips ISA, these are always unconditional. + */ + class Jump : public PCDependentDisassembly + { + protected: + + /// Displacement to target address (signed). + int32_t disp; + + uint32_t target; + + public: + /// Constructor + Jump(const char *mnem, MachInst _machInst, OpClass __opClass) + : PCDependentDisassembly(mnem, _machInst, __opClass), + disp(JMPTARG << 2) + { + } + + Addr branchTarget(ExecContext *xc) const; + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; +}}; + +output decoder {{ + Addr + Branch::branchTarget(Addr branchPC) const + { + return branchPC + 4 + disp; + } + + Addr + BranchLikely::branchTarget(Addr branchPC) const + { + return branchPC + 4 + disp; + } + + Addr + Jump::branchTarget(ExecContext *xc) const + { + Addr NPC = xc->readPC() + 4; + uint64_t Rb = xc->readIntReg(_srcRegIdx[0]); + return (Rb & ~3) | (NPC & 1); + } + + const std::string & + PCDependentDisassembly::disassemble(Addr pc, + const SymbolTable *symtab) const + { + if (!cachedDisassembly || + pc != cachedPC || symtab != cachedSymtab) + { + if (cachedDisassembly) + delete cachedDisassembly; + + cachedDisassembly = + new std::string(generateDisassembly(pc, symtab)); + cachedPC = pc; + cachedSymtab = symtab; + } + + return *cachedDisassembly; + } + + std::string + Branch::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + std::stringstream ss; + + ccprintf(ss, "%-10s ", mnemonic); + + // There's only one register arg (RA), but it could be + // either a source (the condition for conditional + // branches) or a destination (the link reg for + // unconditional branches) + if (_numSrcRegs == 1) { + printReg(ss, _srcRegIdx[0]); + ss << ","; + } else if(_numSrcRegs == 2) { + printReg(ss, _srcRegIdx[0]); + ss << ","; + printReg(ss, _srcRegIdx[1]); + ss << ","; + } + + Addr target = pc + 4 + disp; + + std::string str; + if (symtab && symtab->findSymbol(target, str)) + ss << str; + else + ccprintf(ss, "0x%x", target); + + string inst_name = mnemonic; + + if (inst_name.substr(inst_name.length()-2,inst_name.length()) == "al"){ + ccprintf(ss, " (r31=0x%x)",pc+8); + } + + return ss.str(); + } + + std::string + BranchLikely::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + std::stringstream ss; + + ccprintf(ss, "%-10s ", mnemonic); + + // There's only one register arg (RA), but it could be + // either a source (the condition for conditional + // branches) or a destination (the link reg for + // unconditional branches) + if (_numSrcRegs > 0) { + printReg(ss, _srcRegIdx[0]); + ss << ","; + } + else if (_numDestRegs > 0) { + printReg(ss, _destRegIdx[0]); + ss << ","; + } + + Addr target = pc + 4 + disp; + + std::string str; + if (symtab && symtab->findSymbol(target, str)) + ss << str; + else + ccprintf(ss, "0x%x", target); + + return ss.str(); + } + + std::string + Jump::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + std::stringstream ss; + + ccprintf(ss, "%-10s ", mnemonic); + + if ( mnemonic == "jal" ) { + Addr npc = pc + 4; + ccprintf(ss,"0x%x",(npc & 0xF0000000) | disp); + } else if (_numSrcRegs == 0) { + std::string str; + if (symtab && symtab->findSymbol(disp, str)) + ss << str; + else + ccprintf(ss, "0x%x", disp); + } else if (_numSrcRegs == 1) { + printReg(ss, _srcRegIdx[0]); + } else if(_numSrcRegs == 2) { + printReg(ss, _srcRegIdx[0]); + ss << ","; + printReg(ss, _srcRegIdx[1]); + } else { + panic(">= 3 Source Registers!!!"); + } + + return ss.str(); + } +}}; + +def format Branch(code,*flags) {{ + #Add Link Code if Link instruction + strlen = len(name) + if name[strlen-2:] == 'al': + code += 'R31 = NNPC;\n' + + #Condition code + code = 'bool cond;\n' + code + code += 'if (cond) {\n' + code += ' NNPC = NPC + disp;\n' + code += '} else {\n' + code += ' NNPC = NNPC;\n' + code += '} \n' + + iop = InstObjParams(name, Name, 'Branch', CodeBlock(code), + ('IsDirectControl', 'IsCondControl')) + + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; + + +def format BranchLikely(code,*flags) {{ + #Add Link Code if Link instruction + strlen = len(name) + if name[strlen-3:] == 'all': + code += 'R31 = NNPC;\n' + + #Condition code + code = 'bool cond;\n' + code + code += 'if (cond) {' + code += 'NNPC = NPC + disp;\n' + code += '} \n' + + + iop = InstObjParams(name, Name, 'Branch', CodeBlock(code), + ('IsDirectControl', 'IsCondControl','IsCondDelaySlot')) + + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; + +def format Jump(code,*flags) {{ + #Add Link Code if Link instruction + strlen = len(name) + if strlen > 1 and name[1:] == 'al': + code = 'R31 = NNPC;\n' + code + + + iop = InstObjParams(name, Name, 'Jump', CodeBlock(code),\ + ('IsIndirectControl', 'IsUncondControl')) + + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; + + + + diff --git a/src/arch/mips/isa/formats/formats.isa b/src/arch/mips/isa/formats/formats.isa new file mode 100644 index 000000000..7d493ffae --- /dev/null +++ b/src/arch/mips/isa/formats/formats.isa @@ -0,0 +1,35 @@ +// -*- mode:c++ -*- + +//Templates from this format are used later +//Include the basic format +##include "basic.isa" + +//Include the basic format +##include "noop.isa" + +//Include utility functions +##include "util.isa" + +//Include the cop0 formats +##include "cop0.isa" + +//Include the integer formats +##include "int.isa" + +//Include the floatOp format +##include "fp.isa" + +//Include the mem format +##include "mem.isa" + +//Include the trap format +##include "trap.isa" + +//Include the branch format +##include "branch.isa" + +//Include the noop format +##include "unimp.isa" + +//Include the noop format +##include "unknown.isa" diff --git a/src/arch/mips/isa/formats/fp.isa b/src/arch/mips/isa/formats/fp.isa new file mode 100644 index 000000000..9f2c24755 --- /dev/null +++ b/src/arch/mips/isa/formats/fp.isa @@ -0,0 +1,109 @@ +// -*- mode:c++ -*- + +//////////////////////////////////////////////////////////////////// +// +// Floating Point operate instructions +// + +output header {{ + /** + * Base class for FP operations. + */ + class FPOp : public MipsStaticInst + { + protected: + + /// Constructor + FPOp(const char *mnem, MachInst _machInst, OpClass __opClass) : MipsStaticInst(mnem, _machInst, __opClass) + { + } + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; +}}; + +output decoder {{ + std::string FPOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + return "Disassembly of integer instruction\n"; + } +}}; + + +// Primary format for float operate instructions: +def format FloatOp(code, *flags) {{ + iop = InstObjParams(name, Name, 'MipsStaticInst', CodeBlock(code), flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; + +def format FloatCompareOp(code, *flags) {{ + code = 'bool cond;\n' + code + code += 'FCSR = makeCCVector(FCSR, CC,cond);\n' + iop = InstObjParams(name, Name, 'MipsStaticInst', CodeBlock(code), flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; + +def format FloatCompareWithXcptOp(code, *flags) {{ + code = 'bool cond;\n' + code + code += 'FCSR = makeCCVector(FCSR, CC,cond);\n' + iop = InstObjParams(name, Name, 'MipsStaticInst', CodeBlock(code), flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; + +def format FloatConvertOp(code, *flags) {{ + iop = InstObjParams(name, Name, 'MipsStaticInst', CodeBlock(code), flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; + +// Primary format for float64 operate instructions: +def format Float64Op(code, *flags) {{ + iop = InstObjParams(name, Name, 'MipsStaticInst', CodeBlock(code), flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; + +def format Float64ConvertOp(code, *flags) {{ + code = 'bool cond;\n' + code + code += 'FCSR = makeCCVector(FCSR, CC,cond);\n' + iop = InstObjParams(name, Name, 'MipsStaticInst', CodeBlock(code), flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; + +def format FloatPSCompareOp(code, *flags) {{ + code = 'bool cond1;\nbool cond2;\n' + code + code += 'FCSR = makeCCVector(FCSR, CC+1, cond1);\n' + code += 'FCSR = makeCCVector(FCSR, CC, cond2);\n' + iop = InstObjParams(name, Name, 'MipsStaticInst', CodeBlock(code), flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; + +def format FloatPSCompareWithXcptOp(code, *flags) {{ + code = 'bool cond1;\nbool cond2;\n' + code + code += 'FCSR = makeCCVector(FCSR, CC+1, cond1);\n' + code += 'FCSR = makeCCVector(FCSR, CC, cond2);\n' + iop = InstObjParams(name, Name, 'MipsStaticInst', CodeBlock(code), flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; diff --git a/src/arch/mips/isa/formats/int.isa b/src/arch/mips/isa/formats/int.isa new file mode 100644 index 000000000..7d38b9ff5 --- /dev/null +++ b/src/arch/mips/isa/formats/int.isa @@ -0,0 +1,131 @@ +// -*- mode:c++ -*- + +//////////////////////////////////////////////////////////////////// +// +// Integer operate instructions +// + +//Outputs to decoder.hh +output header {{ +#include <iostream> + using namespace std; + /** + * Base class for integer operations. + */ + class IntOp : public MipsStaticInst + { + protected: + + /// Constructor + IntOp(const char *mnem, MachInst _machInst, OpClass __opClass) : + MipsStaticInst(mnem, _machInst, __opClass) + { + } + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; + + class IntImmOp : public MipsStaticInst + { + protected: + + int16_t imm; + int32_t sextImm; + uint32_t zextImm; + + /// Constructor + IntImmOp(const char *mnem, MachInst _machInst, OpClass __opClass) : + MipsStaticInst(mnem, _machInst, __opClass),imm(INTIMM), + sextImm(INTIMM),zextImm(0x0000FFFF & INTIMM) + { + //If Bit 15 is 1 then Sign Extend + int32_t temp = sextImm & 0x00008000; + if (temp > 0 && mnemonic != "lui") { + sextImm |= 0xFFFF0000; + } + } + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; + + + }; + +}}; + +//Outputs to decoder.cc +output decoder {{ + std::string IntOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + std::stringstream ss; + + ccprintf(ss, "%-10s ", mnemonic); + + // just print the first dest... if there's a second one, + // it's generally implicit + if (_numDestRegs > 0) { + printReg(ss, _destRegIdx[0]); + ss << ","; + } + + // just print the first two source regs... if there's + // a third one, it's a read-modify-write dest (Rc), + // e.g. for CMOVxx + if (_numSrcRegs > 0) { + printReg(ss, _srcRegIdx[0]); + } + + if (_numSrcRegs > 1) { + ss << ","; + printReg(ss, _srcRegIdx[1]); + } + + return ss.str(); + } + + std::string IntImmOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + std::stringstream ss; + + ccprintf(ss, "%-10s ", mnemonic); + + if (_numDestRegs > 0) { + printReg(ss, _destRegIdx[0]); + } + + ss << ","; + + if (_numSrcRegs > 0) { + printReg(ss, _srcRegIdx[0]); + ss << ","; + } + + if( mnemonic == "lui") + ccprintf(ss, "%08p ", sextImm); + else + ss << (int) sextImm; + + return ss.str(); + } + +}}; + +//Used by decoder.isa +def format IntOp(code, *opt_flags) {{ + orig_code = code + cblk = CodeBlock(code) + + # Figure out if we are creating a IntImmOp or a IntOp + # by looking at the instruction name + iop = InstObjParams(name, Name, 'IntOp', cblk, opt_flags) + strlen = len(name) + if name[strlen-1] == 'i' or name[strlen-2:] == 'iu': + iop = InstObjParams(name, Name, 'IntImmOp', cblk, opt_flags) + + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = OperateNopCheckDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; + + + diff --git a/src/arch/mips/isa/formats/mem.isa b/src/arch/mips/isa/formats/mem.isa new file mode 100644 index 000000000..922cdb9a2 --- /dev/null +++ b/src/arch/mips/isa/formats/mem.isa @@ -0,0 +1,478 @@ +// -*- mode:c++ -*- + +// Copyright (c) 2003-2005 The Regents of The University of Michigan +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +//////////////////////////////////////////////////////////////////// +// +// Memory-format instructions: LoadAddress, Load, Store +// + +output header {{ + /** + * Base class for general Mips memory-format instructions. + */ + class Memory : public MipsStaticInst + { + protected: + + /// Memory request flags. See mem_req_base.hh. + unsigned memAccessFlags; + /// Pointer to EAComp object. + const StaticInstPtr eaCompPtr; + /// Pointer to MemAcc object. + const StaticInstPtr memAccPtr; + + /// Displacement for EA calculation (signed). + int32_t disp; + + /// Constructor + Memory(const char *mnem, MachInst _machInst, OpClass __opClass, + StaticInstPtr _eaCompPtr = nullStaticInstPtr, + StaticInstPtr _memAccPtr = nullStaticInstPtr) + : MipsStaticInst(mnem, _machInst, __opClass), + memAccessFlags(0), eaCompPtr(_eaCompPtr), memAccPtr(_memAccPtr), + disp(OFFSET) + { + //If Bit 15 is 1 then Sign Extend + int32_t temp = disp & 0x00008000; + + if (temp > 0) { + disp |= 0xFFFF0000; + } + } + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + + public: + + const StaticInstPtr &eaCompInst() const { return eaCompPtr; } + const StaticInstPtr &memAccInst() const { return memAccPtr; } + }; + +}}; + + +output decoder {{ + std::string + Memory::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + return csprintf("%-10s %c%d,%d(r%d)", mnemonic, + flags[IsFloating] ? 'f' : 'r', RT, disp, RS); + } + +}}; + +def format LoadAddress(code) {{ + iop = InstObjParams(name, Name, 'MemoryDisp32', CodeBlock(code)) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; + + +def template LoadStoreDeclare {{ + /** + * Static instruction class for "%(mnemonic)s". + */ + class %(class_name)s : public %(base_class)s + { + protected: + + /** + * "Fake" effective address computation class for "%(mnemonic)s". + */ + class EAComp : public %(base_class)s + { + public: + /// Constructor + EAComp(MachInst machInst); + + %(BasicExecDeclare)s + }; + + /** + * "Fake" memory access instruction class for "%(mnemonic)s". + */ + class MemAcc : public %(base_class)s + { + public: + /// Constructor + MemAcc(MachInst machInst); + + %(BasicExecDeclare)s + }; + + public: + + /// Constructor. + %(class_name)s(MachInst machInst); + + %(BasicExecDeclare)s + + %(InitiateAccDeclare)s + + %(CompleteAccDeclare)s + }; +}}; + + +def template InitiateAccDeclare {{ + Fault initiateAcc(%(CPU_exec_context)s *, Trace::InstRecord *) const; +}}; + + +def template CompleteAccDeclare {{ + Fault completeAcc(uint8_t *, %(CPU_exec_context)s *, Trace::InstRecord *) const; +}}; + + +def template LoadStoreConstructor {{ + /** TODO: change op_class to AddrGenOp or something (requires + * creating new member of OpClass enum in op_class.hh, updating + * config files, etc.). */ + inline %(class_name)s::EAComp::EAComp(MachInst machInst) + : %(base_class)s("%(mnemonic)s (EAComp)", machInst, IntAluOp) + { + %(ea_constructor)s; + } + + inline %(class_name)s::MemAcc::MemAcc(MachInst machInst) + : %(base_class)s("%(mnemonic)s (MemAcc)", machInst, %(op_class)s) + { + %(memacc_constructor)s; + } + + inline %(class_name)s::%(class_name)s(MachInst machInst) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + new EAComp(machInst), new MemAcc(machInst)) + { + %(constructor)s; + } +}}; + + +def template EACompExecute {{ + Fault + %(class_name)s::EAComp::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + + %(fp_enable_check)s; + %(op_decl)s; + %(op_rd)s; + %(code)s; + + if (fault == NoFault) { + %(op_wb)s; + xc->setEA(EA); + } + + return fault; + } +}}; + +def template LoadMemAccExecute {{ + Fault + %(class_name)s::MemAcc::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + + %(fp_enable_check)s; + %(op_decl)s; + %(op_rd)s; + EA = xc->getEA(); + + if (fault == NoFault) { + fault = xc->read(EA, (uint%(mem_acc_size)d_t&)Mem, memAccessFlags); + %(code)s; + } + + if (fault == NoFault) { + %(op_wb)s; + } + + return fault; + } +}}; + + +def template LoadExecute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + + %(fp_enable_check)s; + %(op_decl)s; + %(op_rd)s; + %(ea_code)s; + + if (fault == NoFault) { + fault = xc->read(EA, (uint%(mem_acc_size)d_t&)Mem, memAccessFlags); + %(memacc_code)s; + } + + if (fault == NoFault) { + %(op_wb)s; + } + + return fault; + } +}}; + + +def template LoadInitiateAcc {{ + Fault %(class_name)s::initiateAcc(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + + %(fp_enable_check)s; + %(op_src_decl)s; + %(op_rd)s; + %(ea_code)s; + + if (fault == NoFault) { + fault = xc->read(EA, (uint%(mem_acc_size)d_t &)Mem, memAccessFlags); + } + + return fault; + } +}}; + + +def template LoadCompleteAcc {{ + Fault %(class_name)s::completeAcc(uint8_t *data, + %(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Fault fault = NoFault; + + %(fp_enable_check)s; + %(op_decl)s; + + memcpy(&Mem, data, sizeof(Mem)); + + if (fault == NoFault) { + %(memacc_code)s; + } + + if (fault == NoFault) { + %(op_wb)s; + } + + return fault; + } +}}; + + +def template StoreMemAccExecute {{ + Fault + %(class_name)s::MemAcc::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + uint64_t write_result = 0; + + %(fp_enable_check)s; + %(op_decl)s; + %(op_rd)s; + EA = xc->getEA(); + + if (fault == NoFault) { + %(code)s; + } + + if (fault == NoFault) { + fault = xc->write((uint%(mem_acc_size)d_t&)Mem, EA, + memAccessFlags, &write_result); + if (traceData) { traceData->setData(Mem); } + } + + if (fault == NoFault) { + %(postacc_code)s; + } + + if (fault == NoFault) { + %(op_wb)s; + } + + return fault; + } +}}; + + +def template StoreExecute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + uint64_t write_result = 0; + + %(fp_enable_check)s; + %(op_decl)s; + %(op_rd)s; + %(ea_code)s; + + if (fault == NoFault) { + %(memacc_code)s; + } + + if (fault == NoFault) { + fault = xc->write((uint%(mem_acc_size)d_t&)Mem, EA, + memAccessFlags, &write_result); + if (traceData) { traceData->setData(Mem); } + } + + if (fault == NoFault) { + %(postacc_code)s; + } + + if (fault == NoFault) { + %(op_wb)s; + } + + return fault; + } +}}; + +def template StoreInitiateAcc {{ + Fault %(class_name)s::initiateAcc(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + uint64_t write_result = 0; + + %(fp_enable_check)s; + %(op_decl)s; + %(op_rd)s; + %(ea_code)s; + + if (fault == NoFault) { + %(memacc_code)s; + } + + if (fault == NoFault) { + fault = xc->write((uint%(mem_acc_size)d_t&)Mem, EA, + memAccessFlags, &write_result); + if (traceData) { traceData->setData(Mem); } + } + + return fault; + } +}}; + + +def template StoreCompleteAcc {{ + Fault %(class_name)s::completeAcc(uint8_t *data, + %(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Fault fault = NoFault; + uint64_t write_result = 0; + + %(fp_enable_check)s; + %(op_dest_decl)s; + + memcpy(&write_result, data, sizeof(write_result)); + + if (fault == NoFault) { + %(postacc_code)s; + } + + if (fault == NoFault) { + %(op_wb)s; + } + + return fault; + } +}}; + +// load instructions use Rt as dest, so check for +// Rt == 31 to detect nops +def template LoadNopCheckDecode {{ + { + MipsStaticInst *i = new %(class_name)s(machInst); + if (RT == 0) { + i = makeNop(i); + } + return i; + } +}}; + +def format LoadMemory(memacc_code, ea_code = {{ EA = Rs + disp; }}, + mem_flags = [], inst_flags = []) {{ + (header_output, decoder_output, decode_block, exec_output) = \ + LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, + decode_template = LoadNopCheckDecode, + exec_template_base = 'Load') +}}; + + +def format StoreMemory(memacc_code, ea_code = {{ EA = Rs + disp; }}, + mem_flags = [], inst_flags = []) {{ + (header_output, decoder_output, decode_block, exec_output) = \ + LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, + exec_template_base = 'Store') +}}; + +//FP loads are offloaded to these formats for now ... +def format LoadFloatMemory(memacc_code, ea_code = {{ EA = Rs + disp; }}, + mem_flags = [], inst_flags = []) {{ + (header_output, decoder_output, decode_block, exec_output) = \ + LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, + decode_template = BasicDecode, + exec_template_base = 'Load') +}}; + + +def format StoreFloatMemory(memacc_code, ea_code = {{ EA = Rs + disp; }}, + mem_flags = [], inst_flags = []) {{ + (header_output, decoder_output, decode_block, exec_output) = \ + LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, + exec_template_base = 'Store') +}}; + + +def format UnalignedStore(memacc_code, postacc_code, + ea_code = {{ EA = Rb + disp; }}, + mem_flags = [], inst_flags = []) {{ + (header_output, decoder_output, decode_block, exec_output) = \ + LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, + postacc_code, exec_template_base = 'Store') +}}; diff --git a/src/arch/mips/isa/formats/noop.isa b/src/arch/mips/isa/formats/noop.isa new file mode 100644 index 000000000..2aa4816e3 --- /dev/null +++ b/src/arch/mips/isa/formats/noop.isa @@ -0,0 +1,94 @@ +// -*- mode:c++ -*- + +//////////////////////////////////////////////////////////////////// +// +// Nop +// + +output header {{ + /** + * Static instruction class for no-ops. This is a leaf class. + */ + class Nop : public MipsStaticInst + { + /// Disassembly of original instruction. + const std::string originalDisassembly; + + public: + /// Constructor + Nop(const std::string _originalDisassembly, MachInst _machInst) + : MipsStaticInst("nop", _machInst, No_OpClass), + originalDisassembly(_originalDisassembly) + { + flags[IsNop] = true; + } + + ~Nop() { } + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + + %(BasicExecDeclare)s + }; +}}; + +output decoder {{ + std::string Nop::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { +#ifdef SS_COMPATIBLE_DISASSEMBLY + return originalDisassembly; +#else + return csprintf("%-10s (%s)", "nop", originalDisassembly); +#endif + } + + /// Helper function for decoding nops. Substitute Nop object + /// for original inst passed in as arg (and delete latter). + inline + MipsStaticInst * + makeNop(MipsStaticInst *inst) + { + MipsStaticInst *nop = new Nop(inst->disassemble(0), inst->machInst); + delete inst; + return nop; + } +}}; + +output exec {{ + Fault + Nop::execute(%(CPU_exec_context)s *, Trace::InstRecord *) const + { + return NoFault; + } +}}; + +// integer & FP operate instructions use RT as dest, so check for +// RT == 0 to detect nops +def template OperateNopCheckDecode {{ + { + MipsStaticInst *i = new %(class_name)s(machInst); + + //if (RD == 0) { + // i = makeNop(i); + //} + + return i; + } +}}; + + +// Like BasicOperate format, but generates NOP if RC/FC == 31 +def format BasicOperateWithNopCheck(code, *opt_args) {{ + iop = InstObjParams(name, Name, 'MipsStaticInst', CodeBlock(code), + opt_args) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = OperateNopCheckDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; + +def format Nop() {{ + decode_block = 'return new Nop(\"sll r0,r0,0\",machInst);\n' +}}; + diff --git a/arch/mips/isa/formats/tlbop.isa b/src/arch/mips/isa/formats/tlbop.isa index f5e4076f2..f5e4076f2 100644 --- a/arch/mips/isa/formats/tlbop.isa +++ b/src/arch/mips/isa/formats/tlbop.isa diff --git a/arch/mips/isa/formats/trap.isa b/src/arch/mips/isa/formats/trap.isa index 6884d4fa8..6884d4fa8 100644 --- a/arch/mips/isa/formats/trap.isa +++ b/src/arch/mips/isa/formats/trap.isa diff --git a/src/arch/mips/isa/formats/unimp.isa b/src/arch/mips/isa/formats/unimp.isa new file mode 100644 index 000000000..ea0c5b15e --- /dev/null +++ b/src/arch/mips/isa/formats/unimp.isa @@ -0,0 +1,171 @@ +// -*- mode:c++ -*- + +// Copyright (c) 2003-2005 The Regents of The University of Michigan +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +//////////////////////////////////////////////////////////////////// +// +// Unimplemented instructions +// + +output header {{ + /** + * Static instruction class for unimplemented instructions that + * cause simulator termination. Note that these are recognized + * (legal) instructions that the simulator does not support; the + * 'Unknown' class is used for unrecognized/illegal instructions. + * This is a leaf class. + */ + class FailUnimplemented : public MipsStaticInst + { + public: + /// Constructor + FailUnimplemented(const char *_mnemonic, MachInst _machInst) + : MipsStaticInst(_mnemonic, _machInst, No_OpClass) + { + // don't call execute() (which panics) if we're on a + // speculative path + flags[IsNonSpeculative] = true; + } + + %(BasicExecDeclare)s + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; + + /** + * Base class for unimplemented instructions that cause a warning + * to be printed (but do not terminate simulation). This + * implementation is a little screwy in that it will print a + * warning for each instance of a particular unimplemented machine + * instruction, not just for each unimplemented opcode. Should + * probably make the 'warned' flag a static member of the derived + * class. + */ + class WarnUnimplemented : public MipsStaticInst + { + private: + /// Have we warned on this instruction yet? + mutable bool warned; + + public: + /// Constructor + WarnUnimplemented(const char *_mnemonic, MachInst _machInst) + : MipsStaticInst(_mnemonic, _machInst, No_OpClass), warned(false) + { + // don't call execute() (which panics) if we're on a + // speculative path + flags[IsNonSpeculative] = true; + } + + %(BasicExecDeclare)s + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; +}}; + +output decoder {{ + std::string + FailUnimplemented::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { + return csprintf("%-10s (unimplemented)", mnemonic); + } + + std::string + WarnUnimplemented::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { +#ifdef SS_COMPATIBLE_DISASSEMBLY + return csprintf("%-10s", mnemonic); +#else + return csprintf("%-10s (unimplemented)", mnemonic); +#endif + } +}}; + +output exec {{ + Fault + FailUnimplemented::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + panic("attempt to execute unimplemented instruction '%s' " + "(inst 0x%08x, opcode 0x%x, binary:%s)", mnemonic, machInst, OPCODE, + inst2string(machInst)); + return new UnimplementedOpcodeFault; + } + + Fault + WarnUnimplemented::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + if (!warned) { + warn("instruction '%s' unimplemented\n", mnemonic); + warned = true; + } + + return NoFault; + } +}}; + + +def format FailUnimpl() {{ + iop = InstObjParams(name, 'FailUnimplemented') + decode_block = BasicDecodeWithMnemonic.subst(iop) +}}; + +def format WarnUnimpl() {{ + iop = InstObjParams(name, 'WarnUnimplemented') + decode_block = BasicDecodeWithMnemonic.subst(iop) +}}; + +output header {{ + /** + * Static instruction class for unknown (illegal) instructions. + * These cause simulator termination if they are executed in a + * non-speculative mode. This is a leaf class. + */ + class Unknown : public MipsStaticInst + { + public: + /// Constructor + Unknown(MachInst _machInst) + : MipsStaticInst("unknown", _machInst, No_OpClass) + { + // don't call execute() (which panics) if we're on a + // speculative path + flags[IsNonSpeculative] = true; + } + + %(BasicExecDeclare)s + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; +}}; + diff --git a/src/arch/mips/isa/formats/unknown.isa b/src/arch/mips/isa/formats/unknown.isa new file mode 100644 index 000000000..6f88e630c --- /dev/null +++ b/src/arch/mips/isa/formats/unknown.isa @@ -0,0 +1,79 @@ +// -*- mode:c++ -*- + +// Copyright (c) 2003-2005 The Regents of The University of Michigan +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +//////////////////////////////////////////////////////////////////// +// +// Unknown instructions +// + +output header {{ + std::string inst2string(MachInst machInst); +}}; +output decoder {{ + +std::string inst2string(MachInst machInst) +{ + string str = ""; + uint32_t mask = 0x80000000; + + for(int i=0; i < 32; i++) { + if ((machInst & mask) == 0) { + str += "0"; + } else { + str += "1"; + } + + mask = mask >> 1; + } + + return str; +} + + std::string + Unknown::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + return csprintf("%-10s (inst 0x%x, opcode 0x%x, binary:%s)", + "unknown", machInst, OPCODE, inst2string(machInst)); + } +}}; + +output exec {{ + Fault + Unknown::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + panic("attempt to execute unknown instruction " + "(inst 0x%08x, opcode 0x%x, binary: %s)", machInst, OPCODE, inst2string(machInst)); + return new UnimplementedOpcodeFault; + } +}}; + +def format Unknown() {{ + decode_block = 'return new Unknown(machInst);\n' +}}; + diff --git a/src/arch/mips/isa/formats/util.isa b/src/arch/mips/isa/formats/util.isa new file mode 100644 index 000000000..615160931 --- /dev/null +++ b/src/arch/mips/isa/formats/util.isa @@ -0,0 +1,129 @@ +// -*- mode:c++ -*- + +let {{ +def LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, + postacc_code = '', base_class = 'Memory', + decode_template = BasicDecode, exec_template_base = ''): + # Make sure flags are in lists (convert to lists if not). + mem_flags = makeList(mem_flags) + inst_flags = makeList(inst_flags) + + # add hook to get effective addresses into execution trace output. + ea_code += '\nif (traceData) { traceData->setAddr(EA); }\n' + + # generate code block objects + ea_cblk = CodeBlock(ea_code) + memacc_cblk = CodeBlock(memacc_code) + postacc_cblk = CodeBlock(postacc_code) + + # Some CPU models execute the memory operation as an atomic unit, + # while others want to separate them into an effective address + # computation and a memory access operation. As a result, we need + # to generate three StaticInst objects. Note that the latter two + # are nested inside the larger "atomic" one. + + # generate InstObjParams for EAComp object + ea_iop = InstObjParams(name, Name, base_class, ea_cblk, inst_flags) + + # generate InstObjParams for MemAcc object + memacc_iop = InstObjParams(name, Name, base_class, memacc_cblk, inst_flags) + # in the split execution model, the MemAcc portion is responsible + # for the post-access code. + memacc_iop.postacc_code = postacc_cblk.code + + # generate InstObjParams for InitiateAcc, CompleteAcc object + # The code used depends on the template being used + if (exec_template_base == 'Load'): + initiateacc_cblk = CodeBlock(ea_code + memacc_code) + completeacc_cblk = CodeBlock(memacc_code + postacc_code) + elif (exec_template_base == 'Store'): + initiateacc_cblk = CodeBlock(ea_code + memacc_code) + completeacc_cblk = CodeBlock(postacc_code) + else: + initiateacc_cblk = '' + completeacc_cblk = '' + + initiateacc_iop = InstObjParams(name, Name, base_class, initiateacc_cblk, + inst_flags) + + completeacc_iop = InstObjParams(name, Name, base_class, completeacc_cblk, + inst_flags) + + if (exec_template_base == 'Load'): + initiateacc_iop.ea_code = ea_cblk.code + initiateacc_iop.memacc_code = memacc_cblk.code + completeacc_iop.memacc_code = memacc_cblk.code + completeacc_iop.postacc_code = postacc_cblk.code + elif (exec_template_base == 'Store'): + initiateacc_iop.ea_code = ea_cblk.code + initiateacc_iop.memacc_code = memacc_cblk.code + completeacc_iop.postacc_code = postacc_cblk.code + + # generate InstObjParams for unified execution + cblk = CodeBlock(ea_code + memacc_code + postacc_code) + iop = InstObjParams(name, Name, base_class, cblk, inst_flags) + + iop.ea_constructor = ea_cblk.constructor + iop.ea_code = ea_cblk.code + iop.memacc_constructor = memacc_cblk.constructor + iop.memacc_code = memacc_cblk.code + iop.postacc_code = postacc_cblk.code + + if mem_flags: + s = '\n\tmemAccessFlags = ' + string.join(mem_flags, '|') + ';' + iop.constructor += s + memacc_iop.constructor += s + + # select templates + memAccExecTemplate = eval(exec_template_base + 'MemAccExecute') + fullExecTemplate = eval(exec_template_base + 'Execute') + initiateAccTemplate = eval(exec_template_base + 'InitiateAcc') + completeAccTemplate = eval(exec_template_base + 'CompleteAcc') + + # (header_output, decoder_output, decode_block, exec_output) + return (LoadStoreDeclare.subst(iop), LoadStoreConstructor.subst(iop), + decode_template.subst(iop), + EACompExecute.subst(ea_iop) + + memAccExecTemplate.subst(memacc_iop) + + fullExecTemplate.subst(iop) + + initiateAccTemplate.subst(initiateacc_iop) + + completeAccTemplate.subst(completeacc_iop)) +}}; + + +output exec {{ + + using namespace MipsISA; + + /// CLEAR ALL CPU INST/EXE HAZARDS + inline void + clear_exe_inst_hazards() + { + //CODE HERE + } + + + /// Check "FP enabled" machine status bit. Called when executing any FP + /// instruction in full-system mode. + /// @retval Full-system mode: NoFault if FP is enabled, FenFault + /// if not. Non-full-system mode: always returns NoFault. +#if FULL_SYSTEM + inline Fault checkFpEnableFault(%(CPU_exec_context)s *xc) + { + Fault fault = NoFault; // dummy... this ipr access should not fault + if (!Mips34k::ICSR_FPE(xc->readIpr(MipsISA::IPR_ICSR, fault))) { + fault = FloatEnableFault; + } + return fault; + } +#else + inline Fault checkFpEnableFault(%(CPU_exec_context)s *xc) + { + return NoFault; + } +#endif + + +}}; + + diff --git a/src/arch/mips/isa/includes.isa b/src/arch/mips/isa/includes.isa new file mode 100644 index 000000000..9c370fbe3 --- /dev/null +++ b/src/arch/mips/isa/includes.isa @@ -0,0 +1,48 @@ +//////////////////////////////////////////////////////////////////// +// +// Output include file directives. +// + +output header {{ +#include <sstream> +#include <iostream> +#include <iomanip> + +#include "cpu/static_inst.hh" +#include "arch/mips/isa_traits.hh" +}}; + +output decoder {{ +#include "arch/mips/isa_traits.hh" +#include "base/cprintf.hh" +#include "base/loader/symtab.hh" +#include "cpu/exec_context.hh" // for Jump::branchTarget() +#include "arch/mips/faults.hh" +#include "arch/mips/isa_traits.hh" + +#include <math.h> +#if defined(linux) +#include <fenv.h> +#endif + +using namespace MipsISA; +}}; + +output exec {{ +#include "arch/mips/faults.hh" +#include "arch/mips/isa_traits.hh" +#include <math.h> +#if defined(linux) +#include <fenv.h> +#endif + +#ifdef FULL_SYSTEM +//#include "arch/alpha/pseudo_inst.hh" +#endif +#include "cpu/base.hh" +#include "cpu/exetrace.hh" +#include "sim/sim_exit.hh" + +using namespace MipsISA; +}}; + diff --git a/src/arch/mips/isa/main.isa b/src/arch/mips/isa/main.isa new file mode 100644 index 000000000..e6f43c3e7 --- /dev/null +++ b/src/arch/mips/isa/main.isa @@ -0,0 +1,59 @@ +// -*- mode:c++ -*- + +// Copyright (c) 2003-2005 The Regents of The University of Michigan +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +//////////////////////////////////////////////////////////////////// +// +// MIPS ISA description file. +// +//////////////////////////////////////////////////////////////////// + +//Include the C++ include directives +##include "includes.isa" + +//////////////////////////////////////////////////////////////////// +// +// Namespace statement. Everything below this line will be in the +// MipsISAInst namespace. +// + +namespace MipsISA; + +//Include the bitfield definitions +##include "bitfields.isa" + +//Include the operand_types and operand definitions +##include "operands.isa" + +//Include the base class for mips instructions, and some support code +##include "base.isa" + +//Include the definitions for the instruction formats +##include "formats/formats.isa" + +//Include the decoder definition +##include "decoder.isa" diff --git a/src/arch/mips/isa/operands.isa b/src/arch/mips/isa/operands.isa new file mode 100644 index 000000000..0f9c74b48 --- /dev/null +++ b/src/arch/mips/isa/operands.isa @@ -0,0 +1,61 @@ +def operand_types {{ + 'sb' : ('signed int', 8), + 'ub' : ('unsigned int', 8), + 'sh' : ('signed int', 16), + 'uh' : ('unsigned int', 16), + 'sw' : ('signed int', 32), + 'uw' : ('unsigned int', 32), + 'sd' : ('signed int', 64), + 'ud' : ('unsigned int', 64), + 'sf' : ('float', 32), + 'df' : ('float', 64), + 'qf' : ('float', 128) +}}; + +def operands {{ + #General Purpose Integer Reg Operands + 'Rd': ('IntReg', 'uw', 'RD', 'IsInteger', 1), + 'Rs': ('IntReg', 'uw', 'RS', 'IsInteger', 2), + 'Rt': ('IntReg', 'uw', 'RT', 'IsInteger', 3), + + #Operands used for Link or Syscall Insts + 'R31': ('IntReg', 'uw','31','IsInteger', 4), + 'R2': ('IntReg', 'uw','2', 'IsInteger', 5), + + #Special Integer Reg operands + 'HI': ('IntReg', 'uw','32', 'IsInteger', 6), + 'LO': ('IntReg', 'uw','33', 'IsInteger', 7), + + #Immediate Value operand + 'IntImm': ('IntReg', 'uw', 'INTIMM', 'IsInteger', 3), + + #Floating Point Reg Operands + 'Fd': ('FloatReg', 'sf', 'FD', 'IsFloating', 1), + 'Fs': ('FloatReg', 'sf', 'FS', 'IsFloating', 2), + 'Ft': ('FloatReg', 'sf', 'FT', 'IsFloating', 3), + 'Fr': ('FloatReg', 'sf', 'FR', 'IsFloating', 3), + + #Special Floating Point Control Reg Operands + 'FIR': ('FloatReg', 'uw', '32', 'IsFloating', 1), + 'FCCR': ('FloatReg', 'uw', '33', 'IsFloating', 2), + 'FEXR': ('FloatReg', 'uw', '34', 'IsFloating', 3), + 'FENR': ('FloatReg', 'uw', '35', 'IsFloating', 3), + 'FCSR': ('FloatReg', 'uw', '36', 'IsFloating', 3), + + #Operands For Paired Singles FP Operations + 'Fd1': ('FloatReg', 'sf', 'FD', 'IsFloating', 4), + 'Fd2': ('FloatReg', 'sf', 'FD+1', 'IsFloating', 4), + 'Fs1': ('FloatReg', 'sf', 'FS', 'IsFloating', 5), + 'Fs2': ('FloatReg', 'sf', 'FS+1', 'IsFloating', 5), + 'Ft1': ('FloatReg', 'sf', 'FT', 'IsFloating', 6), + 'Ft2': ('FloatReg', 'sf', 'FT+1', 'IsFloating', 6), + 'Fr1': ('FloatReg', 'sf', 'FR', 'IsFloating', 7), + 'Fr2': ('FloatReg', 'sf', 'FR+1', 'IsFloating', 7), + + #Memory Operand + 'Mem': ('Mem', 'uw', None, ('IsMemRef', 'IsLoad', 'IsStore'), 4), + + #Program Counter Operands + 'NPC': ('NPC', 'uw', None, ( None, None, 'IsControl' ), 4), + 'NNPC':('NNPC', 'uw', None, ( None, None, 'IsControl' ), 4) +}}; diff --git a/src/arch/mips/isa_traits.cc b/src/arch/mips/isa_traits.cc new file mode 100644 index 000000000..216a6e2ec --- /dev/null +++ b/src/arch/mips/isa_traits.cc @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "arch/mips/isa_traits.hh" +#include "config/full_system.hh" +#include "cpu/static_inst.hh" +#include "sim/serialize.hh" +#include "base/bitfield.hh" + +using namespace MipsISA; +using namespace std; + + +void +MipsISA::copyRegs(ExecContext *src, ExecContext *dest) +{ + /*fpcr = xc->readMiscReg(MipsISA::Fpcr_DepTag); + uniq = xc->readMiscReg(MipsISA::Uniq_DepTag); + lock_flag = xc->readMiscReg(MipsISA::Lock_Flag_DepTag); + lock_addr = xc->readMiscReg(MipsISA::Lock_Addr_DepTag); + +#if FULL_SYSTEM + copyIprs(xc); + #endif*/ +} + +void +MipsISA::MiscRegFile::copyMiscRegs(ExecContext *xc) +{ + /*fpcr = xc->readMiscReg(MipsISA::Fpcr_DepTag); + uniq = xc->readMiscReg(MipsISA::Uniq_DepTag); + lock_flag = xc->readMiscReg(MipsISA::Lock_Flag_DepTag); + lock_addr = xc->readMiscReg(MipsISA::Lock_Addr_DepTag); + + #endif*/ +} + +uint64_t +MipsISA::fpConvert(double fp_val, ConvertType cvt_type) +{ + + switch (cvt_type) + { + case SINGLE_TO_DOUBLE: + double sdouble_val = fp_val; + void *sdouble_ptr = &sdouble_val; + uint64_t sdp_bits = *(uint64_t *) sdouble_ptr; + return sdp_bits; + + case SINGLE_TO_WORD: + int32_t sword_val = (int32_t) fp_val; + void *sword_ptr = &sword_val; + uint64_t sword_bits= *(uint32_t *) sword_ptr; + return sword_bits; + + case WORD_TO_SINGLE: + float wfloat_val = fp_val; + void *wfloat_ptr = &wfloat_val; + uint64_t wfloat_bits = *(uint32_t *) wfloat_ptr; + return wfloat_bits; + + case WORD_TO_DOUBLE: + double wdouble_val = fp_val; + void *wdouble_ptr = &wdouble_val; + uint64_t wdp_bits = *(uint64_t *) wdouble_ptr; + return wdp_bits; + + default: + panic("Invalid Floating Point Conversion Type (%d). See \"types.hh\" for List of Conversions\n",cvt_type); + return 0; + } +} + +double +MipsISA::roundFP(double val, int digits) +{ + double digit_offset = pow(10.0,digits); + val = val * digit_offset; + val = val + 0.5; + val = floor(val); + val = val / digit_offset; + return val; +} + +double +MipsISA::truncFP(double val) +{ + int trunc_val = (int) val; + return (double) trunc_val; +} + +bool +MipsISA::getFPConditionCode(uint32_t fcsr_reg, int cc) +{ + //uint32_t cc_bits = xc->readFloatReg(35); + return false;//regFile.floatRegfile.getConditionCode(cc); +} + +uint32_t +MipsISA::makeCCVector(uint32_t fcsr, int num, bool val) +{ + int shift = (num == 0) ? 22 : num + 23; + + fcsr = fcsr | (val << shift); + + return fcsr; +} + +#if FULL_SYSTEM + +static inline Addr +TruncPage(Addr addr) +{ return addr & ~(MipsISA::PageBytes - 1); } + +static inline Addr +RoundPage(Addr addr) +{ return (addr + MipsISA::PageBytes - 1) & ~(MipsISA::PageBytes - 1); } +#endif + +void +IntRegFile::serialize(std::ostream &os) +{ + SERIALIZE_ARRAY(regs, NumIntRegs); +} + +void +IntRegFile::unserialize(Checkpoint *cp, const std::string §ion) +{ + UNSERIALIZE_ARRAY(regs, NumIntRegs); +} + +void +RegFile::serialize(std::ostream &os) +{ + intRegFile.serialize(os); + //SERIALIZE_ARRAY(floatRegFile.q, NumFloatRegs); + //SERIALIZE_SCALAR(miscRegs.fpcr); + //SERIALIZE_SCALAR(miscRegs.uniq); + //SERIALIZE_SCALAR(miscRegs.lock_flag); + //SERIALIZE_SCALAR(miscRegs.lock_addr); + SERIALIZE_SCALAR(pc); + SERIALIZE_SCALAR(npc); + SERIALIZE_SCALAR(nnpc); +#if FULL_SYSTEM + SERIALIZE_ARRAY(palregs, NumIntRegs); + SERIALIZE_ARRAY(ipr, NumInternalProcRegs); + SERIALIZE_SCALAR(intrflag); + SERIALIZE_SCALAR(pal_shadow); +#endif +} + + +void +RegFile::unserialize(Checkpoint *cp, const std::string §ion) +{ + intRegFile.unserialize(cp, section); + //UNSERIALIZE_ARRAY(floatRegFile.q, NumFloatRegs); + //UNSERIALIZE_SCALAR(miscRegs.fpcr); + //UNSERIALIZE_SCALAR(miscRegs.uniq); + //UNSERIALIZE_SCALAR(miscRegs.lock_flag); + //UNSERIALIZE_SCALAR(miscRegs.lock_addr); + UNSERIALIZE_SCALAR(pc); + UNSERIALIZE_SCALAR(npc); + UNSERIALIZE_SCALAR(nnpc); +#if FULL_SYSTEM + UNSERIALIZE_ARRAY(palregs, NumIntRegs); + UNSERIALIZE_ARRAY(ipr, NumInternalProcRegs); + UNSERIALIZE_SCALAR(intrflag); + UNSERIALIZE_SCALAR(pal_shadow); +#endif +} + + +#if FULL_SYSTEM +void +PTE::serialize(std::ostream &os) +{ + SERIALIZE_SCALAR(tag); + SERIALIZE_SCALAR(ppn); + SERIALIZE_SCALAR(xre); + SERIALIZE_SCALAR(xwe); + SERIALIZE_SCALAR(asn); + SERIALIZE_SCALAR(asma); + SERIALIZE_SCALAR(fonr); + SERIALIZE_SCALAR(fonw); + SERIALIZE_SCALAR(valid); +} + + +void +PTE::unserialize(Checkpoint *cp, const std::string §ion) +{ + UNSERIALIZE_SCALAR(tag); + UNSERIALIZE_SCALAR(ppn); + UNSERIALIZE_SCALAR(xre); + UNSERIALIZE_SCALAR(xwe); + UNSERIALIZE_SCALAR(asn); + UNSERIALIZE_SCALAR(asma); + UNSERIALIZE_SCALAR(fonr); + UNSERIALIZE_SCALAR(fonw); + UNSERIALIZE_SCALAR(valid); +} + +#endif //FULL_SYSTEM diff --git a/src/arch/mips/isa_traits.hh b/src/arch/mips/isa_traits.hh new file mode 100644 index 000000000..148c405df --- /dev/null +++ b/src/arch/mips/isa_traits.hh @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ARCH_MIPS_ISA_TRAITS_HH__ +#define __ARCH_MIPS_ISA_TRAITS_HH__ + +#include "arch/mips/constants.hh" +#include "arch/mips/types.hh" +#include "arch/mips/regfile/regfile.hh" +#include "arch/mips/faults.hh" +#include "arch/mips/utility.hh" +#include "base/misc.hh" +#include "config/full_system.hh" +#include "sim/byteswap.hh" +#include "sim/host.hh" +#include "sim/faults.hh" + +#include <vector> + +class FastCPU; +class FullCPU; +class Checkpoint; +class ExecContext; + +namespace LittleEndianGuest {}; + +#define TARGET_MIPS + +class StaticInst; +class StaticInstPtr; + +namespace MIPS34K { +int DTB_ASN_ASN(uint64_t reg); +int ITB_ASN_ASN(uint64_t reg); +}; + +#if !FULL_SYSTEM +class SyscallReturn { + public: + template <class T> + SyscallReturn(T v, bool s) + { + retval = (uint32_t)v; + success = s; + } + + template <class T> + SyscallReturn(T v) + { + success = (v >= 0); + retval = (uint32_t)v; + } + + ~SyscallReturn() {} + + SyscallReturn& operator=(const SyscallReturn& s) { + retval = s.retval; + success = s.success; + return *this; + } + + bool successful() { return success; } + uint64_t value() { return retval; } + + + private: + uint64_t retval; + bool success; +}; +#endif + +namespace MipsISA +{ + using namespace LittleEndianGuest; + + static inline void setSyscallReturn(SyscallReturn return_value, RegFile *regs) + { + if (return_value.successful()) { + // no error + regs->setIntReg(SyscallSuccessReg, 0); + regs->setIntReg(ReturnValueReg1, return_value.value()); + } else { + // got an error, return details + regs->setIntReg(SyscallSuccessReg, (IntReg) -1); + regs->setIntReg(ReturnValueReg1, -return_value.value()); + } + } + + StaticInstPtr decodeInst(ExtMachInst); + + static inline ExtMachInst + makeExtMI(MachInst inst, const uint64_t &pc) { +#if FULL_SYSTEM + ExtMachInst ext_inst = inst; + if (pc && 0x1) + return ext_inst|=(static_cast<ExtMachInst>(pc & 0x1) << 32); + else + return ext_inst; +#else + return ExtMachInst(inst); +#endif + } + + /** + * Function to insure ISA semantics about 0 registers. + * @param xc The execution context. + */ + template <class XC> + void zeroRegisters(XC *xc); + + const Addr MaxAddr = (Addr)-1; + + void copyRegs(ExecContext *src, ExecContext *dest); + + uint64_t fpConvert(double fp_val, ConvertType cvt_type); + double roundFP(double val, int digits); + double truncFP(double val); + bool getFPConditionCode(uint32_t fcsr_reg, int cc); + uint32_t makeCCVector(uint32_t fcsr, int num, bool val); + + // Machine operations + + void saveMachineReg(AnyReg &savereg, const RegFile ®_file, + int regnum); + + void restoreMachineReg(RegFile ®s, const AnyReg ®, + int regnum); + +#if 0 + static void serializeSpecialRegs(const Serializable::Proxy &proxy, + const RegFile ®s); + + static void unserializeSpecialRegs(const IniFile *db, + const std::string &category, + ConfigNode *node, + RegFile ®s); +#endif + + static inline Addr alignAddress(const Addr &addr, + unsigned int nbytes) { + return (addr & ~(nbytes - 1)); + } + + // Instruction address compression hooks + static inline Addr realPCToFetchPC(const Addr &addr) { + return addr; + } + + static inline Addr fetchPCToRealPC(const Addr &addr) { + return addr; + } + + // the size of "fetched" instructions (not necessarily the size + // of real instructions for PISA) + static inline size_t fetchInstSize() { + return sizeof(MachInst); + } + + static inline MachInst makeRegisterCopy(int dest, int src) { + panic("makeRegisterCopy not implemented"); + return 0; + } + +}; + +#if FULL_SYSTEM + +#include "arch/mips/mips34k.hh" + +#endif + +using namespace MipsISA; + +#endif // __ARCH_MIPS_ISA_TRAITS_HH__ diff --git a/src/arch/mips/linux/linux.cc b/src/arch/mips/linux/linux.cc new file mode 100644 index 000000000..26e3dd479 --- /dev/null +++ b/src/arch/mips/linux/linux.cc @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + */ + +#include "arch/mips/linux/linux.hh" + +// open(2) flags translation table +OpenFlagTransTable MipsLinux::openFlagTable[] = { +#ifdef _MSC_VER + { MipsLinux::TGT_O_RDONLY, _O_RDONLY }, + { MipsLinux::TGT_O_WRONLY, _O_WRONLY }, + { MipsLinux::TGT_O_RDWR, _O_RDWR }, + { MipsLinux::TGT_O_APPEND, _O_APPEND }, + { MipsLinux::TGT_O_CREAT, _O_CREAT }, + { MipsLinux::TGT_O_TRUNC, _O_TRUNC }, + { MipsLinux::TGT_O_EXCL, _O_EXCL }, +#ifdef _O_NONBLOCK + { MipsLinux::TGT_O_NONBLOCK, _O_NONBLOCK }, +#endif +#ifdef _O_NOCTTY + { MipsLinux::TGT_O_NOCTTY, _O_NOCTTY }, +#endif +#ifdef _O_SYNC + { MipsLinux::TGT_O_SYNC, _O_SYNC }, +#endif +#else /* !_MSC_VER */ + { MipsLinux::TGT_O_RDONLY, O_RDONLY }, + { MipsLinux::TGT_O_WRONLY, O_WRONLY }, + { MipsLinux::TGT_O_RDWR, O_RDWR }, + { MipsLinux::TGT_O_APPEND, O_APPEND }, + { MipsLinux::TGT_O_CREAT, O_CREAT }, + { MipsLinux::TGT_O_TRUNC, O_TRUNC }, + { MipsLinux::TGT_O_EXCL, O_EXCL }, + { MipsLinux::TGT_O_NONBLOCK, O_NONBLOCK }, + { MipsLinux::TGT_O_NOCTTY, O_NOCTTY }, +#ifdef O_SYNC + { MipsLinux::TGT_O_SYNC, O_SYNC }, +#endif +#endif /* _MSC_VER */ +}; + +const int MipsLinux::NUM_OPEN_FLAGS = + (sizeof(MipsLinux::openFlagTable)/sizeof(MipsLinux::openFlagTable[0])); + + + diff --git a/src/arch/mips/linux/linux.hh b/src/arch/mips/linux/linux.hh new file mode 100644 index 000000000..f85935bb9 --- /dev/null +++ b/src/arch/mips/linux/linux.hh @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + */ + +#ifndef __ARCH_MIPS_LINUX_LINUX_HH__ +#define __ARCH_MIPS_LINUX_LINUX_HH__ + +#include "kern/linux/linux.hh" + +class MipsLinux : public Linux +{ + public: + + /// This table maps the target open() flags to the corresponding + /// host open() flags. + static OpenFlagTransTable openFlagTable[]; + + /// Number of entries in openFlagTable[]. + static const int NUM_OPEN_FLAGS; + + //@{ + /// open(2) flag values. + static const int TGT_O_RDONLY = 0x00000000; //!< O_RDONLY + static const int TGT_O_WRONLY = 0x00000001; //!< O_WRONLY + static const int TGT_O_RDWR = 0x00000002; //!< O_RDWR + static const int TGT_O_NONBLOCK = 0x00000080; //!< O_NONBLOCK + static const int TGT_O_APPEND = 0x00000008; //!< O_APPEND + static const int TGT_O_CREAT = 0x00000100; //!< O_CREAT + static const int TGT_O_TRUNC = 0x00000200; //!< O_TRUNC + static const int TGT_O_EXCL = 0x00000400; //!< O_EXCL + static const int TGT_O_NOCTTY = 0x00000800; //!< O_NOCTTY + static const int TGT_O_SYNC = 0x00000010; //!< O_SYNC + static const int TGT_O_DRD = 0x00010000; //!< O_DRD + static const int TGT_O_DIRECTIO = 0x00020000; //!< O_DIRECTIO + static const int TGT_O_CACHE = 0x00002000; //!< O_CACHE + static const int TGT_O_DSYNC = 0x00008000; //!< O_DSYNC + static const int TGT_O_RSYNC = 0x00040000; //!< O_RSYNC + //@} + + /// For mmap(). + static const unsigned TGT_MAP_ANONYMOUS = 0x800; + + //@{ + /// For getsysinfo(). + static const unsigned GSI_PLATFORM_NAME = 103; //!< platform name as string + static const unsigned GSI_CPU_INFO = 59; //!< CPU information + static const unsigned GSI_PROC_TYPE = 60; //!< get proc_type + static const unsigned GSI_MAX_CPU = 30; //!< max # cpu's on this machine + static const unsigned GSI_CPUS_IN_BOX = 55; //!< number of CPUs in system + static const unsigned GSI_PHYSMEM = 19; //!< Physical memory in KB + static const unsigned GSI_CLK_TCK = 42; //!< clock freq in Hz + //@} + + //@{ + /// For getrusage(). + static const int TGT_RUSAGE_SELF = 0; + static const int TGT_RUSAGE_CHILDREN = -1; + static const int TGT_RUSAGE_BOTH = -2; + //@} + + //@{ + /// For setsysinfo(). + static const unsigned SSI_IEEE_FP_CONTROL = 14; //!< ieee_set_fp_control() + //@} + + //@{ + /// ioctl() command codes. + static const unsigned TIOCGETP = 0x7408; + static const unsigned TIOCSETP = 0x7409; + static const unsigned TIOCSETN = 0x740a; + static const unsigned TIOCSETC = 0x7411; + static const unsigned TIOCGETC = 0x7412; + static const unsigned FIONREAD = 0x467f; + static const unsigned TIOCISATTY = 0x5480; + static const unsigned TIOCGETS = 0x7413; + static const unsigned TIOCGETA = 0x7417; + //@} + + /// For table(). + static const int TBL_SYSINFO = 12; + + /// Resource enumeration for getrlimit(). + enum rlimit_resources { + TGT_RLIMIT_CPU = 0, + TGT_RLIMIT_FSIZE = 1, + TGT_RLIMIT_DATA = 2, + TGT_RLIMIT_STACK = 3, + TGT_RLIMIT_CORE = 4, + TGT_RLIMIT_NOFILE = 5, + TGT_RLIMIT_AS = 6, + TGT_RLIMIT_RSS = 7, + TGT_RLIMIT_VMEM = 7, + TGT_RLIMIT_NPROC = 8, + TGT_RLIMIT_MEMLOCK = 9, + TGT_RLIMIT_LOCKS = 10 + }; + +}; + +#endif diff --git a/src/arch/mips/linux/process.cc b/src/arch/mips/linux/process.cc new file mode 100644 index 000000000..ffc5da2e1 --- /dev/null +++ b/src/arch/mips/linux/process.cc @@ -0,0 +1,429 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "arch/mips/linux/linux.hh" +#include "arch/mips/linux/process.hh" +#include "arch/mips/isa_traits.hh" + +#include "base/trace.hh" +#include "cpu/exec_context.hh" +#include "kern/linux/linux.hh" + +#include "sim/process.hh" +#include "sim/syscall_emul.hh" + +using namespace std; +using namespace MipsISA; + +/// Target uname() handler. +static SyscallReturn +unameFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + TypedBufferArg<Linux::utsname> name(xc->getSyscallArg(0)); + + strcpy(name->sysname, "Linux"); + strcpy(name->nodename, "m5.eecs.umich.edu"); + strcpy(name->release, "2.4.20"); + strcpy(name->version, "#1 Mon Aug 18 11:32:15 EDT 2003"); + strcpy(name->machine, "mips"); + + name.copyOut(xc->getMemPort()); + return 0; +} + +/// Target sys_getsysyinfo() handler. Even though this call is +/// borrowed from Tru64, the subcases that get used appear to be +/// different in practice from those used by Tru64 processes. +static SyscallReturn +sys_getsysinfoFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + unsigned op = xc->getSyscallArg(0); + // unsigned nbytes = xc->getSyscallArg(2); + + switch (op) { + + case 45: { // GSI_IEEE_FP_CONTROL + TypedBufferArg<uint64_t> fpcr(xc->getSyscallArg(1)); + // I don't think this exactly matches the HW FPCR + *fpcr = 0; + fpcr.copyOut(xc->getMemPort()); + return 0; + } + + default: + cerr << "sys_getsysinfo: unknown op " << op << endl; + abort(); + break; + } + + return 1; +} + +/// Target sys_setsysinfo() handler. +static SyscallReturn +sys_setsysinfoFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + unsigned op = xc->getSyscallArg(0); + // unsigned nbytes = xc->getSyscallArg(2); + + switch (op) { + + case 14: { // SSI_IEEE_FP_CONTROL + TypedBufferArg<uint64_t> fpcr(xc->getSyscallArg(1)); + // I don't think this exactly matches the HW FPCR + fpcr.copyIn(xc->getMemPort()); + DPRINTFR(SyscallVerbose, "sys_setsysinfo(SSI_IEEE_FP_CONTROL): " + " setting FPCR to 0x%x\n", gtoh(*(uint64_t*)fpcr)); + return 0; + } + + default: + cerr << "sys_setsysinfo: unknown op " << op << endl; + abort(); + break; + } + + return 1; +} + + +SyscallDesc MipsLinuxProcess::syscallDescs[] = { + /* 0 */ SyscallDesc("syscall", unimplementedFunc), + /* 1 */ SyscallDesc("exit", exitFunc), + /* 2 */ SyscallDesc("fork", unimplementedFunc), + /* 3 */ SyscallDesc("read", readFunc), + /* 4 */ SyscallDesc("write", writeFunc), + /* 5 */ SyscallDesc("open", openFunc<MipsLinux>), + /* 6 */ SyscallDesc("close", closeFunc), + /* 7 */ SyscallDesc("waitpid", unimplementedFunc), + /* 8 */ SyscallDesc("creat", unimplementedFunc), + /* 9 */ SyscallDesc("link", unimplementedFunc), + /* 10 */ SyscallDesc("unlink", unlinkFunc), + /* 11 */ SyscallDesc("execve", unimplementedFunc), + /* 12 */ SyscallDesc("chdir", unimplementedFunc), + /* 13 */ SyscallDesc("time", unimplementedFunc), + /* 14 */ SyscallDesc("mknod", unimplementedFunc), + /* 15 */ SyscallDesc("chmod", chmodFunc<MipsLinux>), + /* 16 */ SyscallDesc("lchown", chownFunc), + /* 17 */ SyscallDesc("break", obreakFunc), /*obreak*/ + /* 18 */ SyscallDesc("unused#18", unimplementedFunc), + /* 19 */ SyscallDesc("lseek", lseekFunc), + /* 20 */ SyscallDesc("getpid", getpidFunc), + /* 21 */ SyscallDesc("mount", unimplementedFunc), + /* 22 */ SyscallDesc("umount", unimplementedFunc), + /* 23 */ SyscallDesc("setuid", setuidFunc), + /* 24 */ SyscallDesc("getuid", getuidFunc), + /* 25 */ SyscallDesc("stime", unimplementedFunc), + /* 26 */ SyscallDesc("ptrace", unimplementedFunc), + /* 27 */ SyscallDesc("alarm", unimplementedFunc), + /* 28 */ SyscallDesc("unused#28", unimplementedFunc), + /* 29 */ SyscallDesc("pause", unimplementedFunc), + /* 30 */ SyscallDesc("utime", unimplementedFunc), + /* 31 */ SyscallDesc("stty", unimplementedFunc), + /* 32 */ SyscallDesc("gtty", unimplementedFunc), + /* 33 */ SyscallDesc("access", unimplementedFunc), + /* 34 */ SyscallDesc("nice", unimplementedFunc), + /* 35 */ SyscallDesc("ftime", unimplementedFunc), + /* 36 */ SyscallDesc("sync", unimplementedFunc), + /* 37 */ SyscallDesc("kill", ignoreFunc), + /* 38 */ SyscallDesc("rename", unimplementedFunc), + /* 39 */ SyscallDesc("mkdir", unimplementedFunc), + /* 40 */ SyscallDesc("rmdir", unimplementedFunc), + /* 41 */ SyscallDesc("dup", unimplementedFunc), + /* 42 */ SyscallDesc("pipe", unimplementedFunc), + /* 43 */ SyscallDesc("times", unimplementedFunc), + /* 44 */ SyscallDesc("prof", unimplementedFunc), + /* 45 */ SyscallDesc("brk", obreakFunc),/*openFunc<MipsLinux>*/ + /* 46 */ SyscallDesc("setgid", unimplementedFunc), + /* 47 */ SyscallDesc("getgid", getgidFunc), + /* 48 */ SyscallDesc("signal", ignoreFunc), + /* 49 */ SyscallDesc("geteuid", geteuidFunc), + /* 50 */ SyscallDesc("getegid", getegidFunc), + /* 51 */ SyscallDesc("acct", unimplementedFunc), + /* 52 */ SyscallDesc("umount2", unimplementedFunc), + /* 53 */ SyscallDesc("lock", unimplementedFunc), + /* 54 */ SyscallDesc("ioctl", ioctlFunc<MipsLinux>), + /* 55 */ SyscallDesc("fcntl", unimplementedFunc), + /* 56 */ SyscallDesc("mpx", unimplementedFunc), + /* 57 */ SyscallDesc("setpgid", unimplementedFunc), + /* 58 */ SyscallDesc("ulimit", unimplementedFunc), + /* 59 */ SyscallDesc("unused#59", unimplementedFunc), + /* 60 */ SyscallDesc("umask", unimplementedFunc), + /* 61 */ SyscallDesc("chroot", unimplementedFunc), + /* 62 */ SyscallDesc("ustat", unimplementedFunc), + /* 63 */ SyscallDesc("dup2", unimplementedFunc), + /* 64 */ SyscallDesc("getppid", getpagesizeFunc), + /* 65 */ SyscallDesc("getpgrp", unimplementedFunc), + /* 66 */ SyscallDesc("setsid", unimplementedFunc), + /* 67 */ SyscallDesc("sigaction",unimplementedFunc), + /* 68 */ SyscallDesc("sgetmask", unimplementedFunc), + /* 69 */ SyscallDesc("ssetmask", unimplementedFunc), + /* 70 */ SyscallDesc("setreuid", unimplementedFunc), + /* 71 */ SyscallDesc("setregid", unimplementedFunc), + /* 72 */ SyscallDesc("sigsuspend", unimplementedFunc), + /* 73 */ SyscallDesc("sigpending", unimplementedFunc), + /* 74 */ SyscallDesc("sethostname", ignoreFunc), + /* 75 */ SyscallDesc("setrlimit", unimplementedFunc), + /* 76 */ SyscallDesc("getrlimit", unimplementedFunc), + /* 77 */ SyscallDesc("getrusage", unimplementedFunc), + /* 78 */ SyscallDesc("gettimeofday", unimplementedFunc), + /* 79 */ SyscallDesc("settimeofday", unimplementedFunc), + /* 80 */ SyscallDesc("getgroups", unimplementedFunc), + /* 81 */ SyscallDesc("setgroups", unimplementedFunc), + /* 82 */ SyscallDesc("reserved#82", unimplementedFunc), + /* 83 */ SyscallDesc("symlink", unimplementedFunc), + /* 84 */ SyscallDesc("unused#84", unimplementedFunc), + /* 85 */ SyscallDesc("readlink", unimplementedFunc), + /* 86 */ SyscallDesc("uselib", unimplementedFunc), + /* 87 */ SyscallDesc("swapon", gethostnameFunc), + /* 88 */ SyscallDesc("reboot", unimplementedFunc), + /* 89 */ SyscallDesc("readdir", unimplementedFunc), + /* 90 */ SyscallDesc("mmap", mmapFunc<MipsLinux>), + /* 91 */ SyscallDesc("munmap",munmapFunc), + /* 92 */ SyscallDesc("truncate", fcntlFunc), + /* 93 */ SyscallDesc("ftruncate", unimplementedFunc), + /* 94 */ SyscallDesc("fchmod", unimplementedFunc), + /* 95 */ SyscallDesc("fchown", unimplementedFunc), + /* 96 */ SyscallDesc("getpriority", unimplementedFunc), + /* 97 */ SyscallDesc("setpriority", unimplementedFunc), + /* 98 */ SyscallDesc("profil", unimplementedFunc), + /* 99 */ SyscallDesc("statfs", unimplementedFunc), + /* 100 */ SyscallDesc("fstatfs", unimplementedFunc), + /* 101 */ SyscallDesc("ioperm", unimplementedFunc), + /* 102 */ SyscallDesc("socketcall", unimplementedFunc), + /* 103 */ SyscallDesc("syslog", unimplementedFunc), + /* 104 */ SyscallDesc("setitimer", unimplementedFunc), + /* 105 */ SyscallDesc("getitimer", unimplementedFunc), + /* 106 */ SyscallDesc("stat", statFunc<MipsLinux>), + /* 107 */ SyscallDesc("lstat", unimplementedFunc), + /* 108 */ SyscallDesc("fstat", fstatFunc<MipsLinux>), + /* 109 */ SyscallDesc("unused#109", unimplementedFunc), + /* 110 */ SyscallDesc("iopl", unimplementedFunc), + /* 111 */ SyscallDesc("vhangup", unimplementedFunc), + /* 112 */ SyscallDesc("idle", ignoreFunc), + /* 113 */ SyscallDesc("vm86", unimplementedFunc), + /* 114 */ SyscallDesc("wait4", unimplementedFunc), + /* 115 */ SyscallDesc("swapoff", unimplementedFunc), + /* 116 */ SyscallDesc("sysinfo", unimplementedFunc), + /* 117 */ SyscallDesc("ipc", unimplementedFunc), + /* 118 */ SyscallDesc("fsync", unimplementedFunc), + /* 119 */ SyscallDesc("sigreturn", unimplementedFunc), + /* 120 */ SyscallDesc("clone", unimplementedFunc), + /* 121 */ SyscallDesc("setdomainname", unimplementedFunc), + /* 122 */ SyscallDesc("uname", unameFunc), + /* 123 */ SyscallDesc("modify_ldt", unimplementedFunc), + /* 124 */ SyscallDesc("adjtimex", unimplementedFunc), + /* 125 */ SyscallDesc("mprotect", ignoreFunc), + /* 126 */ SyscallDesc("sigprocmask", unimplementedFunc), + /* 127 */ SyscallDesc("create_module", unimplementedFunc), + /* 128 */ SyscallDesc("init_module", unimplementedFunc), + /* 129 */ SyscallDesc("delete_module", unimplementedFunc), + /* 130 */ SyscallDesc("get_kernel_syms", unimplementedFunc), + /* 131 */ SyscallDesc("quotactl", unimplementedFunc), + /* 132 */ SyscallDesc("getpgid", unimplementedFunc), + /* 133 */ SyscallDesc("fchdir", unimplementedFunc), + /* 134 */ SyscallDesc("bdflush", unimplementedFunc), + /* 135 */ SyscallDesc("sysfs", unimplementedFunc), + /* 136 */ SyscallDesc("personality", unimplementedFunc), + /* 137 */ SyscallDesc("afs_syscall", unimplementedFunc), + /* 138 */ SyscallDesc("setfsuid", unimplementedFunc), + /* 139 */ SyscallDesc("setfsgid", unimplementedFunc), + /* 140 */ SyscallDesc("llseek", unimplementedFunc), + /* 141 */ SyscallDesc("getdents", unimplementedFunc), + /* 142 */ SyscallDesc("newselect", unimplementedFunc), + /* 143 */ SyscallDesc("flock", unimplementedFunc), + /* 144 */ SyscallDesc("msync", unimplementedFunc),/*getrlimitFunc<MipsLinux>*/ + /* 145 */ SyscallDesc("readv", unimplementedFunc), + /* 146 */ SyscallDesc("writev", writevFunc<MipsLinux>), + /* 147 */ SyscallDesc("cacheflush", unimplementedFunc), + /* 148 */ SyscallDesc("cachectl", unimplementedFunc), + /* 149 */ SyscallDesc("sysmips", unimplementedFunc), + /* 150 */ SyscallDesc("unused#150", unimplementedFunc), + /* 151 */ SyscallDesc("getsid", unimplementedFunc), + /* 152 */ SyscallDesc("fdatasync", unimplementedFunc), + /* 153 */ SyscallDesc("sysctl", unimplementedFunc), + /* 154 */ SyscallDesc("mlock", unimplementedFunc), + /* 155 */ SyscallDesc("munlock", unimplementedFunc), + /* 156 */ SyscallDesc("mlockall", unimplementedFunc), + /* 157 */ SyscallDesc("munlockall", unimplementedFunc), + /* 158 */ SyscallDesc("sched_setparam", unimplementedFunc), + /* 159 */ SyscallDesc("sched_getparam", unimplementedFunc), + /* 160 */ SyscallDesc("sched_setscheduler", unimplementedFunc), + /* 161 */ SyscallDesc("sched_getscheduler", unimplementedFunc), + /* 162 */ SyscallDesc("sched_yield", unimplementedFunc), + /* 163 */ SyscallDesc("sched_get_prioritymax", unimplementedFunc), + /* 164 */ SyscallDesc("sched_get_priority_min", unimplementedFunc), + /* 165 */ SyscallDesc("sched_rr_get_interval", unimplementedFunc), + /* 166 */ SyscallDesc("nanosleep", unimplementedFunc), + /* 167 */ SyscallDesc("mremap", unimplementedFunc), + /* 168 */ SyscallDesc("accept", unimplementedFunc), + /* 169 */ SyscallDesc("bind", unimplementedFunc), + /* 170 */ SyscallDesc("connect", unimplementedFunc), + /* 171 */ SyscallDesc("getpeername", unimplementedFunc), + /* 172 */ SyscallDesc("getsockname", unimplementedFunc), + /* 173 */ SyscallDesc("getsockopt", unimplementedFunc), + /* 174 */ SyscallDesc("listen", unimplementedFunc), + /* 175 */ SyscallDesc("recv", unimplementedFunc), + /* 176 */ SyscallDesc("recvmsg", unimplementedFunc), + /* 177 */ SyscallDesc("send", unimplementedFunc), + /* 178 */ SyscallDesc("sendmsg", ignoreFunc), + /* 179 */ SyscallDesc("sendto", unimplementedFunc), + /* 180 */ SyscallDesc("setsockopt", unimplementedFunc), + /* 181 */ SyscallDesc("shutdown", unimplementedFunc), + /* 182 */ SyscallDesc("unknown #182", unimplementedFunc), + /* 183 */ SyscallDesc("socket", ignoreFunc), + /* 184 */ SyscallDesc("socketpair", unimplementedFunc), + /* 185 */ SyscallDesc("setresuid", unimplementedFunc), + /* 186 */ SyscallDesc("getresuid", unimplementedFunc), + /* 187 */ SyscallDesc("query_module", unimplementedFunc), + /* 188 */ SyscallDesc("poll", unimplementedFunc), + /* 189 */ SyscallDesc("nfsservctl", unimplementedFunc), + /* 190 */ SyscallDesc("setresgid", unimplementedFunc), + /* 191 */ SyscallDesc("getresgid", unimplementedFunc), + /* 192 */ SyscallDesc("prctl", unimplementedFunc), + /* 193 */ SyscallDesc("rt_sigreturn", unimplementedFunc), + /* 194 */ SyscallDesc("rt_sigaction", ignoreFunc), + /* 195 */ SyscallDesc("rt_sigprocmask", ignoreFunc), + /* 196 */ SyscallDesc("rt_sigpending", unimplementedFunc), + /* 197 */ SyscallDesc("rt_sigtimedwait", unimplementedFunc), + /* 198 */ SyscallDesc("rt_sigqueueinfo", ignoreFunc), + /* 199 */ SyscallDesc("rt_sigsuspend", unimplementedFunc), + /* 200 */ SyscallDesc("pread64", unimplementedFunc), + /* 201 */ SyscallDesc("pwrite64", unimplementedFunc), + /* 202 */ SyscallDesc("chown", unimplementedFunc), + /* 203 */ SyscallDesc("getcwd", unimplementedFunc), + /* 204 */ SyscallDesc("capget", unimplementedFunc), + /* 205 */ SyscallDesc("capset", unimplementedFunc), + /* 206 */ SyscallDesc("sigalstack", unimplementedFunc), + /* 207 */ SyscallDesc("sendfile", unimplementedFunc), + /* 208 */ SyscallDesc("getpmsg", unimplementedFunc), + /* 209 */ SyscallDesc("putpmsg", unimplementedFunc), + /* 210 */ SyscallDesc("mmap2", unimplementedFunc), + /* 211 */ SyscallDesc("truncate64", unimplementedFunc), + /* 212 */ SyscallDesc("ftruncate64", unimplementedFunc), + /* 213 */ SyscallDesc("stat64", unimplementedFunc), + /* 214 */ SyscallDesc("lstat64", lstat64Func<MipsLinux>), + /* 215 */ SyscallDesc("fstat64", fstat64Func<MipsLinux>), + /* 216 */ SyscallDesc("pivot_root", unimplementedFunc), + /* 217 */ SyscallDesc("mincore", unimplementedFunc), + /* 218 */ SyscallDesc("madvise", unimplementedFunc), + /* 219 */ SyscallDesc("getdents64", unimplementedFunc), + /* 220 */ SyscallDesc("fcntl64", fcntlFunc), + /* 221 */ SyscallDesc("reserved#221", unimplementedFunc), + /* 222 */ SyscallDesc("gettid", unimplementedFunc), + /* 223 */ SyscallDesc("readahead", unimplementedFunc), + /* 224 */ SyscallDesc("setxattr", unimplementedFunc), + /* 225 */ SyscallDesc("lsetxattr", unimplementedFunc), + /* 226 */ SyscallDesc("fsetxattr", unimplementedFunc), + /* 227 */ SyscallDesc("getxattr", unimplementedFunc), + /* 228 */ SyscallDesc("lgetxattr", unimplementedFunc), + /* 229 */ SyscallDesc("fgetxattr", unimplementedFunc), + /* 230 */ SyscallDesc("listxattr", unimplementedFunc), + /* 231 */ SyscallDesc("llistxattr", unimplementedFunc), + /* 232 */ SyscallDesc("flistxattr", unimplementedFunc), + /* 233 */ SyscallDesc("removexattr", unimplementedFunc), + /* 234 */ SyscallDesc("lremovexattr", unimplementedFunc), + /* 235 */ SyscallDesc("fremovexattr", ignoreFunc), + /* 236 */ SyscallDesc("tkill", unimplementedFunc), + /* 237 */ SyscallDesc("sendfile64", unimplementedFunc), + /* 238 */ SyscallDesc("futex", unimplementedFunc), + /* 239 */ SyscallDesc("sched_setaffinity", unimplementedFunc), + /* 240 */ SyscallDesc("sched_getaffinity", unimplementedFunc), + /* 241 */ SyscallDesc("io_setup", unimplementedFunc), + /* 242 */ SyscallDesc("io_destroy", unimplementedFunc), + /* 243 */ SyscallDesc("io_getevents", unimplementedFunc), + /* 244 */ SyscallDesc("io_submit", unimplementedFunc), + /* 245 */ SyscallDesc("io_cancel", unimplementedFunc), + /* 246 */ SyscallDesc("exit_group", exitFunc), + /* 247 */ SyscallDesc("lookup_dcookie", unimplementedFunc), + /* 248 */ SyscallDesc("epoll_create", unimplementedFunc), + /* 249 */ SyscallDesc("epoll_ctl", unimplementedFunc), + /* 250 */ SyscallDesc("epoll_wait", unimplementedFunc), + /* 251 */ SyscallDesc("remap_file_pages", unimplementedFunc), + /* 252 */ SyscallDesc("set_tid_address", unimplementedFunc), + /* 253 */ SyscallDesc("restart_syscall", unimplementedFunc), + /* 254 */ SyscallDesc("fadvise64", unimplementedFunc), + /* 255 */ SyscallDesc("statfs64", unimplementedFunc), + /* 256 */ SyscallDesc("fstafs64", unimplementedFunc), + /* 257 */ SyscallDesc("timer_create", sys_getsysinfoFunc), + /* 258 */ SyscallDesc("timer_settime", sys_setsysinfoFunc), + /* 259 */ SyscallDesc("timer_gettime", unimplementedFunc), + /* 260 */ SyscallDesc("timer_getoverrun", unimplementedFunc), + /* 261 */ SyscallDesc("timer_delete", unimplementedFunc), + /* 262 */ SyscallDesc("clock_settime", unimplementedFunc), + /* 263 */ SyscallDesc("clock_gettime", unimplementedFunc), + /* 264 */ SyscallDesc("clock_getres", unimplementedFunc), + /* 265 */ SyscallDesc("clock_nanosleep", unimplementedFunc), + /* 266 */ SyscallDesc("tgkill", unimplementedFunc), + /* 267 */ SyscallDesc("utimes", unimplementedFunc), + /* 268 */ SyscallDesc("mbind", unimplementedFunc), + /* 269 */ SyscallDesc("get_mempolicy", unimplementedFunc), + /* 270 */ SyscallDesc("set_mempolicy", unimplementedFunc), + /* 271 */ SyscallDesc("mq_open", unimplementedFunc), + /* 272 */ SyscallDesc("mq_unlink", unimplementedFunc), + /* 273 */ SyscallDesc("mq_timedsend", unimplementedFunc), + /* 274 */ SyscallDesc("mq_timedreceive", unimplementedFunc), + /* 275 */ SyscallDesc("mq_notify", unimplementedFunc), + /* 276 */ SyscallDesc("mq_getsetattr", unimplementedFunc), + /* 277 */ SyscallDesc("vserver", unimplementedFunc), + /* 278 */ SyscallDesc("waitid", unimplementedFunc), + /* 279 */ SyscallDesc("unknown #279", unimplementedFunc), + /* 280 */ SyscallDesc("add_key", unimplementedFunc), + /* 281 */ SyscallDesc("request_key", unimplementedFunc), + /* 282 */ SyscallDesc("keyctl", unimplementedFunc), +}; + +MipsLinuxProcess::MipsLinuxProcess(const std::string &name, + ObjectFile *objFile, + System *system, + int stdin_fd, + int stdout_fd, + int stderr_fd, + std::vector<std::string> &argv, + std::vector<std::string> &envp) + : MipsLiveProcess(name, objFile, system, stdin_fd, stdout_fd, stderr_fd, + argv, envp), + Num_Syscall_Descs(sizeof(syscallDescs) / sizeof(SyscallDesc)) +{ + //init_regs->intRegFile[0] = 0; +} + +SyscallDesc* +MipsLinuxProcess::getDesc(int callnum) +{ + //MIPS32 syscalls are in the range of 4000 - 4999 + int m5_sys_idx = callnum - 4000; + + if (m5_sys_idx < 0 || m5_sys_idx > Num_Syscall_Descs) + return NULL; + + return &syscallDescs[m5_sys_idx]; +} diff --git a/src/arch/mips/linux/process.hh b/src/arch/mips/linux/process.hh new file mode 100644 index 000000000..68da3227b --- /dev/null +++ b/src/arch/mips/linux/process.hh @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2003-2004 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MIPS_LINUX_PROCESS_HH__ +#define __MIPS_LINUX_PROCESS_HH__ + +#include "arch/mips/process.hh" + + +/// A process with emulated Mips/Linux syscalls. +class MipsLinuxProcess : public MipsLiveProcess +{ + public: + /// Constructor. + MipsLinuxProcess(const std::string &name, + ObjectFile *objFile, + System *system, + int stdin_fd, int stdout_fd, int stderr_fd, + std::vector<std::string> &argv, + std::vector<std::string> &envp); + + virtual SyscallDesc* getDesc(int callnum); + + /// The target system's hostname. + static const char *hostname; + + /// Array of syscall descriptors, indexed by call number. + static SyscallDesc syscallDescs[]; + + const int Num_Syscall_Descs; +}; + + +#endif // __MIPS_LINUX_PROCESS_HH__ diff --git a/src/arch/mips/process.cc b/src/arch/mips/process.cc new file mode 100644 index 000000000..7831551be --- /dev/null +++ b/src/arch/mips/process.cc @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2003-2004 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "arch/mips/isa_traits.hh" +#include "arch/mips/process.hh" +#include "arch/mips/linux/process.hh" +#include "base/loader/object_file.hh" +#include "base/misc.hh" +#include "cpu/exec_context.hh" +#include "sim/builder.hh" +#include "sim/system.hh" + +using namespace std; +using namespace MipsISA; + + +MipsLiveProcess * +MipsLiveProcess::create(const std::string &nm, System *system, int stdin_fd, + int stdout_fd, int stderr_fd, std::string executable, + std::vector<std::string> &argv, std::vector<std::string> &envp) +{ + MipsLiveProcess *process = NULL; + + ObjectFile *objFile = createObjectFile(executable); + if (objFile == NULL) { + fatal("Can't load object file %s", executable); + } + + + if (objFile->getArch() != ObjectFile::Mips) + fatal("Object file does not match architecture."); + switch (objFile->getOpSys()) { + case ObjectFile::Linux: + process = new MipsLinuxProcess(nm, objFile, system, + stdin_fd, stdout_fd, stderr_fd, + argv, envp); + break; + + default: + fatal("Unknown/unsupported operating system."); + } + + if (process == NULL) + fatal("Unknown error creating process object."); + return process; +} + +MipsLiveProcess::MipsLiveProcess(const std::string &nm, ObjectFile *objFile, + System *_system, int stdin_fd, int stdout_fd, int stderr_fd, + std::vector<std::string> &argv, std::vector<std::string> &envp) + : LiveProcess(nm, objFile, _system, stdin_fd, stdout_fd, stderr_fd, + argv, envp) +{ + + // XXX all the below need to be updated for SPARC - Ali + brk_point = objFile->dataBase() + objFile->dataSize() + objFile->bssSize(); + brk_point = roundUp(brk_point, VMPageSize); + + // Set up stack. On Alpha, stack goes below text section. This + // code should get moved to some architecture-specific spot. + stack_base = objFile->textBase() - (409600+4096); + + // Set up region for mmaps. Tru64 seems to start just above 0 and + // grow up from there. + mmap_start = mmap_end = 0x10000; + + // Set pointer for next thread stack. Reserve 8M for main stack. + next_thread_stack_base = stack_base - (8 * 1024 * 1024); + +} + +void +MipsLiveProcess::startup() +{ + argsInit(MachineBytes, VMPageSize); +} + + + + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(MipsLiveProcess) + + VectorParam<string> cmd; + Param<string> executable; + Param<string> input; + Param<string> output; + VectorParam<string> env; + SimObjectParam<System *> system; + +END_DECLARE_SIM_OBJECT_PARAMS(MipsLiveProcess) + + +BEGIN_INIT_SIM_OBJECT_PARAMS(MipsLiveProcess) + + INIT_PARAM(cmd, "command line (executable plus arguments)"), + INIT_PARAM(executable, "executable (overrides cmd[0] if set)"), + INIT_PARAM(input, "filename for stdin (dflt: use sim stdin)"), + INIT_PARAM(output, "filename for stdout/stderr (dflt: use sim stdout)"), + INIT_PARAM(env, "environment settings"), + INIT_PARAM(system, "system") + +END_INIT_SIM_OBJECT_PARAMS(MipsLiveProcess) + + +CREATE_SIM_OBJECT(MipsLiveProcess) +{ + string in = input; + string out = output; + + // initialize file descriptors to default: same as simulator + int stdin_fd, stdout_fd, stderr_fd; + + if (in == "stdin" || in == "cin") + stdin_fd = STDIN_FILENO; + else + stdin_fd = Process::openInputFile(input); + + if (out == "stdout" || out == "cout") + stdout_fd = STDOUT_FILENO; + else if (out == "stderr" || out == "cerr") + stdout_fd = STDERR_FILENO; + else + stdout_fd = Process::openOutputFile(out); + + stderr_fd = (stdout_fd != STDOUT_FILENO) ? stdout_fd : STDERR_FILENO; + + return MipsLiveProcess::create(getInstanceName(), system, + stdin_fd, stdout_fd, stderr_fd, + (string)executable == "" ? cmd[0] : executable, + cmd, env); +} + + +REGISTER_SIM_OBJECT("MipsLiveProcess", MipsLiveProcess) + + diff --git a/src/arch/mips/process.hh b/src/arch/mips/process.hh new file mode 100644 index 000000000..2a13dc955 --- /dev/null +++ b/src/arch/mips/process.hh @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2003-2004 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MIPS_PROCESS_HH__ +#define __MIPS_PROCESS_HH__ + +#include <string> +#include <vector> +#include "sim/process.hh" + +class LiveProcess; +class ObjectFile; +class System; + +class MipsLiveProcess : public LiveProcess +{ + protected: + MipsLiveProcess(const std::string &nm, ObjectFile *objFile, + System *_system, int stdin_fd, int stdout_fd, int stderr_fd, + std::vector<std::string> &argv, + std::vector<std::string> &envp); + + void startup(); + + public: + // this function is used to create the LiveProcess object, since + // we can't tell which subclass of LiveProcess to use until we + // open and look at the object file. + static MipsLiveProcess *create(const std::string &nm, + System *_system, + int stdin_fd, int stdout_fd, int stderr_fd, + std::string executable, + std::vector<std::string> &argv, + std::vector<std::string> &envp); + +}; + + +#endif // __MIPS_PROCESS_HH__ diff --git a/src/arch/mips/regfile/float_regfile.hh b/src/arch/mips/regfile/float_regfile.hh new file mode 100644 index 000000000..15c6f97f4 --- /dev/null +++ b/src/arch/mips/regfile/float_regfile.hh @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ARCH_MIPS_FLOAT_REGFILE_HH__ +#define __ARCH_MIPS_FLOAT_REGFILE_HH__ + +#include "arch/mips/types.hh" +#include "arch/mips/constants.hh" +#include "base/misc.hh" +#include "config/full_system.hh" +#include "sim/byteswap.hh" +#include "sim/faults.hh" +#include "sim/host.hh" + +class Checkpoint; +class ExecContext; +class Regfile; + +namespace MipsISA +{ + class FloatRegFile + { + protected: + FloatReg32 regs[NumFloatRegs]; + + public: + + void clear() + { + bzero(regs, sizeof(regs)); + } + + double readReg(int floatReg, int width) + { + switch(width) + { + case SingleWidth: + void *float_ptr = ®s[floatReg]; + return *(float *) float_ptr; + + case DoubleWidth: + uint64_t double_val = (FloatReg64)regs[floatReg + 1] << 32 | regs[floatReg]; + void *double_ptr = &double_val; + return *(double *) double_ptr; + + default: + panic("Attempted to read a %d bit floating point register!", width); + } + } + + FloatRegBits readRegBits(int floatReg, int width) + { + if (floatReg < NumFloatArchRegs - 1) { + switch(width) + { + case SingleWidth: + return regs[floatReg]; + + case DoubleWidth: + return (FloatReg64)regs[floatReg + 1] << 32 | regs[floatReg]; + + default: + panic("Attempted to read a %d bit floating point register!", width); + } + } else { + if (width > SingleWidth) + assert("Control Regs are only 32 bits wide"); + + return regs[floatReg]; + } + } + + Fault setReg(int floatReg, const FloatReg &val, int width) + { + + switch(width) + { + case SingleWidth: + float temp = val; + void *float_ptr = &temp; + regs[floatReg] = *(FloatReg32 *) float_ptr; + break; + + case DoubleWidth: + const void *double_ptr = &val; + FloatReg64 temp_double = *(FloatReg64 *) double_ptr; + regs[floatReg + 1] = temp_double >> 32; + regs[floatReg] = temp_double; + break; + + default: + panic("Attempted to read a %d bit floating point register!", width); + } + + return NoFault; + } + + Fault setRegBits(int floatReg, const FloatRegBits &val, int width) + { + using namespace std; + + switch(width) + { + case SingleWidth: + regs[floatReg] = val; + break; + + case DoubleWidth: + regs[floatReg + 1] = val >> 32; + regs[floatReg] = val; + break; + + default: + panic("Attempted to read a %d bit floating point register!", width); + } + return NoFault; + } + + void serialize(std::ostream &os); + + void unserialize(Checkpoint *cp, const std::string §ion); + }; + + enum MiscFloatRegNums { + FIR = NumFloatArchRegs, + FCCR, + FEXR, + FENR, + FCSR + }; + +} // namespace MipsISA + +#endif diff --git a/src/arch/mips/regfile/int_regfile.hh b/src/arch/mips/regfile/int_regfile.hh new file mode 100644 index 000000000..3cd87734d --- /dev/null +++ b/src/arch/mips/regfile/int_regfile.hh @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ARCH_MIPS_INT_REGFILE_HH__ +#define __ARCH_MIPS_INT_REGFILE_HH__ + +#include "arch/mips/types.hh" +#include "arch/mips/constants.hh" +#include "base/misc.hh" +#include "sim/faults.hh" + +class Checkpoint; +class ExecContext; +class Regfile; + +namespace MipsISA +{ + class IntRegFile + { + protected: + IntReg regs[NumIntRegs]; + + public: + IntReg readReg(int intReg) + { + return regs[intReg]; + } + + Fault setReg(int intReg, const IntReg &val) + { + regs[intReg] = val; + return NoFault; + } + + void serialize(std::ostream &os); + + void unserialize(Checkpoint *cp, const std::string §ion); + + }; + + enum MiscIntRegNums { + HI = NumIntArchRegs, + LO + }; + +} // namespace MipsISA + +#endif diff --git a/src/arch/mips/regfile/misc_regfile.hh b/src/arch/mips/regfile/misc_regfile.hh new file mode 100644 index 000000000..9f054e5f7 --- /dev/null +++ b/src/arch/mips/regfile/misc_regfile.hh @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ARCH_MIPS_MISC_REGFILE_HH__ +#define __ARCH_MIPS_MISC_REGFILE_HH__ + +#include "arch/mips/types.hh" +#include "arch/mips/constants.hh" +#include "sim/faults.hh" + +class Checkpoint; +class ExecContext; +class Regfile; + +namespace MipsISA +{ + class MiscRegFile { + + protected: + uint64_t fpcr; // floating point condition codes + uint64_t uniq; // process-unique register + bool lock_flag; // lock flag for LL/SC + Addr lock_addr; // lock address for LL/SC + + MiscReg miscRegFile[NumMiscRegs]; + + public: + //These functions should be removed once the simplescalar cpu model + //has been replaced. + int getInstAsid(); + int getDataAsid(); + + void copyMiscRegs(ExecContext *xc); + + MiscReg readReg(int misc_reg) + { + return miscRegFile[misc_reg]; + } + + MiscReg readRegWithEffect(int misc_reg, Fault &fault, ExecContext *xc) + { + return miscRegFile[misc_reg]; + } + + Fault setReg(int misc_reg, const MiscReg &val) + { + miscRegFile[misc_reg] = val; return NoFault; + } + + Fault setRegWithEffect(int misc_reg, const MiscReg &val, + ExecContext *xc) + { + miscRegFile[misc_reg] = val; return NoFault; + } + +#if FULL_SYSTEM + void clearIprs() { } + + protected: + InternalProcReg ipr[NumInternalProcRegs]; // Internal processor regs + + private: + MiscReg readIpr(int idx, Fault &fault, ExecContext *xc) { } + + Fault setIpr(int idx, uint64_t val, ExecContext *xc) { } +#endif + friend class RegFile; + }; +} // namespace MipsISA + +#endif diff --git a/src/arch/mips/regfile/regfile.hh b/src/arch/mips/regfile/regfile.hh new file mode 100644 index 000000000..e77571b33 --- /dev/null +++ b/src/arch/mips/regfile/regfile.hh @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ARCH_MIPS_REGFILE_HH__ +#define __ARCH_MIPS_REGFILE_HH__ + +#include "arch/mips/types.hh" +#include "arch/mips/constants.hh" +#include "arch/mips/regfile/int_regfile.hh" +#include "arch/mips/regfile/float_regfile.hh" +#include "arch/mips/regfile/misc_regfile.hh" +#include "sim/faults.hh" + +class Checkpoint; +class ExecContext; + +namespace MipsISA +{ + class RegFile { + protected: + IntRegFile intRegFile; // (signed) integer register file + FloatRegFile floatRegFile; // floating point register file + MiscRegFile miscRegFile; // control register file + + public: + + void clear() + { + bzero(&intRegFile, sizeof(intRegFile)); + bzero(&floatRegFile, sizeof(floatRegFile)); + bzero(&miscRegFile, sizeof(miscRegFile)); + } + + MiscReg readMiscReg(int miscReg) + { + return miscRegFile.readReg(miscReg); + } + + MiscReg readMiscRegWithEffect(int miscReg, + Fault &fault, ExecContext *xc) + { + fault = NoFault; + return miscRegFile.readRegWithEffect(miscReg, fault, xc); + } + + Fault setMiscReg(int miscReg, const MiscReg &val) + { + return miscRegFile.setReg(miscReg, val); + } + + Fault setMiscRegWithEffect(int miscReg, const MiscReg &val, + ExecContext * xc) + { + return miscRegFile.setRegWithEffect(miscReg, val, xc); + } + + FloatReg readFloatReg(int floatReg) + { + return floatRegFile.readReg(floatReg,SingleWidth); + } + + FloatReg readFloatReg(int floatReg, int width) + { + return floatRegFile.readReg(floatReg,width); + } + + FloatRegBits readFloatRegBits(int floatReg) + { + return floatRegFile.readRegBits(floatReg,SingleWidth); + } + + FloatRegBits readFloatRegBits(int floatReg, int width) + { + return floatRegFile.readRegBits(floatReg,width); + } + + Fault setFloatReg(int floatReg, const FloatReg &val) + { + return floatRegFile.setReg(floatReg, val, SingleWidth); + } + + Fault setFloatReg(int floatReg, const FloatReg &val, int width) + { + return floatRegFile.setReg(floatReg, val, width); + } + + Fault setFloatRegBits(int floatReg, const FloatRegBits &val) + { + return floatRegFile.setRegBits(floatReg, val, SingleWidth); + } + + Fault setFloatRegBits(int floatReg, const FloatRegBits &val, int width) + { + return floatRegFile.setRegBits(floatReg, val, width); + } + + IntReg readIntReg(int intReg) + { + return intRegFile.readReg(intReg); + } + + Fault setIntReg(int intReg, const IntReg &val) + { + return intRegFile.setReg(intReg, val); + } + protected: + + Addr pc; // program counter + Addr npc; // next-cycle program counter + Addr nnpc; // next-next-cycle program counter + // used to implement branch delay slot + // not real register + public: + Addr readPC() + { + return pc; + } + + void setPC(Addr val) + { + pc = val; + } + + Addr readNextPC() + { + return npc; + } + + void setNextPC(Addr val) + { + npc = val; + } + + Addr readNextNPC() + { + return nnpc; + } + + void setNextNPC(Addr val) + { + nnpc = val; + } + + +#if FULL_SYSTEM + IntReg palregs[NumIntRegs]; // PAL shadow registers + InternalProcReg ipr[NumInternalProcRegs]; // internal processor regs + int intrflag; // interrupt flag + bool pal_shadow; // using pal_shadow registers + inline int instAsid() { return MIPS34K::ITB_ASN_ASN(ipr[IPR_ITB_ASN]); } + inline int dataAsid() { return MIPS34K::DTB_ASN_ASN(ipr[IPR_DTB_ASN]); } +#endif // FULL_SYSTEM + + void serialize(std::ostream &os); + void unserialize(Checkpoint *cp, const std::string §ion); + + typedef int ContextParam; + typedef int ContextVal; + + void changeContext(ContextParam param, ContextVal val) + { + } + }; + + void copyRegs(ExecContext *src, ExecContext *dest); + + void copyMiscRegs(ExecContext *src, ExecContext *dest); + +#if FULL_SYSTEM + void copyIprs(ExecContext *src, ExecContext *dest); +#endif +} // namespace MipsISA + +#endif diff --git a/arch/mips/stacktrace.hh b/src/arch/mips/stacktrace.hh index 1d8d97a79..1d8d97a79 100644 --- a/arch/mips/stacktrace.hh +++ b/src/arch/mips/stacktrace.hh diff --git a/src/arch/mips/types.hh b/src/arch/mips/types.hh new file mode 100644 index 000000000..4d5fb3456 --- /dev/null +++ b/src/arch/mips/types.hh @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ARCH_MIPS_TYPES_HH__ +#define __ARCH_MIPS_TYPES_HH__ + +#include "sim/host.hh" + +namespace MipsISA +{ + typedef uint32_t MachInst; + typedef uint64_t ExtMachInst; + typedef uint8_t RegIndex; + + typedef uint32_t IntReg; + + // floating point register file entry type + typedef double FloatReg; + typedef uint32_t FloatReg32; + typedef uint64_t FloatReg64; + typedef uint64_t FloatRegBits; + + // cop-0/cop-1 system control register + typedef uint64_t MiscReg; + typedef uint64_t InternalProcReg; + + typedef union { + IntReg intreg; + FloatReg fpreg; + MiscReg ctrlreg; + } AnyReg; + + //used in FP convert & round function + enum ConvertType{ + SINGLE_TO_DOUBLE, + SINGLE_TO_WORD, + SINGLE_TO_LONG, + + DOUBLE_TO_SINGLE, + DOUBLE_TO_WORD, + DOUBLE_TO_LONG, + + LONG_TO_SINGLE, + LONG_TO_DOUBLE, + LONG_TO_WORD, + LONG_TO_PS, + + WORD_TO_SINGLE, + WORD_TO_DOUBLE, + WORD_TO_LONG, + WORD_TO_PS, + + PL_TO_SINGLE, + PU_TO_SINGLE + }; + + //used in FP convert & round function + enum RoundMode{ + RND_ZERO, + RND_DOWN, + RND_UP, + RND_NEAREST + }; + +} // namespace MipsISA + +#endif diff --git a/src/arch/mips/utility.hh b/src/arch/mips/utility.hh new file mode 100644 index 000000000..5c7dc3ea4 --- /dev/null +++ b/src/arch/mips/utility.hh @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Nathan Binkert + * Steve Reinhardt + */ + +#ifndef __ARCH_MIPS_UTILITY_HH__ +#define __ARCH_MIPS_UTILITY_HH__ + +#include "arch/mips/types.hh" +#include "arch/mips/constants.hh" +#include "base/misc.hh" +#include "sim/host.hh" + +namespace MipsISA { + +}; + +#endif diff --git a/src/arch/sparc/SConscript b/src/arch/sparc/SConscript new file mode 100644 index 000000000..66435c239 --- /dev/null +++ b/src/arch/sparc/SConscript @@ -0,0 +1,80 @@ +# -*- mode:python -*- + +# Copyright (c) 2004-2005 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +import os +import sys +from os.path import isdir + +# Import build environment variable from SConstruct. +Import('env') + +################################################### +# +# Define needed sources. +# +################################################### + +# Base sources used by all configurations. +base_sources = Split(''' + faults.cc + isa_traits.cc + ''') + +# Full-system sources +full_system_sources = Split(''' + vtophys.cc + ua2005.cc + ''') + +# Syscall emulation (non-full-system) sources +syscall_emulation_sources = Split(''' + linux/linux.cc + linux/process.cc + solaris/solaris.cc + solaris/process.cc + process.cc + ''') + +sources = base_sources + +if env['FULL_SYSTEM']: + sources += full_system_sources +else: + sources += syscall_emulation_sources + +# Convert file names to SCons File objects. This takes care of the +# path relative to the top of the directory tree. +sources = [File(s) for s in sources] + +# Add in files generated by the ISA description. +isa_desc_files = env.ISADesc('isa/main.isa') +# Only non-header files need to be compiled. +isa_desc_sources = [f for f in isa_desc_files if not f.path.endswith('.hh')] +sources += isa_desc_sources + +Return('sources') diff --git a/src/arch/sparc/faults.cc b/src/arch/sparc/faults.cc new file mode 100644 index 000000000..67a89ab0e --- /dev/null +++ b/src/arch/sparc/faults.cc @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "arch/sparc/faults.hh" +#include "cpu/exec_context.hh" +#include "cpu/base.hh" +#include "base/trace.hh" + +namespace SparcISA +{ + +FaultName InternalProcessorError::_name = "intprocerr"; +TrapType InternalProcessorError::_trapType = 0x029; +FaultPriority InternalProcessorError::_priority = 4; +FaultStat InternalProcessorError::_count; + +FaultName MemAddressNotAligned::_name = "unalign"; +TrapType MemAddressNotAligned::_trapType = 0x034; +FaultPriority MemAddressNotAligned::_priority = 10; +FaultStat MemAddressNotAligned::_count; + +FaultName PowerOnReset::_name = "pow_reset"; +TrapType PowerOnReset::_trapType = 0x001; +FaultPriority PowerOnReset::_priority = 0; +FaultStat PowerOnReset::_count; + +FaultName WatchDogReset::_name = "watch_dog_reset"; +TrapType WatchDogReset::_trapType = 0x002; +FaultPriority WatchDogReset::_priority = 1; +FaultStat WatchDogReset::_count; + +FaultName ExternallyInitiatedReset::_name = "extern_reset"; +TrapType ExternallyInitiatedReset::_trapType = 0x003; +FaultPriority ExternallyInitiatedReset::_priority = 1; +FaultStat ExternallyInitiatedReset::_count; + +FaultName SoftwareInitiatedReset::_name = "software_reset"; +TrapType SoftwareInitiatedReset::_trapType = 0x004; +FaultPriority SoftwareInitiatedReset::_priority = 1; +FaultStat SoftwareInitiatedReset::_count; + +FaultName REDStateException::_name = "red_counte"; +TrapType REDStateException::_trapType = 0x005; +FaultPriority REDStateException::_priority = 1; +FaultStat REDStateException::_count; + +FaultName InstructionAccessException::_name = "inst_access"; +TrapType InstructionAccessException::_trapType = 0x008; +FaultPriority InstructionAccessException::_priority = 5; +FaultStat InstructionAccessException::_count; + +FaultName InstructionAccessMMUMiss::_name = "inst_mmu"; +TrapType InstructionAccessMMUMiss::_trapType = 0x009; +FaultPriority InstructionAccessMMUMiss::_priority = 2; +FaultStat InstructionAccessMMUMiss::_count; + +FaultName InstructionAccessError::_name = "inst_error"; +TrapType InstructionAccessError::_trapType = 0x00A; +FaultPriority InstructionAccessError::_priority = 3; +FaultStat InstructionAccessError::_count; + +FaultName IllegalInstruction::_name = "illegal_inst"; +TrapType IllegalInstruction::_trapType = 0x010; +FaultPriority IllegalInstruction::_priority = 7; +FaultStat IllegalInstruction::_count; + +FaultName PrivilegedOpcode::_name = "priv_opcode"; +TrapType PrivilegedOpcode::_trapType = 0x011; +FaultPriority PrivilegedOpcode::_priority = 6; +FaultStat PrivilegedOpcode::_count; + +FaultName UnimplementedLDD::_name = "unimp_ldd"; +TrapType UnimplementedLDD::_trapType = 0x012; +FaultPriority UnimplementedLDD::_priority = 6; +FaultStat UnimplementedLDD::_count; + +FaultName UnimplementedSTD::_name = "unimp_std"; +TrapType UnimplementedSTD::_trapType = 0x013; +FaultPriority UnimplementedSTD::_priority = 6; +FaultStat UnimplementedSTD::_count; + +FaultName FpDisabled::_name = "fp_disabled"; +TrapType FpDisabled::_trapType = 0x020; +FaultPriority FpDisabled::_priority = 8; +FaultStat FpDisabled::_count; + +FaultName FpExceptionIEEE754::_name = "fp_754"; +TrapType FpExceptionIEEE754::_trapType = 0x021; +FaultPriority FpExceptionIEEE754::_priority = 11; +FaultStat FpExceptionIEEE754::_count; + +FaultName FpExceptionOther::_name = "fp_other"; +TrapType FpExceptionOther::_trapType = 0x022; +FaultPriority FpExceptionOther::_priority = 11; +FaultStat FpExceptionOther::_count; + +FaultName TagOverflow::_name = "tag_overflow"; +TrapType TagOverflow::_trapType = 0x023; +FaultPriority TagOverflow::_priority = 14; +FaultStat TagOverflow::_count; + +FaultName DivisionByZero::_name = "div_by_zero"; +TrapType DivisionByZero::_trapType = 0x028; +FaultPriority DivisionByZero::_priority = 15; +FaultStat DivisionByZero::_count; + +FaultName DataAccessException::_name = "data_access"; +TrapType DataAccessException::_trapType = 0x030; +FaultPriority DataAccessException::_priority = 12; +FaultStat DataAccessException::_count; + +FaultName DataAccessMMUMiss::_name = "data_mmu"; +TrapType DataAccessMMUMiss::_trapType = 0x031; +FaultPriority DataAccessMMUMiss::_priority = 12; +FaultStat DataAccessMMUMiss::_count; + +FaultName DataAccessError::_name = "data_error"; +TrapType DataAccessError::_trapType = 0x032; +FaultPriority DataAccessError::_priority = 12; +FaultStat DataAccessError::_count; + +FaultName DataAccessProtection::_name = "data_protection"; +TrapType DataAccessProtection::_trapType = 0x033; +FaultPriority DataAccessProtection::_priority = 12; +FaultStat DataAccessProtection::_count; + +FaultName LDDFMemAddressNotAligned::_name = "unalign_lddf"; +TrapType LDDFMemAddressNotAligned::_trapType = 0x035; +FaultPriority LDDFMemAddressNotAligned::_priority = 10; +FaultStat LDDFMemAddressNotAligned::_count; + +FaultName STDFMemAddressNotAligned::_name = "unalign_stdf"; +TrapType STDFMemAddressNotAligned::_trapType = 0x036; +FaultPriority STDFMemAddressNotAligned::_priority = 10; +FaultStat STDFMemAddressNotAligned::_count; + +FaultName PrivilegedAction::_name = "priv_action"; +TrapType PrivilegedAction::_trapType = 0x037; +FaultPriority PrivilegedAction::_priority = 11; +FaultStat PrivilegedAction::_count; + +FaultName LDQFMemAddressNotAligned::_name = "unalign_ldqf"; +TrapType LDQFMemAddressNotAligned::_trapType = 0x038; +FaultPriority LDQFMemAddressNotAligned::_priority = 10; +FaultStat LDQFMemAddressNotAligned::_count; + +FaultName STQFMemAddressNotAligned::_name = "unalign_stqf"; +TrapType STQFMemAddressNotAligned::_trapType = 0x039; +FaultPriority STQFMemAddressNotAligned::_priority = 10; +FaultStat STQFMemAddressNotAligned::_count; + +FaultName AsyncDataError::_name = "async_data"; +TrapType AsyncDataError::_trapType = 0x040; +FaultPriority AsyncDataError::_priority = 2; +FaultStat AsyncDataError::_count; + +FaultName CleanWindow::_name = "clean_win"; +TrapType CleanWindow::_trapType = 0x024; +FaultPriority CleanWindow::_priority = 10; +FaultStat CleanWindow::_count; + +//The enumerated faults + +FaultName InterruptLevelN::_name = "interrupt_n"; +TrapType InterruptLevelN::_baseTrapType = 0x041; +FaultStat InterruptLevelN::_count; + +FaultName SpillNNormal::_name = "spill_n_normal"; +TrapType SpillNNormal::_baseTrapType = 0x080; +FaultPriority SpillNNormal::_priority = 9; +FaultStat SpillNNormal::_count; + +FaultName SpillNOther::_name = "spill_n_other"; +TrapType SpillNOther::_baseTrapType = 0x0A0; +FaultPriority SpillNOther::_priority = 9; +FaultStat SpillNOther::_count; + +FaultName FillNNormal::_name = "fill_n_normal"; +TrapType FillNNormal::_baseTrapType = 0x0C0; +FaultPriority FillNNormal::_priority = 9; +FaultStat FillNNormal::_count; + +FaultName FillNOther::_name = "fill_n_other"; +TrapType FillNOther::_baseTrapType = 0x0E0; +FaultPriority FillNOther::_priority = 9; +FaultStat FillNOther::_count; + +FaultName TrapInstruction::_name = "trap_inst_n"; +TrapType TrapInstruction::_baseTrapType = 0x100; +FaultPriority TrapInstruction::_priority = 16; +FaultStat TrapInstruction::_count; + +#if FULL_SYSTEM + +void SparcFault::invoke(ExecContext * xc) +{ + FaultBase::invoke(xc); + countStat()++; + + //Use the SPARC trap state machine + /*// exception restart address + if (setRestartAddress() || !xc->inPalMode()) + xc->setMiscReg(AlphaISA::IPR_EXC_ADDR, xc->regs.pc); + + if (skipFaultingInstruction()) { + // traps... skip faulting instruction. + xc->setMiscReg(AlphaISA::IPR_EXC_ADDR, + xc->readMiscReg(AlphaISA::IPR_EXC_ADDR) + 4); + } + + if (!xc->inPalMode()) + AlphaISA::swap_palshadow(&(xc->regs), true); + + xc->regs.pc = xc->readMiscReg(AlphaISA::IPR_PAL_BASE) + vect(); + xc->regs.npc = xc->regs.pc + sizeof(MachInst);*/ +} + +#endif + +#if !FULL_SYSTEM + +void TrapInstruction::invoke(ExecContext * xc) +{ + xc->syscall(syscall_num); +} + +#endif + +} // namespace SparcISA + diff --git a/src/arch/sparc/faults.hh b/src/arch/sparc/faults.hh new file mode 100644 index 000000000..e8fb8dfc5 --- /dev/null +++ b/src/arch/sparc/faults.hh @@ -0,0 +1,591 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ALPHA_FAULTS_HH__ +#define __ALPHA_FAULTS_HH__ + +#include "sim/faults.hh" + +// The design of the "name" and "vect" functions is in sim/faults.hh + +namespace SparcISA +{ + +typedef const uint32_t TrapType; +typedef const uint32_t FaultPriority; + +class SparcFault : public FaultBase +{ + public: +#if FULL_SYSTEM + void invoke(ExecContext * xc); +#endif + virtual TrapType trapType() = 0; + virtual FaultPriority priority() = 0; + virtual FaultStat & countStat() = 0; +}; + +class InternalProcessorError : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} + bool isMachineCheckFault() {return true;} +}; + +class MemAddressNotAligned : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} + bool isAlignmentFault() {return true;} +}; + +static inline Fault genMachineCheckFault() +{ + return new InternalProcessorError; +} + +static inline Fault genAlignmentFault() +{ + return new MemAddressNotAligned; +} + +class PowerOnReset : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class WatchDogReset : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class ExternallyInitiatedReset : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class SoftwareInitiatedReset : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class REDStateException : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class InstructionAccessException : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class InstructionAccessMMUMiss : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class InstructionAccessError : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class IllegalInstruction : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class PrivilegedOpcode : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class UnimplementedLDD : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class UnimplementedSTD : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class FpDisabled : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class FpExceptionIEEE754 : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class FpExceptionOther : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class TagOverflow : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class DivisionByZero : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class DataAccessException : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class DataAccessMMUMiss : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class DataAccessError : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class DataAccessProtection : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class LDDFMemAddressNotAligned : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class STDFMemAddressNotAligned : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class PrivilegedAction : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class LDQFMemAddressNotAligned : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class STQFMemAddressNotAligned : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class AsyncDataError : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class CleanWindow : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class EnumeratedFault : public SparcFault +{ + protected: + uint32_t _n; + virtual TrapType baseTrapType() = 0; + public: + EnumeratedFault(uint32_t n) : SparcFault() {_n = n;} + TrapType trapType() {return baseTrapType() + _n;} +}; + +class InterruptLevelN : public EnumeratedFault +{ + private: + static FaultName _name; + static TrapType _baseTrapType; + static FaultStat _count; + TrapType baseTrapType() {return _baseTrapType;} + public: + InterruptLevelN(uint32_t n) : EnumeratedFault(n) {;} + FaultName name() {return _name;} + FaultPriority priority() {return 32 - _n;} + FaultStat & countStat() {return _count;} +}; + +class SpillNNormal : public EnumeratedFault +{ + private: + static FaultName _name; + static TrapType _baseTrapType; + static FaultPriority _priority; + static FaultStat _count; + TrapType baseTrapType() {return _baseTrapType;} + public: + SpillNNormal(uint32_t n) : EnumeratedFault(n) {;} + FaultName name() {return _name;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class SpillNOther : public EnumeratedFault +{ + private: + static FaultName _name; + static TrapType _baseTrapType; + static FaultPriority _priority; + static FaultStat _count; + TrapType baseTrapType() {return _baseTrapType;} + public: + SpillNOther(uint32_t n) : EnumeratedFault(n) {;} + FaultName name() {return _name;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class FillNNormal : public EnumeratedFault +{ + private: + static FaultName _name; + static TrapType _baseTrapType; + static FaultPriority _priority; + static FaultStat _count; + TrapType baseTrapType() {return _baseTrapType;} + public: + FillNNormal(uint32_t n) : EnumeratedFault(n) {;} + FaultName name() {return _name;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class FillNOther : public EnumeratedFault +{ + private: + static FaultName _name; + static TrapType _baseTrapType; + static FaultPriority _priority; + static FaultStat _count; + TrapType baseTrapType() {return _baseTrapType;} + public: + FillNOther(uint32_t n) : EnumeratedFault(n) {;} + FaultName name() {return _name;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class TrapInstruction : public EnumeratedFault +{ + private: + static FaultName _name; + static TrapType _baseTrapType; + static FaultPriority _priority; + static FaultStat _count; + uint64_t syscall_num; + TrapType baseTrapType() {return _baseTrapType;} + public: + TrapInstruction(uint32_t n, uint64_t syscall) : + EnumeratedFault(n), syscall_num(syscall) {;} + FaultName name() {return _name;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +#if !FULL_SYSTEM + void invoke(ExecContext * xc); +#endif +}; + +} // SparcISA namespace + +#endif // __FAULTS_HH__ diff --git a/src/arch/sparc/isa/base.isa b/src/arch/sparc/isa/base.isa new file mode 100644 index 000000000..02f7cf61a --- /dev/null +++ b/src/arch/sparc/isa/base.isa @@ -0,0 +1,252 @@ +// Copyright (c) 2006 The Regents of The University of Michigan +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: Ali Saidi +// Gabe Black +// Steve Reinhardt + +//////////////////////////////////////////////////////////////////// +// +// Base class for sparc instructions, and some support functions +// + +output header {{ + + union CondCodes + { + struct + { + uint8_t c:1; + uint8_t v:1; + uint8_t z:1; + uint8_t n:1; + }; + uint32_t bits; + }; + + enum CondTest + { + Always=0x8, + Never=0x0, + NotEqual=0x9, + Equal=0x1, + Greater=0xA, + LessOrEqual=0x2, + GreaterOrEqual=0xB, + Less=0x3, + GreaterUnsigned=0xC, + LessOrEqualUnsigned=0x4, + CarryClear=0xD, + CarrySet=0x5, + Positive=0xE, + Negative=0x6, + OverflowClear=0xF, + OverflowSet=0x7 + }; + + extern char * CondTestAbbrev[]; + + /** + * Base class for all SPARC static instructions. + */ + class SparcStaticInst : public StaticInst + { + protected: + // Constructor. + SparcStaticInst(const char *mnem, + MachInst _machInst, OpClass __opClass) + : StaticInst(mnem, _machInst, __opClass) + { + } + + std::string generateDisassembly(Addr pc, + const SymbolTable *symtab) const; + + void printReg(std::ostream &os, int reg) const; + }; + + bool passesCondition(uint32_t codes, uint32_t condition); + + inline int64_t sign_ext(uint64_t data, int origWidth) + { + int shiftAmount = 64 - origWidth; + return (((int64_t)data) << shiftAmount) >> shiftAmount; + } +}}; + +output decoder {{ + + char * CondTestAbbrev[] = + { + "nev", //Never + "e", //Equal + "le", //Less or Equal + "l", //Less + "leu", //Less or Equal Unsigned + "c", //Carry set + "n", //Negative + "o", //Overflow set + "a", //Always + "ne", //Not Equal + "g", //Greater + "ge", //Greater or Equal + "gu", //Greater Unsigned + "cc", //Carry clear + "p", //Positive + "oc" //Overflow Clear + }; +}}; + +def template ROrImmDecode {{ + { + return (I ? (SparcStaticInst *)(new %(class_name)sImm(machInst)) + : (SparcStaticInst *)(new %(class_name)s(machInst))); + } +}}; + +let {{ + def splitOutImm(code): + matcher = re.compile(r'Rs(?P<rNum>\d)_or_imm(?P<iNum>\d+)(?P<typeQual>\.\w+)?') + rOrImmMatch = matcher.search(code) + if (rOrImmMatch == None): + return (False, code, '', '', '') + rString = rOrImmMatch.group("rNum") + if (rOrImmMatch.group("typeQual") != None): + rString += rOrImmMatch.group("typeQual") + iString = rOrImmMatch.group("iNum") + orig_code = code + code = matcher.sub('Rs' + rString, orig_code) + imm_code = matcher.sub('imm', orig_code) + return (True, code, imm_code, rString, iString) +}}; + +output decoder {{ + + inline void printMnemonic(std::ostream &os, const char * mnemonic) + { + ccprintf(os, "\t%s ", mnemonic); + } + + void + SparcStaticInst::printReg(std::ostream &os, int reg) const + { + const int MaxGlobal = 8; + const int MaxOutput = 16; + const int MaxLocal = 24; + const int MaxInput = 32; + if (reg == FramePointerReg) + ccprintf(os, "%%fp"); + else if (reg == StackPointerReg) + ccprintf(os, "%%sp"); + else if(reg < MaxGlobal) + ccprintf(os, "%%g%d", reg); + else if(reg < MaxOutput) + ccprintf(os, "%%o%d", reg - MaxGlobal); + else if(reg < MaxLocal) + ccprintf(os, "%%l%d", reg - MaxOutput); + else if(reg < MaxInput) + ccprintf(os, "%%i%d", reg - MaxLocal); + else { + ccprintf(os, "%%f%d", reg - FP_Base_DepTag); + } + } + + std::string SparcStaticInst::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { + std::stringstream ss; + + printMnemonic(ss, mnemonic); + + // just print the first two source regs... if there's + // a third one, it's a read-modify-write dest (Rc), + // e.g. for CMOVxx + if(_numSrcRegs > 0) + { + printReg(ss, _srcRegIdx[0]); + } + if(_numSrcRegs > 1) + { + ss << ","; + printReg(ss, _srcRegIdx[1]); + } + + // just print the first dest... if there's a second one, + // it's generally implicit + if(_numDestRegs > 0) + { + if(_numSrcRegs > 0) + ss << ","; + printReg(ss, _destRegIdx[0]); + } + + return ss.str(); + } + + bool passesCondition(uint32_t codes, uint32_t condition) + { + CondCodes condCodes; + condCodes.bits = codes; + switch(condition) + { + case Always: + return true; + case Never: + return false; + case NotEqual: + return !condCodes.z; + case Equal: + return condCodes.z; + case Greater: + return !(condCodes.z | (condCodes.n ^ condCodes.v)); + case LessOrEqual: + return condCodes.z | (condCodes.n ^ condCodes.v); + case GreaterOrEqual: + return !(condCodes.n ^ condCodes.v); + case Less: + return (condCodes.n ^ condCodes.v); + case GreaterUnsigned: + return !(condCodes.c | condCodes.z); + case LessOrEqualUnsigned: + return (condCodes.c | condCodes.z); + case CarryClear: + return !condCodes.c; + case CarrySet: + return condCodes.c; + case Positive: + return !condCodes.n; + case Negative: + return condCodes.n; + case OverflowClear: + return !condCodes.v; + case OverflowSet: + return condCodes.v; + } + panic("Tried testing condition nonexistant " + "condition code %d", condition); + } +}}; + diff --git a/src/arch/sparc/isa/bitfields.isa b/src/arch/sparc/isa/bitfields.isa new file mode 100644 index 000000000..27f52fa29 --- /dev/null +++ b/src/arch/sparc/isa/bitfields.isa @@ -0,0 +1,78 @@ +// Copyright (c) 2006 The Regents of The University of Michigan +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: Ali Saidi +// Gabe Black +// Steve Reinhardt + +//////////////////////////////////////////////////////////////////// +// +// Bitfield definitions. +// + +// Bitfields are shared liberally between instruction formats, so they are +// simply defined alphabetically + +def bitfield A <29>; +def bitfield BPCC <21:20>; // for BPcc & FBPcc +def bitfield FCMPCC <26:56>; // for FCMP & FCMPEa +def bitfield FMOVCC <13:11>; // for FMOVcc +def bitfield CC <12:11>; // for MOVcc & Tcc +def bitfield MOVCC3 <18>; // also for MOVcc +def bitfield CMASK <6:4>; +def bitfield COND2 <28:25>; +def bitfield COND4 <17:14>; +def bitfield D16HI <21:20>; +def bitfield D16LO <13:0>; +def bitfield DISP19 <18:0>; +def bitfield DISP22 <21:0>; +def bitfield DISP30 <29:0>; +def bitfield FCN <29:26>; +def bitfield I <13>; +def bitfield IMM_ASI <12:5>; +def bitfield IMM22 <21:0>; +def bitfield MMASK <3:0>; +def bitfield OP <31:30>; +def bitfield OP2 <24:22>; +def bitfield OP3 <24:19>; +def bitfield OPF <13:5>; +def bitfield OPF_CC <13:11>; +def bitfield OPF_LOW5 <9:5>; +def bitfield OPF_LOW6 <10:5>; +def bitfield P <19>; +def bitfield RCOND2 <27:25>; +def bitfield RCOND3 <12:10>; +def bitfield RCOND4 <12:10>; +def bitfield RD <29:25>; +def bitfield RS1 <18:14>; +def bitfield RS2 <4:0>; +def bitfield SHCNT32 <4:0>; +def bitfield SHCNT64 <5:0>; +def bitfield SIMM10 <9:0>; +def bitfield SIMM11 <10:0>; +def bitfield SIMM13 <12:0>; +def bitfield SW_TRAP <7:0>; +def bitfield X <12>; diff --git a/src/arch/sparc/isa/decoder.isa b/src/arch/sparc/isa/decoder.isa new file mode 100644 index 000000000..fa8832920 --- /dev/null +++ b/src/arch/sparc/isa/decoder.isa @@ -0,0 +1,669 @@ +// Copyright (c) 2006 The Regents of The University of Michigan +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: Ali Saidi +// Gabe Black +// Steve Reinhardt + +//////////////////////////////////////////////////////////////////// +// +// The actual decoder specification +// + +decode OP default Unknown::unknown() +{ + 0x0: decode OP2 + { + //Throw an illegal instruction acception + 0x0: Trap::illtrap({{fault = new IllegalInstruction;}}); + 0x1: decode BPCC + { + format Branch19 + { + 0x0: bpcci({{ + if(passesCondition(Ccr<3:0>, COND2)) + NNPC = xc->readPC() + disp; + else + handle_annul + }}); + 0x2: bpccx({{ + if(passesCondition(Ccr<7:4>, COND2)) + NNPC = xc->readPC() + disp; + else + handle_annul + }}); + } + } + 0x2: Branch22::bicc({{ + if(passesCondition(Ccr<3:0>, COND2)) + NNPC = xc->readPC() + disp; + else + handle_annul + }}); + 0x3: decode RCOND2 + { + format BranchSplit + { + 0x1: bpreq({{ + if(Rs1.sdw == 0) + NNPC = xc->readPC() + disp; + else + handle_annul + }}); + 0x2: bprle({{ + if(Rs1.sdw <= 0) + NNPC = xc->readPC() + disp; + else + handle_annul + }}); + 0x3: bprl({{ + if(Rs1.sdw < 0) + NNPC = xc->readPC() + disp; + else + handle_annul + }}); + 0x5: bprne({{ + if(Rs1.sdw != 0) + NNPC = xc->readPC() + disp; + else + handle_annul + }}); + 0x6: bprg({{ + if(Rs1.sdw > 0) + NNPC = xc->readPC() + disp; + else + handle_annul + }}); + 0x7: bprge({{ + if(Rs1.sdw >= 0) + NNPC = xc->readPC() + disp; + else + handle_annul + }}); + } + } + //SETHI (or NOP if rd == 0 and imm == 0) + 0x4: SetHi::sethi({{Rd = imm;}}); + 0x5: Trap::fbpfcc({{fault = new FpDisabled;}}); + 0x6: Trap::fbfcc({{fault = new FpDisabled;}}); + } + 0x1: Branch30::call({{ + R15 = xc->readPC(); + NNPC = R15 + disp; + }}); + 0x2: decode OP3 { + format IntOp { + 0x00: add({{Rd = Rs1.sdw + Rs2_or_imm13;}}); + 0x01: and({{Rd = Rs1.udw & Rs2_or_imm13;}}); + 0x02: or({{Rd = Rs1.udw | Rs2_or_imm13;}}); + 0x03: xor({{Rd = Rs1.udw ^ Rs2_or_imm13;}}); + 0x04: sub({{Rd = Rs1.sdw - Rs2_or_imm13;}}); + 0x05: andn({{Rd = Rs1.udw & ~Rs2_or_imm13;}}); + 0x06: orn({{Rd = Rs1.udw | ~Rs2_or_imm13;}}); + 0x07: xnor({{Rd = ~(Rs1.udw ^ Rs2_or_imm13);}}); + 0x08: addc({{Rd = Rs1.sdw + Rs2_or_imm13 + Ccr<0:0>;}}); + 0x09: mulx({{Rd = Rs1 * Rs2_or_imm13;}}); + 0x0A: umul({{ + Rd = Rs1.udw<31:0> * Rs2_or_imm13<31:0>; + Y = Rd<63:32>; + }}); + 0x0B: smul({{ + Rd.sdw = Rs1.sdw<31:0> * Rs2_or_imm13<31:0>; + Y = Rd.sdw; + }}); + 0x0C: subc({{Rd.sdw = Rs1.sdw + (~Rs2_or_imm13) + 1 + Ccr<0:0>}}); + 0x0D: udivx({{ + if(Rs2_or_imm13 == 0) fault = new DivisionByZero; + else Rd.udw = Rs1.udw / Rs2_or_imm13; + }}); + 0x0E: udiv({{ + if(Rs2_or_imm13 == 0) fault = new DivisionByZero; + else + { + Rd.udw = ((Y << 32) | Rs1.udw<31:0>) / Rs2_or_imm13; + if(Rd.udw >> 32 != 0) + Rd.udw = 0xFFFFFFFF; + } + }}); + 0x0F: sdiv({{ + if(Rs2_or_imm13.sdw == 0) + fault = new DivisionByZero; + else + { + Rd.udw = ((int64_t)((Y << 32) | Rs1.sdw<31:0>)) / Rs2_or_imm13.sdw; + if(Rd.udw<63:31> != 0) + Rd.udw = 0x7FFFFFFF; + else if(Rd.udw<63:> && Rd.udw<62:31> != 0xFFFFFFFF) + Rd.udw = 0xFFFFFFFF80000000ULL; + } + }}); + } + format IntOpCc { + 0x10: addcc({{ + int64_t resTemp, val2 = Rs2_or_imm13; + Rd = resTemp = Rs1 + val2;}}, + {{(Rs1<31:0> + val2<31:0>)<32:>}}, + {{Rs1<31:> == val2<31:> && val2<31:> != resTemp<31:>}}, + {{(Rs1<63:1> + val2<63:1> + (Rs1 & val2)<0:>)<63:>}}, + {{Rs1<63:> == val2<63:> && val2<63:> != resTemp<63:>}} + ); + 0x11: IntOpCcRes::andcc({{Rd = Rs1 & Rs2_or_imm13;}}); + 0x12: IntOpCcRes::orcc({{Rd = Rs1 | Rs2_or_imm13;}}); + 0x13: IntOpCcRes::xorcc({{Rd = Rs1 ^ Rs2_or_imm13;}}); + 0x14: subcc({{ + int64_t val2 = Rs2_or_imm13; + Rd = Rs1 - val2;}}, + {{(~(Rs1<31:0> + (~val2)<31:0> + 1))<32:>}}, + {{(Rs1<31:> != val2<31:>) && (Rs1<31:> != Rd<31:>)}}, + {{(~(Rs1<63:1> + (~val2)<63:1> + + (Rs1 | ~val2)<0:>))<63:>}}, + {{Rs1<63:> != val2<63:> && Rs1<63:> != Rd<63:>}} + ); + 0x15: IntOpCcRes::andncc({{Rd = Rs1 & ~Rs2_or_imm13;}}); + 0x16: IntOpCcRes::orncc({{Rd = Rs1 | ~Rs2_or_imm13;}}); + 0x17: IntOpCcRes::xnorcc({{Rd = ~(Rs1 ^ Rs2_or_imm13);}}); + 0x18: addccc({{ + int64_t resTemp, val2 = Rs2_or_imm13; + int64_t carryin = Ccr<0:0>; + Rd = resTemp = Rs1 + val2 + carryin;}}, + {{(Rs1<31:0> + val2<31:0> + carryin)<32:>}}, + {{Rs1<31:> == val2<31:> && val2<31:> != resTemp<31:>}}, + {{(Rs1<63:1> + val2<63:1> + + ((Rs1 & val2) | (carryin & (Rs1 | val2)))<0:>)<63:>}}, + {{Rs1<63:> == val2<63:> && val2<63:> != resTemp<63:>}} + ); + 0x1A: umulcc({{ + uint64_t resTemp; + Rd = resTemp = Rs1.udw<31:0> * Rs2_or_imm13.udw<31:0>; + Y = resTemp<63:32>;}}, + {{0}},{{0}},{{0}},{{0}}); + 0x1B: smulcc({{ + int64_t resTemp; + Rd = resTemp = Rs1.sdw<31:0> * Rs2_or_imm13.sdw<31:0>; + Y = resTemp<63:32>;}}, + {{0}},{{0}},{{0}},{{0}}); + 0x1C: subccc({{ + int64_t resTemp, val2 = Rs2_or_imm13; + int64_t carryin = Ccr<0:0>; + Rd = resTemp = Rs1 + ~(val2 + carryin) + 1;}}, + {{(~((Rs1<31:0> + (~(val2 + carryin))<31:0> + 1))<32:>)}}, + {{Rs1<31:> != val2<31:> && Rs1<31:> != resTemp<31:>}}, + {{(~((Rs1<63:1> + (~(val2 + carryin))<63:1>) + (Rs1<0:> + (~(val2+carryin))<0:> + 1)<63:1>))<63:>}}, + {{Rs1<63:> != val2<63:> && Rs1<63:> != resTemp<63:>}} + ); + 0x1D: udivxcc({{ + if(Rs2_or_imm13.udw == 0) fault = new DivisionByZero; + else Rd = Rs1.udw / Rs2_or_imm13.udw;}} + ,{{0}},{{0}},{{0}},{{0}}); + 0x1E: udivcc({{ + uint32_t resTemp, val2 = Rs2_or_imm13.udw; + int32_t overflow; + if(val2 == 0) fault = new DivisionByZero; + else + { + resTemp = (uint64_t)((Y << 32) | Rs1.udw<31:0>) / val2; + overflow = (resTemp<63:32> != 0); + if(overflow) Rd = resTemp = 0xFFFFFFFF; + else Rd = resTemp; + } }}, + {{0}}, + {{overflow}}, + {{0}}, + {{0}} + ); + 0x1F: sdivcc({{ + int32_t resTemp, val2 = Rs2_or_imm13.sdw; + int32_t overflow, underflow; + if(val2 == 0) fault = new DivisionByZero; + else + { + Rd = resTemp = (int64_t)((Y << 32) | Rs1.sdw<31:0>) / val2; + overflow = (resTemp<63:31> != 0); + underflow = (resTemp<63:> && resTemp<62:31> != 0xFFFFFFFF); + if(overflow) Rd = resTemp = 0x7FFFFFFF; + else if(underflow) Rd = resTemp = 0xFFFFFFFF80000000ULL; + else Rd = resTemp; + } }}, + {{0}}, + {{overflow || underflow}}, + {{0}}, + {{0}} + ); + 0x20: taddcc({{ + int64_t resTemp, val2 = Rs2_or_imm13; + Rd = resTemp = Rs1 + val2; + int32_t overflow = Rs1<1:0> || val2<1:0> || (Rs1<31:> == val2<31:> && val2<31:> != resTemp<31:>);}}, + {{((Rs1 & 0xFFFFFFFF + val2 & 0xFFFFFFFF) >> 31)}}, + {{overflow}}, + {{((Rs1 >> 1) + (val2 >> 1) + (Rs1 & val2 & 0x1))<63:>}}, + {{Rs1<63:> == val2<63:> && val2<63:> != resTemp<63:>}} + ); + 0x21: tsubcc({{ + int64_t resTemp, val2 = Rs2_or_imm13; + Rd = resTemp = Rs1 + val2; + int32_t overflow = Rs1<1:0> || val2<1:0> || (Rs1<31:> == val2<31:> && val2<31:> != resTemp<31:>);}}, + {{(Rs1 & 0xFFFFFFFF + val2 & 0xFFFFFFFF) >> 31}}, + {{overflow}}, + {{((Rs1 >> 1) + (val2 >> 1) + (Rs1 & val2 & 0x1))<63:>}}, + {{Rs1<63:> == val2<63:> && val2<63:> != resTemp<63:>}} + ); + 0x22: taddcctv({{ + int64_t resTemp, val2 = Rs2_or_imm13; + Rd = resTemp = Rs1 + val2; + int32_t overflow = Rs1<1:0> || val2<1:0> || (Rs1<31:> == val2<31:> && val2<31:> != resTemp<31:>); + if(overflow) fault = new TagOverflow;}}, + {{((Rs1 & 0xFFFFFFFF + val2 & 0xFFFFFFFF) >> 31)}}, + {{overflow}}, + {{((Rs1 >> 1) + (val2 >> 1) + (Rs1 & val2 & 0x1))<63:>}}, + {{Rs1<63:> == val2<63:> && val2<63:> != resTemp<63:>}} + ); + 0x23: tsubcctv({{ + int64_t resTemp, val2 = Rs2_or_imm13; + Rd = resTemp = Rs1 + val2; + int32_t overflow = Rs1<1:0> || val2<1:0> || (Rs1<31:> == val2<31:> && val2<31:> != resTemp<31:>); + if(overflow) fault = new TagOverflow;}}, + {{((Rs1 & 0xFFFFFFFF + val2 & 0xFFFFFFFF) >> 31)}}, + {{overflow}}, + {{((Rs1 >> 1) + (val2 >> 1) + (Rs1 & val2 & 0x1))<63:>}}, + {{Rs1<63:> == val2<63:> && val2<63:> != resTemp<63:>}} + ); + 0x24: mulscc({{ + int64_t resTemp, multiplicand = Rs2_or_imm13; + int32_t multiplier = Rs1<31:0>; + int32_t savedLSB = Rs1<0:>; + multiplier = multiplier<31:1> | + ((Ccr<3:3> + ^ Ccr<1:1>) << 32); + if(!Y<0:>) + multiplicand = 0; + Rd = resTemp = multiplicand + multiplier; + Y = Y<31:1> | (savedLSB << 31);}}, + {{((multiplicand & 0xFFFFFFFF + multiplier & 0xFFFFFFFF) >> 31)}}, + {{multiplicand<31:> == multiplier<31:> && multiplier<31:> != resTemp<31:>}}, + {{((multiplicand >> 1) + (multiplier >> 1) + (multiplicand & multiplier & 0x1))<63:>}}, + {{multiplicand<63:> == multiplier<63:> && multiplier<63:> != resTemp<63:>}} + ); + } + format IntOp + { + 0x25: decode X { + 0x0: sll({{Rd = Rs1 << (I ? SHCNT32 : Rs2<4:0>);}}); + 0x1: sllx({{Rd = Rs1 << (I ? SHCNT64 : Rs2<5:0>);}}); + } + 0x26: decode X { + 0x0: srl({{Rd = Rs1.uw >> (I ? SHCNT32 : Rs2<4:0>);}}); + 0x1: srlx({{Rd = Rs1.udw >> (I ? SHCNT64 : Rs2<5:0>);}}); + } + 0x27: decode X { + 0x0: sra({{Rd = Rs1.sw >> (I ? SHCNT32 : Rs2<4:0>);}}); + 0x1: srax({{Rd = Rs1.sdw >> (I ? SHCNT64 : Rs2<5:0>);}}); + } + // XXX might want a format rdipr thing here + 0x28: rdasr({{ + Rd = xc->readMiscRegWithEffect(RS1 + AsrStart, fault); + }}); + 0x29: rdhpr({{ + // XXX Need to protect with format that traps non-priv/priv + // access + Rd = xc->readMiscRegWithEffect(RS1 + HprStart, fault); + }}); + 0x2A: rdpr({{ + // XXX Need to protect with format that traps non-priv + // access + Rd = xc->readMiscRegWithEffect(RS1 + PrStart, fault); + }}); + 0x2B: BasicOperate::flushw({{ + if(NWindows - 2 - Cansave == 0) + { + if(Otherwin) + fault = new SpillNOther(Wstate<5:3>); + else + fault = new SpillNNormal(Wstate<2:0>); + } + }}); + 0x2C: decode MOVCC3 + { + 0x0: Trap::movccfcc({{fault = new FpDisabled;}}); + 0x1: decode CC + { + 0x0: movcci({{ + if(passesCondition(Ccr<3:0>, COND4)) + Rd = Rs2_or_imm11; + else + Rd = Rd; + }}); + 0x2: movccx({{ + if(passesCondition(Ccr<7:4>, COND4)) + Rd = Rs2_or_imm11; + else + Rd = Rd; + }}); + } + } + 0x2D: sdivx({{ + if(Rs2_or_imm13.sdw == 0) fault = new DivisionByZero; + else Rd.sdw = Rs1.sdw / Rs2_or_imm13.sdw; + }}); + 0x2E: decode RS1 { + 0x0: IntOp::popc({{ + int64_t count = 0; + uint64_t temp = Rs2_or_imm13; + //Count the 1s in the front 4bits until none are left + uint8_t oneBits[] = {0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4}; + while(temp) + { + count += oneBits[temp & 0xF]; + temp = temp >> 4; + } + Rd = count; + }}); + } + 0x2F: decode RCOND3 + { + 0x1: movreq({{Rd = (Rs1.sdw == 0) ? Rs2_or_imm10 : Rd;}}); + 0x2: movrle({{Rd = (Rs1.sdw <= 0) ? Rs2_or_imm10 : Rd;}}); + 0x3: movrl({{Rd = (Rs1.sdw < 0) ? Rs2_or_imm10 : Rd;}}); + 0x5: movrne({{Rd = (Rs1.sdw != 0) ? Rs2_or_imm10 : Rd;}}); + 0x6: movrg({{Rd = (Rs1.sdw > 0) ? Rs2_or_imm10 : Rd;}}); + 0x7: movrge({{Rd = (Rs1.sdw >= 0) ? Rs2_or_imm10 : Rd;}}); + } + 0x30: wrasr({{ + xc->setMiscRegWithEffect(RD + AsrStart, Rs1 ^ Rs2_or_imm13); + }}); + 0x31: decode FCN { + 0x0: BasicOperate::saved({{/*Boogy Boogy*/}}); + 0x1: BasicOperate::restored({{/*Boogy Boogy*/}}); + } + 0x32: wrpr({{ + // XXX Need to protect with format that traps non-priv + // access + xc->setMiscRegWithEffect(RD + PrStart, Rs1 ^ Rs2_or_imm13); + }}); + 0x33: wrhpr({{ + // XXX Need to protect with format that traps non-priv/priv + // access + xc->setMiscRegWithEffect(RD + HprStart, Rs1 ^ Rs2_or_imm13); + }}); + 0x34: Trap::fpop1({{fault = new FpDisabled;}}); + 0x35: Trap::fpop2({{fault = new FpDisabled;}}); + 0x38: Branch::jmpl({{ + Addr target = Rs1 + Rs2_or_imm13; + if(target & 0x3) + fault = new MemAddressNotAligned; + else + { + Rd = xc->readPC(); + NNPC = target; + } + }}); + 0x39: Branch::return({{ + //If both MemAddressNotAligned and + //a fill trap happen, it's not clear + //which one should be returned. + Addr target = Rs1 + Rs2_or_imm13; + if(target & 0x3) + fault = new MemAddressNotAligned; + else + NNPC = target; + if(fault == NoFault) + { + //CWP should be set directly so that it always happens + //Also, this will allow writing to the new window and + //reading from the old one + Cwp = (Cwp - 1 + NWindows) % NWindows; + if(Canrestore == 0) + { + if(Otherwin) + fault = new FillNOther(Wstate<5:3>); + else + fault = new FillNNormal(Wstate<2:0>); + } + else + { + Rd = Rs1 + Rs2_or_imm13; + Cansave = Cansave + 1; + Canrestore = Canrestore - 1; + } + //This is here to make sure the CWP is written + //no matter what. This ensures that the results + //are written in the new window as well. + xc->setMiscRegWithEffect(MISCREG_CWP, Cwp); + } + }}); + 0x3A: decode CC + { + 0x0: Trap::tcci({{ + if(passesCondition(Ccr<3:0>, COND2)) + { + int lTrapNum = I ? (Rs1 + SW_TRAP) : (Rs1 + Rs2); + DPRINTF(Sparc, "The trap number is %d\n", lTrapNum); +#if FULL_SYSTEM + fault = new TrapInstruction(lTrapNum); +#else + DPRINTF(Sparc, "The syscall number is %d\n", R1); + xc->syscall(R1); +#endif + } + }}); + 0x2: Trap::tccx({{ + if(passesCondition(Ccr<7:4>, COND2)) + { + int lTrapNum = I ? (Rs1 + SW_TRAP) : (Rs1 + Rs2); + DPRINTF(Sparc, "The trap number is %d\n", lTrapNum); +#if FULL_SYSTEM + fault = new TrapInstruction(lTrapNum); +#else + DPRINTF(Sparc, "The syscall number is %d\n", R1); + xc->syscall(R1); +#endif + } + }}); + } + 0x3B: Nop::flush({{/*Instruction memory flush*/}}); + 0x3C: save({{ + //CWP should be set directly so that it always happens + //Also, this will allow writing to the new window and + //reading from the old one + if(Cansave == 0) + { + if(Otherwin) + fault = new SpillNOther(Wstate<5:3>); + else + fault = new SpillNNormal(Wstate<2:0>); + Cwp = (Cwp + 2) % NWindows; + } + else if(Cleanwin - Canrestore == 0) + { + Cwp = (Cwp + 1) % NWindows; + fault = new CleanWindow; + } + else + { + Cwp = (Cwp + 1) % NWindows; + Rd = Rs1 + Rs2_or_imm13; + Cansave = Cansave - 1; + Canrestore = Canrestore + 1; + } + //This is here to make sure the CWP is written + //no matter what. This ensures that the results + //are written in the new window as well. + xc->setMiscRegWithEffect(MISCREG_CWP, Cwp); + }}); + 0x3D: restore({{ + //CWP should be set directly so that it always happens + //Also, this will allow writing to the new window and + //reading from the old one + Cwp = (Cwp - 1 + NWindows) % NWindows; + if(Canrestore == 0) + { + if(Otherwin) + fault = new FillNOther(Wstate<5:3>); + else + fault = new FillNNormal(Wstate<2:0>); + } + else + { + Rd = Rs1 + Rs2_or_imm13; + Cansave = Cansave + 1; + Canrestore = Canrestore - 1; + } + //This is here to make sure the CWP is written + //no matter what. This ensures that the results + //are written in the new window as well. + xc->setMiscRegWithEffect(MISCREG_CWP, Cwp); + }}); + 0x3E: decode FCN { + 0x0: Priv::done({{ + if(Tl == 0) + return new IllegalInstruction; + + Cwp = Tstate<4:0>; + Pstate = Tstate<20:8>; + Asi = Tstate<31:24>; + Ccr = Tstate<39:32>; + Gl = Tstate<42:40>; + NPC = Tnpc; + NNPC = Tnpc + 4; + Tl = Tl - 1; + }}); + 0x1: BasicOperate::retry({{ + if(Tl == 0) + return new IllegalInstruction; + Cwp = Tstate<4:0>; + Pstate = Tstate<20:8>; + Asi = Tstate<31:24>; + Ccr = Tstate<39:32>; + Gl = Tstate<42:40>; + NPC = Tpc; + NNPC = Tnpc + 4; + Tl = Tl - 1; + }}); + } + } + } + 0x3: decode OP3 { + format Load { + 0x00: lduw({{Rd = Mem;}}, {{32}}); + 0x01: ldub({{Rd = Mem;}}, {{8}}); + 0x02: lduh({{Rd = Mem;}}, {{16}}); + 0x03: ldd({{ + uint64_t val = Mem; + RdLow = val<31:0>; + RdHigh = val<63:32>; + }}, {{64}}); + } + format Store { + 0x04: stw({{Mem = Rd.sw;}}, {{32}}); + 0x05: stb({{Mem = Rd.sb;}}, {{8}}); + 0x06: sth({{Mem = Rd.shw;}}, {{16}}); + 0x07: std({{Mem = RdLow<31:0> | RdHigh<31:0> << 32;}}, {{64}}); + } + format Load { + 0x08: ldsw({{Rd = (int32_t)Mem;}}, {{32}}); + 0x09: ldsb({{Rd = (int8_t)Mem;}}, {{8}}); + 0x0A: ldsh({{Rd = (int16_t)Mem;}}, {{16}}); + 0x0B: ldx({{Rd = (int64_t)Mem;}}, {{64}}); + 0x0D: ldstub({{ + Rd = Mem; + Mem = 0xFF; + }}, {{8}}); + } + 0x0E: Store::stx({{Mem = Rd}}, {{64}}); + 0x0F: LoadStore::swap({{ + uint32_t temp = Rd; + Rd = Mem; + Mem = temp; + }}, {{32}}); + format Load { + 0x10: lduwa({{Rd = Mem;}}, {{32}}); + 0x11: lduba({{Rd = Mem;}}, {{8}}); + 0x12: lduha({{Rd = Mem;}}, {{16}}); + 0x13: ldda({{ + uint64_t val = Mem; + RdLow = val<31:0>; + RdHigh = val<63:32>; + }}, {{64}}); + } + format Store { + 0x14: stwa({{Mem = Rd;}}, {{32}}); + 0x15: stba({{Mem = Rd;}}, {{8}}); + 0x16: stha({{Mem = Rd;}}, {{16}}); + 0x17: stda({{Mem = RdLow<31:0> | RdHigh<31:0> << 32;}}, {{64}}); + } + format Load { + 0x18: ldswa({{Rd = (int32_t)Mem;}}, {{32}}); + 0x19: ldsba({{Rd = (int8_t)Mem;}}, {{8}}); + 0x1A: ldsha({{Rd = (int16_t)Mem;}}, {{16}}); + 0x1B: ldxa({{Rd = (int64_t)Mem;}}, {{64}}); + } + 0x1D: LoadStore::ldstuba({{ + Rd = Mem; + Mem = 0xFF; + }}, {{8}}); + 0x1E: Store::stxa({{Mem = Rd}}, {{64}}); + 0x1F: LoadStore::swapa({{ + uint32_t temp = Rd; + Rd = Mem; + Mem = temp; + }}, {{32}}); + format Trap { + 0x20: ldf({{fault = new FpDisabled;}}); + 0x21: decode X { + 0x0: Load::ldfsr({{Fsr = Mem<31:0> | Fsr<63:32>;}}, {{32}}); + 0x1: Load::ldxfsr({{Fsr = Mem;}}, {{64}}); + } + 0x22: ldqf({{fault = new FpDisabled;}}); + 0x23: lddf({{fault = new FpDisabled;}}); + 0x24: stf({{fault = new FpDisabled;}}); + 0x25: decode X { + 0x0: Store::stfsr({{Mem = Fsr<31:0>;}}, {{32}}); + 0x1: Store::stxfsr({{Mem = Fsr;}}, {{64}}); + } + 0x26: stqf({{fault = new FpDisabled;}}); + 0x27: stdf({{fault = new FpDisabled;}}); + 0x2D: Nop::prefetch({{ }}); + 0x30: ldfa({{return new FpDisabled;}}); + 0x32: ldqfa({{fault = new FpDisabled;}}); + 0x33: lddfa({{fault = new FpDisabled;}}); + 0x34: stfa({{fault = new FpDisabled;}}); + 0x35: stqfa({{fault = new FpDisabled;}}); + 0x36: stdfa({{fault = new FpDisabled;}}); + 0x3C: Cas::casa({{ + uint64_t val = Mem.uw; + if(Rs2.uw == val) + Mem.uw = Rd.uw; + Rd.uw = val; + }}); + 0x3D: Nop::prefetcha({{ }}); + 0x3E: Cas::casxa({{ + uint64_t val = Mem.udw; + if(Rs2 == val) + Mem.udw = Rd; + Rd = val; + }}); + } + } +} diff --git a/src/arch/sparc/isa/formats.isa b/src/arch/sparc/isa/formats.isa new file mode 100644 index 000000000..17d68061b --- /dev/null +++ b/src/arch/sparc/isa/formats.isa @@ -0,0 +1,28 @@ +//Include the basic format +//Templates from this format are used later +##include "formats/basic.isa" + +//Include the noop format +##include "formats/nop.isa" + +//Include the integerOp and integerOpCc format +##include "formats/integerop.isa" + +//Include the memory format +##include "formats/mem.isa" + +//Include the compare and swap format +##include "formats/cas.isa" + +//Include the trap format +##include "formats/trap.isa" + +//Include the "unknown" format +##include "formats/unknown.isa" + +//Include the priveleged mode format +##include "formats/priv.isa" + +//Include the branch format +##include "formats/branch.isa" + diff --git a/src/arch/sparc/isa/formats/basic.isa b/src/arch/sparc/isa/formats/basic.isa new file mode 100644 index 000000000..60432cb6b --- /dev/null +++ b/src/arch/sparc/isa/formats/basic.isa @@ -0,0 +1,97 @@ +// Copyright (c) 2006 The Regents of The University of Michigan +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: Ali Saidi +// Gabe Black +// Steve Reinhardt + +// Declarations for execute() methods. +def template BasicExecDeclare {{ + Fault execute(%(CPU_exec_context)s *, Trace::InstRecord *) const; +}}; + +// Basic instruction class declaration template. +def template BasicDeclare {{ + /** + * Static instruction class for "%(mnemonic)s". + */ + class %(class_name)s : public %(base_class)s + { + public: + // Constructor. + %(class_name)s(MachInst machInst); + %(BasicExecDeclare)s + }; +}}; + +// Basic instruction class constructor template. +def template BasicConstructor {{ + inline %(class_name)s::%(class_name)s(MachInst machInst) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s) + { + %(constructor)s; + } +}}; + +// Basic instruction class execute method template. +def template BasicExecute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Fault fault = NoFault; + + %(fp_enable_check)s; + %(op_decl)s; + %(op_rd)s; + %(code)s; + + if(fault == NoFault) + { + %(op_wb)s; + } + return fault; + } +}}; + +// Basic decode template. +def template BasicDecode {{ + return new %(class_name)s(machInst); +}}; + +// Basic decode template, passing mnemonic in as string arg to constructor. +def template BasicDecodeWithMnemonic {{ + return new %(class_name)s("%(mnemonic)s", machInst); +}}; + +// The most basic instruction format... used only for a few misc. insts +def format BasicOperate(code, *flags) {{ + iop = InstObjParams(name, Name, 'SparcStaticInst', + CodeBlock(code), flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; diff --git a/src/arch/sparc/isa/formats/branch.isa b/src/arch/sparc/isa/formats/branch.isa new file mode 100644 index 000000000..7d46ce739 --- /dev/null +++ b/src/arch/sparc/isa/formats/branch.isa @@ -0,0 +1,337 @@ +// Copyright (c) 2006 The Regents of The University of Michigan +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: Gabe Black +// Steve Reinhardt + +//////////////////////////////////////////////////////////////////// +// +// Branch instructions +// + +output header {{ + /** + * Base class for branch operations. + */ + class Branch : public SparcStaticInst + { + protected: + // Constructor + Branch(const char *mnem, MachInst _machInst, OpClass __opClass) : + SparcStaticInst(mnem, _machInst, __opClass) + { + } + + std::string generateDisassembly(Addr pc, + const SymbolTable *symtab) const; + }; + + /** + * Base class for branch operations with an immediate displacement. + */ + class BranchDisp : public Branch + { + protected: + // Constructor + BranchDisp(const char *mnem, MachInst _machInst, + OpClass __opClass) : + Branch(mnem, _machInst, __opClass) + { + } + + std::string generateDisassembly(Addr pc, + const SymbolTable *symtab) const; + + int32_t disp; + }; + + /** + * Base class for branches with 19 bit displacements. + */ + class Branch19 : public BranchDisp + { + protected: + // Constructor + Branch19(const char *mnem, MachInst _machInst, + OpClass __opClass) : + BranchDisp(mnem, _machInst, __opClass) + { + disp = sign_ext(DISP19 << 2, 21); + } + }; + + /** + * Base class for branches with 22 bit displacements. + */ + class Branch22 : public BranchDisp + { + protected: + // Constructor + Branch22(const char *mnem, MachInst _machInst, + OpClass __opClass) : + BranchDisp(mnem, _machInst, __opClass) + { + disp = sign_ext(DISP22 << 2, 24); + } + }; + + /** + * Base class for branches with 30 bit displacements. + */ + class Branch30 : public BranchDisp + { + protected: + // Constructor + Branch30(const char *mnem, MachInst _machInst, + OpClass __opClass) : + BranchDisp(mnem, _machInst, __opClass) + { + disp = sign_ext(DISP30 << 2, 32); + } + }; + + /** + * Base class for 16bit split displacements. + */ + class BranchSplit : public BranchDisp + { + protected: + // Constructor + BranchSplit(const char *mnem, MachInst _machInst, + OpClass __opClass) : + BranchDisp(mnem, _machInst, __opClass) + { + disp = sign_ext((D16HI << 16) | (D16LO << 2), 18); + } + }; + + /** + * Base class for branches that use an immediate and a register to + * compute their displacements. + */ + class BranchImm13 : public Branch + { + protected: + // Constructor + BranchImm13(const char *mnem, MachInst _machInst, OpClass __opClass) : + Branch(mnem, _machInst, __opClass), imm(sign_ext(SIMM13, 13)) + { + } + + std::string generateDisassembly(Addr pc, + const SymbolTable *symtab) const; + + int32_t imm; + }; +}}; + +output decoder {{ + std::string Branch::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { + std::stringstream response; + + printMnemonic(response, mnemonic); + + if (_numSrcRegs > 0) + { + printReg(response, _srcRegIdx[0]); + for(int x = 1; x < _numSrcRegs; x++) + { + response << ", "; + printReg(response, _srcRegIdx[x]); + } + } + + if (_numDestRegs > 0) + { + if(_numSrcRegs > 0) + response << ", "; + printReg(response, _destRegIdx[0]); + } + + return response.str(); + } + + std::string BranchImm13::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { + std::stringstream response; + + printMnemonic(response, mnemonic); + + if (_numSrcRegs > 0) + { + printReg(response, _srcRegIdx[0]); + for(int x = 1; x < _numSrcRegs; x++) + { + response << ", "; + printReg(response, _srcRegIdx[x]); + } + } + + if(_numSrcRegs > 0) + response << ", "; + + ccprintf(response, "0x%x", imm); + + if (_numDestRegs > 0) + { + response << ", "; + printReg(response, _destRegIdx[0]); + } + + return response.str(); + } + + std::string BranchDisp::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { + std::stringstream response; + std::string symbol; + Addr symbolAddr; + + Addr target = disp + pc; + + printMnemonic(response, mnemonic); + ccprintf(response, "0x%x", target); + + if(symtab->findNearestSymbol(target, symbol, symbolAddr)) + { + ccprintf(response, " <%s", symbol); + if(symbolAddr != target) + ccprintf(response, "+%d>", target - symbolAddr); + else + ccprintf(response, ">"); + } + + return response.str(); + } +}}; + +def template BranchExecute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + //Attempt to execute the instruction + Fault fault = NoFault; + + %(op_decl)s; + %(op_rd)s; + + NNPC = xc->readNextNPC(); + %(code)s; + + if(fault == NoFault) + { + //Write the resulting state to the execution context + %(op_wb)s; + } + + return fault; + } +}}; + +let {{ + handle_annul = ''' + { + if(A) + { + NPC = xc->readNextNPC(); + NNPC = NPC + 4; + } + else + { + NPC = xc->readNextPC(); + NNPC = xc->readNextNPC(); + } + }''' +}}; + +// Primary format for branch instructions: +def format Branch(code, *opt_flags) {{ + code = re.sub(r'handle_annul', handle_annul, code) + (usesImm, code, immCode, + rString, iString) = splitOutImm(code) + iop = InstObjParams(name, Name, 'Branch', code, opt_flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + exec_output = BranchExecute.subst(iop) + if usesImm: + imm_iop = InstObjParams(name, Name + 'Imm', 'BranchImm' + iString, + immCode, opt_flags) + header_output += BasicDeclare.subst(imm_iop) + decoder_output += BasicConstructor.subst(imm_iop) + exec_output += BranchExecute.subst(imm_iop) + decode_block = ROrImmDecode.subst(iop) + else: + decode_block = BasicDecode.subst(iop) +}}; + +// Primary format for branch instructions: +def format Branch19(code, *opt_flags) {{ + code = re.sub(r'handle_annul', handle_annul, code) + codeBlk = CodeBlock(code) + iop = InstObjParams(name, Name, 'Branch19', codeBlk, opt_flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + exec_output = BranchExecute.subst(iop) + decode_block = BasicDecode.subst(iop) +}}; + +// Primary format for branch instructions: +def format Branch22(code, *opt_flags) {{ + code = re.sub(r'handle_annul', handle_annul, code) + codeBlk = CodeBlock(code) + iop = InstObjParams(name, Name, 'Branch22', codeBlk, opt_flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + exec_output = BranchExecute.subst(iop) + decode_block = BasicDecode.subst(iop) +}}; + +// Primary format for branch instructions: +def format Branch30(code, *opt_flags) {{ + code = re.sub(r'handle_annul', handle_annul, code) + codeBlk = CodeBlock(code) + iop = InstObjParams(name, Name, 'Branch30', codeBlk, opt_flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + exec_output = BranchExecute.subst(iop) + decode_block = BasicDecode.subst(iop) +}}; + +// Primary format for branch instructions: +def format BranchSplit(code, *opt_flags) {{ + code = re.sub(r'handle_annul', handle_annul, code) + codeBlk = CodeBlock(code) + iop = InstObjParams(name, Name, 'BranchSplit', codeBlk, opt_flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + exec_output = BranchExecute.subst(iop) + decode_block = BasicDecode.subst(iop) +}}; + diff --git a/src/arch/sparc/isa/formats/integerop.isa b/src/arch/sparc/isa/formats/integerop.isa new file mode 100644 index 000000000..1894ce541 --- /dev/null +++ b/src/arch/sparc/isa/formats/integerop.isa @@ -0,0 +1,395 @@ +// Copyright (c) 2006 The Regents of The University of Michigan +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: Ali Saidi +// Gabe Black +// Steve Reinhardt + +//////////////////////////////////////////////////////////////////// +// +// Integer operate instructions +// + +output header {{ + /** + * Base class for integer operations. + */ + class IntOp : public SparcStaticInst + { + protected: + // Constructor + IntOp(const char *mnem, ExtMachInst _machInst, + OpClass __opClass) : + SparcStaticInst(mnem, _machInst, __opClass) + { + } + + std::string generateDisassembly(Addr pc, + const SymbolTable *symtab) const; + + virtual bool printPseudoOps(std::ostream &os, Addr pc, + const SymbolTable *symtab) const; + }; + + /** + * Base class for immediate integer operations. + */ + class IntOpImm : public IntOp + { + protected: + // Constructor + IntOpImm(const char *mnem, ExtMachInst _machInst, + OpClass __opClass) : + IntOp(mnem, _machInst, __opClass) + { + } + + int32_t imm; + + std::string generateDisassembly(Addr pc, + const SymbolTable *symtab) const; + + virtual bool printPseudoOps(std::ostream &os, Addr pc, + const SymbolTable *symtab) const; + }; + + /** + * Base class for 10 bit immediate integer operations. + */ + class IntOpImm10 : public IntOpImm + { + protected: + // Constructor + IntOpImm10(const char *mnem, ExtMachInst _machInst, + OpClass __opClass) : + IntOpImm(mnem, _machInst, __opClass) + { + imm = sign_ext(SIMM10, 10); + } + }; + + /** + * Base class for 11 bit immediate integer operations. + */ + class IntOpImm11 : public IntOpImm + { + protected: + // Constructor + IntOpImm11(const char *mnem, ExtMachInst _machInst, + OpClass __opClass) : + IntOpImm(mnem, _machInst, __opClass) + { + imm = sign_ext(SIMM11, 11); + } + }; + + /** + * Base class for 13 bit immediate integer operations. + */ + class IntOpImm13 : public IntOpImm + { + protected: + // Constructor + IntOpImm13(const char *mnem, ExtMachInst _machInst, + OpClass __opClass) : + IntOpImm(mnem, _machInst, __opClass) + { + imm = sign_ext(SIMM13, 13); + } + }; + + /** + * Base class for sethi. + */ + class SetHi : public IntOpImm + { + protected: + // Constructor + SetHi(const char *mnem, ExtMachInst _machInst, + OpClass __opClass) : + IntOpImm(mnem, _machInst, __opClass) + { + imm = (IMM22 << 10) & 0xFFFFFC00; + } + + std::string generateDisassembly(Addr pc, + const SymbolTable *symtab) const; + }; +}}; + +def template SetHiDecode {{ + { + if(RD == 0 && IMM22 == 0) + return (SparcStaticInst *)(new Nop("nop", machInst, No_OpClass)); + else + return (SparcStaticInst *)(new %(class_name)s(machInst)); + } +}}; + +output decoder {{ + + bool IntOp::printPseudoOps(std::ostream &os, Addr pc, + const SymbolTable *symbab) const + { + if(!strcmp(mnemonic, "or") && _srcRegIdx[0] == 0) + { + printMnemonic(os, "mov"); + if(_numSrcRegs > 0) + printReg(os, _srcRegIdx[1]); + ccprintf(os, ", "); + if(_numDestRegs > 0) + printReg(os, _destRegIdx[0]); + + return true; + } + return false; + } + + bool IntOpImm::printPseudoOps(std::ostream &os, Addr pc, + const SymbolTable *symbab) const + { + if(!strcmp(mnemonic, "or")) + { + if(_srcRegIdx[0] == 0) + { + if(imm == 0) + { + printMnemonic(os, "clr"); + if(_numDestRegs > 0) + printReg(os, _destRegIdx[0]); + return true; + } + else + { + printMnemonic(os, "mov"); + ccprintf(os, ", 0x%x, ", imm); + if(_numDestRegs > 0) + printReg(os, _destRegIdx[0]); + return true; + } + } + else if(imm == 0) + { + printMnemonic(os, "mov"); + if(_numSrcRegs > 0) + printReg(os, _srcRegIdx[0]); + ccprintf(os, ", "); + if(_numDestRegs > 0) + printReg(os, _destRegIdx[0]); + return true; + } + } + return false; + } + + std::string IntOp::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { + std::stringstream response; + + if(!printPseudoOps(response, pc, symtab)) + { + printMnemonic(response, mnemonic); + if (_numSrcRegs > 0) + { + printReg(response, _srcRegIdx[0]); + for(int x = 1; x < _numSrcRegs; x++) + { + response << ", "; + printReg(response, _srcRegIdx[x]); + } + } + if (_numDestRegs > 0) + { + if(_numSrcRegs > 0) + response << ", "; + printReg(response, _destRegIdx[0]); + } + } + return response.str(); + } + + std::string IntOpImm::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { + std::stringstream response; + + if(!printPseudoOps(response, pc, symtab)) + { + printMnemonic(response, mnemonic); + if (_numSrcRegs > 0) + { + printReg(response, _srcRegIdx[0]); + for(int x = 1; x < _numSrcRegs - 1; x++) + { + response << ", "; + printReg(response, _srcRegIdx[x]); + } + } + if(_numSrcRegs > 0) + response << ", "; + ccprintf(response, "0x%x", imm); + if (_numDestRegs > 0) + { + response << ", "; + printReg(response, _destRegIdx[0]); + } + } + return response.str(); + } + + std::string SetHi::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { + std::stringstream response; + + printMnemonic(response, mnemonic); + if(_numSrcRegs > 0) + response << ", "; + ccprintf(response, "%%hi(0x%x), ", imm); + printReg(response, _destRegIdx[0]); + return response.str(); + } +}}; + +def template IntOpExecute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Fault fault = NoFault; + + %(op_decl)s; + %(op_rd)s; + %(code)s; + + //Write the resulting state to the execution context + if(fault == NoFault) + { + %(cc_code)s; + %(op_wb)s; + } + return fault; + } +}}; + +let {{ + def doIntFormat(code, ccCode, name, Name, opt_flags): + (usesImm, code, immCode, + rString, iString) = splitOutImm(code) + iop = InstObjParams(name, Name, 'IntOp', code, + opt_flags, ("cc_code", ccCode)) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + exec_output = IntOpExecute.subst(iop) + if usesImm: + imm_iop = InstObjParams(name, Name + 'Imm', 'IntOpImm' + iString, + immCode, opt_flags, ("cc_code", ccCode)) + header_output += BasicDeclare.subst(imm_iop) + decoder_output += BasicConstructor.subst(imm_iop) + exec_output += IntOpExecute.subst(imm_iop) + decode_block = ROrImmDecode.subst(iop) + else: + decode_block = BasicDecode.subst(iop) + return (header_output, decoder_output, exec_output, decode_block) + + calcCcCode = ''' + uint8_t tmp_ccriccc; + uint8_t tmp_ccriccv; + uint8_t tmp_ccriccz; + uint8_t tmp_ccriccn; + uint8_t tmp_ccrxccc; + uint8_t tmp_ccrxccv; + uint8_t tmp_ccrxccz; + uint8_t tmp_ccrxccn; + + tmp_ccriccn = (Rd >> 31) & 1; + tmp_ccriccz = ((Rd & 0xFFFFFFFF) == 0); + tmp_ccrxccn = (Rd >> 63) & 1; + tmp_ccrxccz = (Rd == 0); + tmp_ccriccv = %(ivValue)s & 1; + tmp_ccriccc = %(icValue)s & 1; + tmp_ccrxccv = %(xvValue)s & 1; + tmp_ccrxccc = %(xcValue)s & 1; + + Ccr = tmp_ccriccc | tmp_ccriccv << 1 | + tmp_ccriccz << 2 | tmp_ccriccn << 3| + tmp_ccrxccc << 4 | tmp_ccrxccv << 5| + tmp_ccrxccz << 6| tmp_ccrxccn << 7; + + + DPRINTF(Sparc, "in = %%d\\n", (uint16_t)tmp_ccriccn); + DPRINTF(Sparc, "iz = %%d\\n", (uint16_t)tmp_ccriccz); + DPRINTF(Sparc, "xn = %%d\\n", (uint16_t)tmp_ccrxccn); + DPRINTF(Sparc, "xz = %%d\\n", (uint16_t)tmp_ccrxccz); + DPRINTF(Sparc, "iv = %%d\\n", (uint16_t)tmp_ccriccv); + DPRINTF(Sparc, "ic = %%d\\n", (uint16_t)tmp_ccriccc); + DPRINTF(Sparc, "xv = %%d\\n", (uint16_t)tmp_ccrxccv); + DPRINTF(Sparc, "xc = %%d\\n", (uint16_t)tmp_ccrxccc); + ''' +}}; + +// Primary format for integer operate instructions: +def format IntOp(code, *opt_flags) {{ + ccCode = '' + (header_output, + decoder_output, + exec_output, + decode_block) = doIntFormat(code, ccCode, + name, Name, opt_flags) +}}; + +// Primary format for integer operate instructions: +def format IntOpCc(code, icValue, ivValue, xcValue, xvValue, *opt_flags) {{ + ccCode = calcCcCode % vars() + (header_output, + decoder_output, + exec_output, + decode_block) = doIntFormat(code, ccCode, + name, Name, opt_flags) +}}; + +// Primary format for integer operate instructions: +def format IntOpCcRes(code, *opt_flags) {{ + ccCode = calcCcCode % {"icValue":"0", + "ivValue":"0", + "xcValue":"0", + "xvValue":"0"} + (header_output, + decoder_output, + exec_output, + decode_block) = doIntFormat(code, ccCode, + name, Name, opt_flags) +}}; + +def format SetHi(code, *opt_flags) {{ + iop = InstObjParams(name, Name, 'SetHi', + code, opt_flags, ("cc_code", '')) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + exec_output = IntOpExecute.subst(iop) + decode_block = SetHiDecode.subst(iop) +}}; + diff --git a/src/arch/sparc/isa/formats/mem.isa b/src/arch/sparc/isa/formats/mem.isa new file mode 100644 index 000000000..12dae57e5 --- /dev/null +++ b/src/arch/sparc/isa/formats/mem.isa @@ -0,0 +1,171 @@ +//////////////////////////////////////////////////////////////////// +// +// Mem instructions +// + +output header {{ + /** + * Base class for memory operations. + */ + class Mem : public SparcStaticInst + { + protected: + + // Constructor + Mem(const char *mnem, ExtMachInst _machInst, OpClass __opClass) : + SparcStaticInst(mnem, _machInst, __opClass) + { + } + + std::string generateDisassembly(Addr pc, + const SymbolTable *symtab) const; + }; + + /** + * Class for memory operations which use an immediate offset. + */ + class MemImm : public Mem + { + protected: + + // Constructor + MemImm(const char *mnem, ExtMachInst _machInst, OpClass __opClass) : + Mem(mnem, _machInst, __opClass) + { + imm = sign_ext(SIMM13, 13); + } + + std::string generateDisassembly(Addr pc, + const SymbolTable *symtab) const; + + int32_t imm; + }; +}}; + +output decoder {{ + std::string Mem::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { + std::stringstream response; + bool load = flags[IsLoad]; + bool save = flags[IsStore]; + + printMnemonic(response, mnemonic); + if(save) + { + printReg(response, _srcRegIdx[0]); + ccprintf(response, ", "); + } + ccprintf(response, "[ "); + printReg(response, _srcRegIdx[!save ? 0 : 1]); + ccprintf(response, " + "); + printReg(response, _srcRegIdx[!save ? 1 : 2]); + ccprintf(response, " ]"); + if(load) + { + ccprintf(response, ", "); + printReg(response, _destRegIdx[0]); + } + + return response.str(); + } + + std::string MemImm::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { + std::stringstream response; + bool load = flags[IsLoad]; + bool save = flags[IsStore]; + + printMnemonic(response, mnemonic); + if(save) + { + printReg(response, _srcRegIdx[0]); + ccprintf(response, ", "); + } + ccprintf(response, "[ "); + printReg(response, _srcRegIdx[!save ? 0 : 1]); + if(imm >= 0) + ccprintf(response, " + 0x%x ]", imm); + else + ccprintf(response, " + -0x%x ]", -imm); + if(load) + { + ccprintf(response, ", "); + printReg(response, _destRegIdx[0]); + } + + return response.str(); + } +}}; + +def template MemExecute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Fault fault = NoFault; + Addr EA; + %(op_decl)s; + %(op_rd)s; + %(ea_code)s; + DPRINTF(Sparc, "The address is 0x%x\n", EA); + %(load)s; + %(code)s; + %(store)s; + + if(fault == NoFault) + { + //Write the resulting state to the execution context + %(op_wb)s; + } + + return fault; + } +}}; + +let {{ + # Leave memAccessFlags at 0 for now + loadString = "xc->read(EA, (uint%(width)s_t&)Mem, 0);" + storeString = "uint64_t write_result = 0; \ + xc->write((uint%(width)s_t)Mem, EA, 0, &write_result);" + + def doMemFormat(code, load, store, name, Name, opt_flags): + addrCalcReg = 'EA = Rs1 + Rs2;' + addrCalcImm = 'EA = Rs1 + imm;' + iop = InstObjParams(name, Name, 'Mem', code, + opt_flags, ("ea_code", addrCalcReg), + ("load", load), ("store", store)) + iop_imm = InstObjParams(name, Name + 'Imm', 'MemImm', code, + opt_flags, ("ea_code", addrCalcImm), + ("load", load), ("store", store)) + header_output = BasicDeclare.subst(iop) + BasicDeclare.subst(iop_imm) + decoder_output = BasicConstructor.subst(iop) + BasicConstructor.subst(iop_imm) + decode_block = ROrImmDecode.subst(iop) + exec_output = MemExecute.subst(iop) + MemExecute.subst(iop_imm) + return (header_output, decoder_output, exec_output, decode_block) +}}; + +def format Load(code, width, *opt_flags) {{ + (header_output, + decoder_output, + exec_output, + decode_block) = doMemFormat(code, + loadString % {"width":width}, '', name, Name, opt_flags) +}}; + +def format Store(code, width, *opt_flags) {{ + (header_output, + decoder_output, + exec_output, + decode_block) = doMemFormat(code, '', + storeString % {"width":width}, name, Name, opt_flags) +}}; + +def format LoadStore(code, width, *opt_flags) {{ + (header_output, + decoder_output, + exec_output, + decode_block) = doMemFormat(code, + loadString % {"width":width}, storeString % {"width":width}, + name, Name, opt_flags) +}}; diff --git a/src/arch/sparc/isa/formats/nop.isa b/src/arch/sparc/isa/formats/nop.isa new file mode 100644 index 000000000..37ef2e8d0 --- /dev/null +++ b/src/arch/sparc/isa/formats/nop.isa @@ -0,0 +1,98 @@ +// Copyright (c) 2006 The Regents of The University of Michigan +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: Gabe Black +// Steve Reinhardt + +//////////////////////////////////////////////////////////////////// +// +// Nop instruction +// + +// Per-cpu-model nop execute method. +def template NopExec {{ + + Fault execute(%(CPU_exec_context)s *xc, Trace::InstRecord *traceData) const + { + // Nothing to see here, move along + return NoFault; + } +}}; + +output header {{ + /** + * Nop class. + */ + class Nop : public SparcStaticInst + { + public: + // Constructor + Nop(const char *mnem, ExtMachInst _machInst, OpClass __opClass) : + SparcStaticInst(mnem, _machInst, __opClass) + { + } + + // All Nop instructions do the same thing, so this can be + // defined here. Nops can be defined directly, so there + // needs to be a default implementation. Interpolate via + // template so i gets expanded to a set of + // cpu-model-specific functions. + %(NopExec)s + + std::string generateDisassembly(Addr pc, + const SymbolTable *symtab) const; + }; +}}; + +output decoder {{ + std::string Nop::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { + std::stringstream response; + printMnemonic(response, mnemonic); + return response.str(); + } +}}; + +def template NopExecute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + //Nothing to see here, move along + return NoFault; + } +}}; + +// Primary format for integer operate instructions: +def format Nop(code, *opt_flags) {{ + orig_code = code + cblk = CodeBlock(code) + iop = InstObjParams(name, Name, 'Nop', cblk, opt_flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = NopExecute.subst(iop) +}}; diff --git a/src/arch/sparc/isa/formats/priv.isa b/src/arch/sparc/isa/formats/priv.isa new file mode 100644 index 000000000..7df59d736 --- /dev/null +++ b/src/arch/sparc/isa/formats/priv.isa @@ -0,0 +1,125 @@ +// Copyright (c) 2006 The Regents of The University of Michigan +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: Ali Saidi +// Gabe Black +// Steve Reinhardt + +//////////////////////////////////////////////////////////////////// +// +// Privilege mode instructions +// + +output header {{ + /** + * Base class for privelege mode operations. + */ + class Priv : public SparcStaticInst + { + protected: + // Constructor + Priv(const char *mnem, ExtMachInst _machInst, OpClass __opClass) : + SparcStaticInst(mnem, _machInst, __opClass) + { + } + + std::string generateDisassembly(Addr pc, + const SymbolTable *symtab) const; + }; + + /** + * Base class for privelege mode operations with immediates. + */ + class PrivImm : public Priv + { + protected: + // Constructor + PrivImm(const char *mnem, ExtMachInst _machInst, + OpClass __opClass) : + Priv(mnem, _machInst, __opClass), imm(SIMM13) + { + } + + int32_t imm; + }; + +}}; + +output decoder {{ + std::string Priv::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { + return "Privileged Instruction"; + } +}}; + +def template PrivExecute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + %(op_decl)s; + %(op_rd)s; + + //If the processor isn't in privileged mode, fault out right away + if(%(check)s) + return new PrivilegedAction; + + %(code)s; + %(op_wb)s; + return NoFault; + } +}}; + +let {{ + def doPrivFormat(code, checkCode, name, Name, opt_flags): + (usesImm, code, immCode, + rString, iString) = splitOutImm(code) + iop = InstObjParams(name, Name, 'Priv', code, + opt_flags, ("check", checkCode)) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + exec_output = PrivExecute.subst(iop) + if usesImm: + imm_iop = InstObjParams(name, Name + 'Imm', 'PrivImm', + immCode, opt_flags, ("check", checkCode)) + header_output += BasicDeclare.subst(imm_iop) + decoder_output += BasicConstructor.subst(imm_iop) + exec_output += PrivExecute.subst(imm_iop) + decode_block = ROrImmDecode.subst(iop) + else: + decode_block = BasicDecode.subst(iop) + return (header_output, decoder_output, exec_output, decode_block) +}}; + +// Primary format for integer operate instructions: +def format Priv(code, *opt_flags) {{ + checkCode = "((xc->readMiscReg(PrStart + MISCREG_PSTATE))<2:2>)" + (header_output, decoder_output, + exec_output, decode_block) = doPrivFormat(code, + checkCode, name, Name, opt_flags) +}}; + + diff --git a/src/arch/sparc/isa/formats/trap.isa b/src/arch/sparc/isa/formats/trap.isa new file mode 100644 index 000000000..04d467cfe --- /dev/null +++ b/src/arch/sparc/isa/formats/trap.isa @@ -0,0 +1,93 @@ +// Copyright (c) 2006 The Regents of The University of Michigan +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: Gabe Black +// Steve Reinhardt + +//////////////////////////////////////////////////////////////////// +// +// Trap instructions +// + +output header {{ + /** + * Base class for trap instructions, + * or instructions that always fault. + */ + class Trap : public SparcStaticInst + { + protected: + + // Constructor + Trap(const char *mnem, ExtMachInst _machInst, OpClass __opClass) : + SparcStaticInst(mnem, _machInst, __opClass), trapNum(SW_TRAP) + { + } + + std::string generateDisassembly(Addr pc, + const SymbolTable *symtab) const; + + int trapNum; + }; +}}; + +output decoder {{ + std::string Trap::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { + std::stringstream response; + + printMnemonic(response, mnemonic); + ccprintf(response, " "); + printReg(response, _srcRegIdx[0]); + ccprintf(response, ", 0x%x", trapNum); + ccprintf(response, ", or "); + printReg(response, _srcRegIdx[1]); + return response.str(); + } +}}; + +def template TrapExecute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Fault fault = NoFault; + %(op_decl)s; + %(op_rd)s; + %(code)s + return fault; + } +}}; + +def format Trap(code, *opt_flags) {{ + orig_code = code + cblk = CodeBlock(code) + iop = InstObjParams(name, Name, 'Trap', cblk, opt_flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = TrapExecute.subst(iop) +}}; diff --git a/src/arch/sparc/isa/formats/unknown.isa b/src/arch/sparc/isa/formats/unknown.isa new file mode 100644 index 000000000..8541d6a62 --- /dev/null +++ b/src/arch/sparc/isa/formats/unknown.isa @@ -0,0 +1,75 @@ +// Copyright (c) 2006 The Regents of The University of Michigan +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: Gabe Black +// Steve Reinhardt + +//////////////////////////////////////////////////////////////////// +// +// Unknown instructions +// + +output header {{ + /** + * Class for Unknown/Illegal instructions + */ + class Unknown : public SparcStaticInst + { + public: + + // Constructor + Unknown(ExtMachInst _machInst) : + SparcStaticInst("unknown", _machInst, No_OpClass) + { + } + + %(BasicExecDeclare)s + + std::string generateDisassembly(Addr pc, + const SymbolTable *symtab) const; + + }; +}}; + +output decoder {{ + std::string Unknown::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { + return "Unknown instruction"; + } +}}; + +output exec {{ + Fault Unknown::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + return new IllegalInstruction; + } +}}; + +def format Unknown() {{ + decode_block = 'return new Unknown(machInst);\n' +}}; diff --git a/src/arch/sparc/isa/includes.isa b/src/arch/sparc/isa/includes.isa new file mode 100644 index 000000000..762de243a --- /dev/null +++ b/src/arch/sparc/isa/includes.isa @@ -0,0 +1,76 @@ +// Copyright (c) 2006 The Regents of The University of Michigan +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: Ali Saidi +// Gabe Black +// Steve Reinhardt + +//////////////////////////////////////////////////////////////////// +// +// Output include file directives. +// + +output header {{ +#include <sstream> +#include <iostream> +#include <iomanip> + +#include "cpu/static_inst.hh" +#include "arch/sparc/faults.hh" +#include "mem/request.hh" // some constructors use MemReq flags +#include "arch/sparc/isa_traits.hh" +#include "arch/sparc/regfile.hh" +}}; + +output decoder {{ +#include "base/cprintf.hh" +#include "base/loader/symtab.hh" +#include "cpu/exec_context.hh" // for Jump::branchTarget() + +#include <math.h> +#if defined(linux) +#include <fenv.h> +#endif + +using namespace SparcISA; +}}; + +output exec {{ +#include <math.h> +#if defined(linux) +#include <fenv.h> +#endif + +#ifdef FULL_SYSTEM +//#include "sim/pseudo_inst.hh" +#endif +#include "cpu/base.hh" +#include "cpu/exetrace.hh" +#include "sim/sim_exit.hh" + +using namespace SparcISA; +}}; + diff --git a/src/arch/sparc/isa/main.isa b/src/arch/sparc/isa/main.isa new file mode 100644 index 000000000..79be0e2a3 --- /dev/null +++ b/src/arch/sparc/isa/main.isa @@ -0,0 +1,59 @@ +// -*- mode:c++ -*- + +// Copyright (c) 2003-2005 The Regents of The University of Michigan +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +//////////////////////////////////////////////////////////////////// +// +// SPARC ISA description file. +// +//////////////////////////////////////////////////////////////////// + +//Include the C++ include directives +##include "includes.isa" + +//////////////////////////////////////////////////////////////////// +// +// Namespace statement. Everything below this line will be in the +// SparcISAInst namespace. +// + +namespace SparcISA; + +//Include the bitfield definitions +##include "bitfields.isa" + +//Include the operand_types and operand definitions +##include "operands.isa" + +//Include the base class for sparc instructions, and some support code +##include "base.isa" + +//Include the definitions for the instruction formats +##include "formats.isa" + +//Include the decoder definition +##include "decoder.isa" diff --git a/src/arch/sparc/isa/operands.isa b/src/arch/sparc/isa/operands.isa new file mode 100644 index 000000000..9e5c783e8 --- /dev/null +++ b/src/arch/sparc/isa/operands.isa @@ -0,0 +1,88 @@ +// Copyright (c) 2006 The Regents of The University of Michigan +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: Ali Saidi +// Gabe Black +// Steve Reinhardt + +def operand_types {{ + 'sb' : ('signed int', 8), + 'ub' : ('unsigned int', 8), + 'shw' : ('signed int', 16), + 'uhw' : ('unsigned int', 16), + 'sw' : ('signed int', 32), + 'uw' : ('unsigned int', 32), + 'sdw' : ('signed int', 64), + 'udw' : ('unsigned int', 64), + 'sf' : ('float', 32), + 'df' : ('float', 64), + 'qf' : ('float', 128) +}}; + +def operands {{ + # Int regs default to unsigned, but code should not count on this. + # For clarity, descriptions that depend on unsigned behavior should + # explicitly specify '.uq'. + 'Rd': ('IntReg', 'udw', 'RD', 'IsInteger', 1), + 'RdLow': ('IntReg', 'udw', 'RD & (~1)', 'IsInteger', 2), + 'RdHigh': ('IntReg', 'udw', 'RD | 1', 'IsInteger', 3), + 'Rs1': ('IntReg', 'udw', 'RS1', 'IsInteger', 4), + 'Rs2': ('IntReg', 'udw', 'RS2', 'IsInteger', 5), + #'Fa': ('FloatReg', 'df', 'FA', 'IsFloating', 1), + #'Fb': ('FloatReg', 'df', 'FB', 'IsFloating', 2), + #'Fc': ('FloatReg', 'df', 'FC', 'IsFloating', 3), + 'Mem': ('Mem', 'udw', None, ('IsMemRef', 'IsLoad', 'IsStore'), 4), + 'NPC': ('NPC', 'udw', None, ( None, None, 'IsControl' ), 4), + 'NNPC': ('NNPC', 'udw', None, (None, None, 'IsControl' ), 4), + #'Runiq': ('ControlReg', 'uq', 'Uniq', None, 1), + #'FPCR': ('ControlReg', 'uq', 'Fpcr', None, 1), + 'R0': ('IntReg', 'udw', '0', None, 6), + 'R1': ('IntReg', 'udw', '1', None, 7), + 'R15': ('IntReg', 'udw', '15', 'IsInteger', 8), + 'R16': ('IntReg', 'udw', '16', None, 9), + + # Control registers + 'Y': ('ControlReg', 'udw', 'MISCREG_Y', None, 12), + 'Ccr': ('ControlReg', 'udw', 'MISCREG_CCR', None, 17), + 'Asi': ('ControlReg', 'udw', 'MISCREG_ASI', None, 26), + + 'Tpc': ('ControlReg', 'udw', 'MISCREG_TPC', None, 28), + 'Tnpc': ('ControlReg', 'udw', 'MISCREG_TNPC', None, 28), + 'Tstate': ('ControlReg', 'udw', 'MISCREG_TSTATE', None, 28), + 'Pstate': ('ControlReg', 'udw', 'MISCREG_PSTATE', None, 1), + 'Tl': ('ControlReg', 'udw', 'MISCREG_TL', None, 27), + + 'Cwp': ('ControlReg', 'udw', 'MISCREG_CWP', None, 15), + 'Cansave': ('ControlReg', 'udw', 'MISCREG_CANSAVE', None, 34), + 'Canrestore': ('ControlReg', 'udw', 'MISCREG_CANRESTORE', None, 35), + 'Cleanwin': ('ControlReg', 'udw', 'MISCREG_CLEANWIN', None, 37), + 'Otherwin': ('ControlReg', 'udw', 'MISCREG_OTHERWIN', None, 36), + 'Wstate': ('ControlReg', 'udw', 'MISCREG_WSTATE', None, 38), + 'Gl': ('ControlReg', 'udw', 'MISCREG_GL', None, 12), + + 'Fsr': ('ControlReg', 'udw', 'MISCREG_FSR', None, 47) + +}}; diff --git a/src/arch/sparc/isa_traits.hh b/src/arch/sparc/isa_traits.hh new file mode 100644 index 000000000..3d55ff361 --- /dev/null +++ b/src/arch/sparc/isa_traits.hh @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ARCH_SPARC_ISA_TRAITS_HH__ +#define __ARCH_SPARC_ISA_TRAITS_HH__ + +#include "base/misc.hh" +#include "config/full_system.hh" +#include "sim/host.hh" + +class ExecContext; +class FastCPU; +//class FullCPU; +class Checkpoint; + +class StaticInst; +class StaticInstPtr; + +namespace BigEndianGuest {} + +#if !FULL_SYSTEM +class SyscallReturn +{ + public: + template <class T> + SyscallReturn(T v, bool s) + { + retval = (uint64_t)v; + success = s; + } + + template <class T> + SyscallReturn(T v) + { + success = (v >= 0); + retval = (uint64_t)v; + } + + ~SyscallReturn() {} + + SyscallReturn& operator=(const SyscallReturn& s) + { + retval = s.retval; + success = s.success; + return *this; + } + + bool successful() { return success; } + uint64_t value() { return retval; } + + private: + uint64_t retval; + bool success; +}; + +#endif + +#if FULL_SYSTEM +#include "arch/sparc/isa_fullsys_traits.hh" +#endif + +namespace SparcISA +{ + + // These enumerate all the registers for dependence tracking. + enum DependenceTags { + // 0..31 are the integer regs 0..31 + // 32..63 are the FP regs 0..31, i.e. use (reg + FP_Base_DepTag) + FP_Base_DepTag = 32, + Ctrl_Base_DepTag = 96, + //XXX These are here solely to get compilation and won't work + Fpcr_DepTag = 0, + Uniq_DepTag = 0 + }; + + //This makes sure the big endian versions of certain functions are used. + using namespace BigEndianGuest; + + typedef uint32_t MachInst; + typedef uint64_t ExtMachInst; + + const int NumIntRegs = 32; + const int NumFloatRegs = 64; + const int NumMiscRegs = 32; + + // semantically meaningful register indices + const int ZeroReg = 0; // architecturally meaningful + // the rest of these depend on the ABI + const int StackPointerReg = 14; + const int ReturnAddressReg = 31; // post call, precall is 15 + const int ReturnValueReg = 8; // Post return, 24 is pre-return. + const int FramePointerReg = 30; + const int ArgumentReg0 = 8; + const int ArgumentReg1 = 9; + const int ArgumentReg2 = 10; + const int ArgumentReg3 = 11; + const int ArgumentReg4 = 12; + const int ArgumentReg5 = 13; + // Some OS syscall use a second register (o1) to return a second value + const int SyscallPseudoReturnReg = ArgumentReg1; + + //XXX These numbers are bogus + const int MaxInstSrcRegs = 8; + const int MaxInstDestRegs = 9; + + typedef uint64_t IntReg; + + // control register file contents + typedef uint64_t MiscReg; + + typedef double FloatReg; + typedef uint64_t FloatRegBits; + + //8K. This value is implmentation specific; and should probably + //be somewhere else. + const int LogVMPageSize = 13; + const int VMPageSize = (1 << LogVMPageSize); + + //Why does both the previous set of constants and this one exist? + const int PageShift = 13; + const int PageBytes = ULL(1) << PageShift; + + const int BranchPredAddrShiftAmt = 2; + + const int MachineBytes = 8; + const int WordBytes = 4; + const int HalfwordBytes = 2; + const int ByteBytes = 1; + + void serialize(std::ostream & os); + + void unserialize(Checkpoint *cp, const std::string §ion); + + StaticInstPtr decodeInst(ExtMachInst); + + // return a no-op instruction... used for instruction fetch faults + extern const MachInst NoopMachInst; +} + +#include "arch/sparc/regfile.hh" + +namespace SparcISA +{ + +#if !FULL_SYSTEM + static inline void setSyscallReturn(SyscallReturn return_value, + RegFile *regs) + { + // check for error condition. SPARC syscall convention is to + // indicate success/failure in reg the carry bit of the ccr + // and put the return value itself in the standard return value reg (). + if (return_value.successful()) { + // no error, clear XCC.C + regs->setMiscReg(MISCREG_CCR, regs->readMiscReg(MISCREG_CCR) & 0xEF); + regs->setIntReg(ReturnValueReg, return_value.value()); + } else { + // got an error, set XCC.C + regs->setMiscReg(MISCREG_CCR, regs->readMiscReg(MISCREG_CCR) | 0x10); + regs->setIntReg(ReturnValueReg, return_value.value()); + } + } +#endif +}; + +#endif // __ARCH_SPARC_ISA_TRAITS_HH__ diff --git a/src/arch/sparc/linux/linux.cc b/src/arch/sparc/linux/linux.cc new file mode 100644 index 000000000..c7ed29358 --- /dev/null +++ b/src/arch/sparc/linux/linux.cc @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "arch/sparc/linux/linux.hh" + +// open(2) flags translation table +OpenFlagTransTable SparcLinux::openFlagTable[] = { +#ifdef _MSC_VER + { SparcLinux::TGT_O_RDONLY, _O_RDONLY }, + { SparcLinux::TGT_O_WRONLY, _O_WRONLY }, + { SparcLinux::TGT_O_RDWR, _O_RDWR }, + { SparcLinux::TGT_O_APPEND, _O_APPEND }, + { SparcLinux::TGT_O_CREAT, _O_CREAT }, + { SparcLinux::TGT_O_TRUNC, _O_TRUNC }, + { SparcLinux::TGT_O_EXCL, _O_EXCL }, +#ifdef _O_NONBLOCK + { SparcLinux::TGT_O_NONBLOCK, _O_NONBLOCK }, +#endif +#ifdef _O_NOCTTY + { SparcLinux::TGT_O_NOCTTY, _O_NOCTTY }, +#endif +#ifdef _O_SYNC + { SparcLinux::TGT_O_SYNC, _O_SYNC }, +#endif +#else /* !_MSC_VER */ + { SparcLinux::TGT_O_RDONLY, O_RDONLY }, + { SparcLinux::TGT_O_WRONLY, O_WRONLY }, + { SparcLinux::TGT_O_RDWR, O_RDWR }, + { SparcLinux::TGT_O_APPEND, O_APPEND }, + { SparcLinux::TGT_O_CREAT, O_CREAT }, + { SparcLinux::TGT_O_TRUNC, O_TRUNC }, + { SparcLinux::TGT_O_EXCL, O_EXCL }, + { SparcLinux::TGT_O_NONBLOCK, O_NONBLOCK }, + { SparcLinux::TGT_O_NOCTTY, O_NOCTTY }, +#ifdef O_SYNC + { SparcLinux::TGT_O_SYNC, O_SYNC }, +#endif +#endif /* _MSC_VER */ +}; + +const int SparcLinux::NUM_OPEN_FLAGS = + (sizeof(SparcLinux::openFlagTable)/sizeof(SparcLinux::openFlagTable[0])); + diff --git a/src/arch/sparc/linux/linux.hh b/src/arch/sparc/linux/linux.hh new file mode 100644 index 000000000..9cde5bb9c --- /dev/null +++ b/src/arch/sparc/linux/linux.hh @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ARCH_SPARC_LINUX_LINUX_HH__ +#define __ARCH_SPARC_LINUX_LINUX_HH__ + +#include "kern/linux/linux.hh" + +class SparcLinux : public Linux +{ + public: + + static OpenFlagTransTable openFlagTable[]; + + static const int TGT_O_RDONLY = 0x00000000; //!< O_RDONLY + static const int TGT_O_WRONLY = 0x00000001; //!< O_WRONLY + static const int TGT_O_RDWR = 0x00000002; //!< O_RDWR + static const int TGT_O_NONBLOCK = 0x00004000; //!< O_NONBLOCK + static const int TGT_O_APPEND = 0x00000008; //!< O_APPEND + static const int TGT_O_CREAT = 0x00000200; //!< O_CREAT + static const int TGT_O_TRUNC = 0x00000400; //!< O_TRUNC + static const int TGT_O_EXCL = 0x00000800; //!< O_EXCL + static const int TGT_O_NOCTTY = 0x00008000; //!< O_NOCTTY + static const int TGT_O_SYNC = 0x00002000; //!< O_SYNC +// static const int TGT_O_DRD = 0x00010000; //!< O_DRD +// static const int TGT_O_DIRECTIO = 0x00020000; //!< O_DIRECTIO +// static const int TGT_O_CACHE = 0x00002000; //!< O_CACHE +// static const int TGT_O_DSYNC = 0x00008000; //!< O_DSYNC +// static const int TGT_O_RSYNC = 0x00040000; //!< O_RSYNC + + static const int NUM_OPEN_FLAGS; + + static const unsigned TGT_MAP_ANONYMOUS = 0x20; +}; + +#endif diff --git a/src/arch/sparc/linux/process.cc b/src/arch/sparc/linux/process.cc new file mode 100644 index 000000000..71be6a83a --- /dev/null +++ b/src/arch/sparc/linux/process.cc @@ -0,0 +1,407 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "arch/sparc/isa_traits.hh" +#include "arch/sparc/linux/process.hh" +#include "arch/sparc/regfile.hh" + +#include "base/trace.hh" +#include "cpu/exec_context.hh" +#include "kern/linux/linux.hh" + +#include "sim/process.hh" +#include "sim/syscall_emul.hh" + +using namespace std; +using namespace SparcISA; + + +/// Target uname() handler. +static SyscallReturn +unameFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + TypedBufferArg<Linux::utsname> name(xc->getSyscallArg(0)); + + strcpy(name->sysname, "Linux"); + strcpy(name->nodename, "m5.eecs.umich.edu"); + strcpy(name->release, "2.4.20"); + strcpy(name->version, "#1 Mon Aug 18 11:32:15 EDT 2003"); + strcpy(name->machine, "sparc"); + + name.copyOut(xc->getMemPort()); + + return 0; +} + + +SyscallReturn SparcISA::getresuidFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc) +{ + const IntReg id = htog(100); + Addr ruid = xc->getSyscallArg(0); + Addr euid = xc->getSyscallArg(1); + Addr suid = xc->getSyscallArg(2); + //Handle the EFAULT case + //Set the ruid + if(ruid) + { + BufferArg ruidBuff(ruid, sizeof(IntReg)); + memcpy(ruidBuff.bufferPtr(), &id, sizeof(IntReg)); + ruidBuff.copyOut(xc->getMemPort()); + } + //Set the euid + if(euid) + { + BufferArg euidBuff(euid, sizeof(IntReg)); + memcpy(euidBuff.bufferPtr(), &id, sizeof(IntReg)); + euidBuff.copyOut(xc->getMemPort()); + } + //Set the suid + if(suid) + { + BufferArg suidBuff(suid, sizeof(IntReg)); + memcpy(suidBuff.bufferPtr(), &id, sizeof(IntReg)); + suidBuff.copyOut(xc->getMemPort()); + } + return 0; +} + +SyscallDesc SparcLinuxProcess::syscallDescs[] = { + /* 0 */ SyscallDesc("restart_syscall", unimplementedFunc), + /* 1 */ SyscallDesc("exit", exitFunc), + /* 2 */ SyscallDesc("fork", unimplementedFunc), + /* 3 */ SyscallDesc("read", readFunc), + /* 4 */ SyscallDesc("write", writeFunc), + /* 5 */ SyscallDesc("open", openFunc<SparcLinux>), + /* 6 */ SyscallDesc("close", closeFunc), + /* 7 */ SyscallDesc("wait4", unimplementedFunc), + /* 8 */ SyscallDesc("creat", unimplementedFunc), + /* 9 */ SyscallDesc("link", unimplementedFunc), + /* 10 */ SyscallDesc("unlink", unlinkFunc), + /* 11 */ SyscallDesc("execv", unimplementedFunc), + /* 12 */ SyscallDesc("chdir", unimplementedFunc), + /* 13 */ SyscallDesc("chown", chownFunc), + /* 14 */ SyscallDesc("mknod", unimplementedFunc), + /* 15 */ SyscallDesc("chmod", chmodFunc<Linux>), + /* 16 */ SyscallDesc("lchown", unimplementedFunc), + /* 17 */ SyscallDesc("brk", obreakFunc), + /* 18 */ SyscallDesc("perfctr", unimplementedFunc), + /* 19 */ SyscallDesc("lseek", lseekFunc), + /* 20 */ SyscallDesc("getpid", getpidFunc), + /* 21 */ SyscallDesc("capget", unimplementedFunc), + /* 22 */ SyscallDesc("capset", unimplementedFunc), + /* 23 */ SyscallDesc("setuid", setuidFunc), + /* 24 */ SyscallDesc("getuid", getuidFunc), + /* 25 */ SyscallDesc("time", unimplementedFunc), + /* 26 */ SyscallDesc("ptrace", unimplementedFunc), + /* 27 */ SyscallDesc("alarm", unimplementedFunc), + /* 28 */ SyscallDesc("sigaltstack", unimplementedFunc), + /* 29 */ SyscallDesc("pause", unimplementedFunc), + /* 30 */ SyscallDesc("utime", unimplementedFunc), + /* 31 */ SyscallDesc("lchown32", unimplementedFunc), + /* 32 */ SyscallDesc("fchown32", unimplementedFunc), + /* 33 */ SyscallDesc("access", unimplementedFunc), + /* 34 */ SyscallDesc("nice", unimplementedFunc), + /* 35 */ SyscallDesc("chown32", unimplementedFunc), + /* 36 */ SyscallDesc("sync", unimplementedFunc), + /* 37 */ SyscallDesc("kill", unimplementedFunc), + /* 38 */ SyscallDesc("stat", unimplementedFunc), + /* 39 */ SyscallDesc("sendfile", unimplementedFunc), + /* 40 */ SyscallDesc("lstat", unimplementedFunc), + /* 41 */ SyscallDesc("dup", unimplementedFunc), + /* 42 */ SyscallDesc("pipe", pipePseudoFunc), + /* 43 */ SyscallDesc("times", unimplementedFunc), + /* 44 */ SyscallDesc("getuid32", unimplementedFunc), + /* 45 */ SyscallDesc("umount2", unimplementedFunc), + /* 46 */ SyscallDesc("setgid", unimplementedFunc), + /* 47 */ SyscallDesc("getgid", getgidFunc), + /* 48 */ SyscallDesc("signal", unimplementedFunc), + /* 49 */ SyscallDesc("geteuid", geteuidFunc), + /* 50 */ SyscallDesc("getegid", getegidFunc), + /* 51 */ SyscallDesc("acct", unimplementedFunc), + /* 52 */ SyscallDesc("memory_ordering", unimplementedFunc), + /* 53 */ SyscallDesc("getgid32", unimplementedFunc), + /* 54 */ SyscallDesc("ioctl", unimplementedFunc), + /* 55 */ SyscallDesc("reboot", unimplementedFunc), + /* 56 */ SyscallDesc("mmap2", unimplementedFunc), + /* 57 */ SyscallDesc("symlink", unimplementedFunc), + /* 58 */ SyscallDesc("readlink", unimplementedFunc), + /* 59 */ SyscallDesc("execve", unimplementedFunc), + /* 60 */ SyscallDesc("umask", unimplementedFunc), + /* 61 */ SyscallDesc("chroot", unimplementedFunc), + /* 62 */ SyscallDesc("fstat", fstatFunc<SparcLinux>), + /* 63 */ SyscallDesc("fstat64", unimplementedFunc), + /* 64 */ SyscallDesc("getpagesize", unimplementedFunc), + /* 65 */ SyscallDesc("msync", unimplementedFunc), + /* 66 */ SyscallDesc("vfork", unimplementedFunc), + /* 67 */ SyscallDesc("pread64", unimplementedFunc), + /* 68 */ SyscallDesc("pwrite64", unimplementedFunc), + /* 69 */ SyscallDesc("geteuid32", unimplementedFunc), + /* 70 */ SyscallDesc("getdgid32", unimplementedFunc), + /* 71 */ SyscallDesc("mmap", mmapFunc<SparcLinux>), + /* 72 */ SyscallDesc("setreuid32", unimplementedFunc), + /* 73 */ SyscallDesc("munmap", munmapFunc), + /* 74 */ SyscallDesc("mprotect", unimplementedFunc), + /* 75 */ SyscallDesc("madvise", unimplementedFunc), + /* 76 */ SyscallDesc("vhangup", unimplementedFunc), + /* 77 */ SyscallDesc("truncate64", unimplementedFunc), + /* 78 */ SyscallDesc("mincore", unimplementedFunc), + /* 79 */ SyscallDesc("getgroups", unimplementedFunc), + /* 80 */ SyscallDesc("setgroups", unimplementedFunc), + /* 81 */ SyscallDesc("getpgrp", unimplementedFunc), + /* 82 */ SyscallDesc("setgroups32", unimplementedFunc), + /* 83 */ SyscallDesc("setitimer", unimplementedFunc), + /* 84 */ SyscallDesc("ftruncate64", unimplementedFunc), + /* 85 */ SyscallDesc("swapon", unimplementedFunc), + /* 86 */ SyscallDesc("getitimer", unimplementedFunc), + /* 87 */ SyscallDesc("setuid32", unimplementedFunc), + /* 88 */ SyscallDesc("sethostname", unimplementedFunc), + /* 89 */ SyscallDesc("setgid32", unimplementedFunc), + /* 90 */ SyscallDesc("dup2", unimplementedFunc), + /* 91 */ SyscallDesc("setfsuid32", unimplementedFunc), + /* 92 */ SyscallDesc("fcntl", unimplementedFunc), + /* 93 */ SyscallDesc("select", unimplementedFunc), + /* 94 */ SyscallDesc("setfsgid32", unimplementedFunc), + /* 95 */ SyscallDesc("fsync", unimplementedFunc), + /* 96 */ SyscallDesc("setpriority", unimplementedFunc), + /* 97 */ SyscallDesc("socket", unimplementedFunc), + /* 98 */ SyscallDesc("connect", unimplementedFunc), + /* 99 */ SyscallDesc("accept", unimplementedFunc), + /* 100 */ SyscallDesc("getpriority", unimplementedFunc), + /* 101 */ SyscallDesc("rt_sigreturn", unimplementedFunc), + /* 102 */ SyscallDesc("rt_sigaction", unimplementedFunc), + /* 103 */ SyscallDesc("rt_sigprocmask", unimplementedFunc), + /* 104 */ SyscallDesc("rt_sigpending", unimplementedFunc), + /* 105 */ SyscallDesc("rt_sigtimedwait", unimplementedFunc), + /* 106 */ SyscallDesc("rt_sigqueueinfo", unimplementedFunc), + /* 107 */ SyscallDesc("rt_sigsuspend", unimplementedFunc), + /* 108 */ SyscallDesc("setresuid", unimplementedFunc), + /* 109 */ SyscallDesc("getresuid", getresuidFunc), + /* 110 */ SyscallDesc("setresgid", unimplementedFunc), + /* 111 */ SyscallDesc("getresgid", unimplementedFunc), + /* 112 */ SyscallDesc("setregid32", unimplementedFunc), + /* 113 */ SyscallDesc("recvmsg", unimplementedFunc), + /* 114 */ SyscallDesc("sendmsg", unimplementedFunc), + /* 115 */ SyscallDesc("getgroups32", unimplementedFunc), + /* 116 */ SyscallDesc("gettimeofday", unimplementedFunc), + /* 117 */ SyscallDesc("getrusage", unimplementedFunc), + /* 118 */ SyscallDesc("getsockopt", unimplementedFunc), + /* 119 */ SyscallDesc("getcwd", unimplementedFunc), + /* 120 */ SyscallDesc("readv", unimplementedFunc), + /* 121 */ SyscallDesc("writev", unimplementedFunc), + /* 122 */ SyscallDesc("settimeofday", unimplementedFunc), + /* 123 */ SyscallDesc("fchown", unimplementedFunc), + /* 124 */ SyscallDesc("fchmod", unimplementedFunc), + /* 125 */ SyscallDesc("recvfrom", unimplementedFunc), + /* 126 */ SyscallDesc("setreuid", unimplementedFunc), + /* 127 */ SyscallDesc("setregid", unimplementedFunc), + /* 128 */ SyscallDesc("rename", unimplementedFunc), + /* 129 */ SyscallDesc("truncate", unimplementedFunc), + /* 130 */ SyscallDesc("ftruncate", unimplementedFunc), + /* 131 */ SyscallDesc("flock", unimplementedFunc), + /* 132 */ SyscallDesc("lstat64", unimplementedFunc), + /* 133 */ SyscallDesc("sendto", unimplementedFunc), + /* 134 */ SyscallDesc("shutdown", unimplementedFunc), + /* 135 */ SyscallDesc("socketpair", unimplementedFunc), + /* 136 */ SyscallDesc("mkdir", unimplementedFunc), + /* 137 */ SyscallDesc("rmdir", unimplementedFunc), + /* 138 */ SyscallDesc("utimes", unimplementedFunc), + /* 139 */ SyscallDesc("stat64", unimplementedFunc), + /* 140 */ SyscallDesc("sendfile64", unimplementedFunc), + /* 141 */ SyscallDesc("getpeername", unimplementedFunc), + /* 142 */ SyscallDesc("futex", unimplementedFunc), + /* 143 */ SyscallDesc("gettid", unimplementedFunc), + /* 144 */ SyscallDesc("getrlimit", unimplementedFunc), + /* 145 */ SyscallDesc("setrlimit", unimplementedFunc), + /* 146 */ SyscallDesc("pivot_root", unimplementedFunc), + /* 147 */ SyscallDesc("prctl", unimplementedFunc), + /* 148 */ SyscallDesc("pciconfig_read", unimplementedFunc), + /* 149 */ SyscallDesc("pciconfig_write", unimplementedFunc), + /* 150 */ SyscallDesc("getsockname", unimplementedFunc), + /* 151 */ SyscallDesc("inotify_init", unimplementedFunc), + /* 152 */ SyscallDesc("inotify_add_watch", unimplementedFunc), + /* 153 */ SyscallDesc("poll", unimplementedFunc), + /* 154 */ SyscallDesc("getdents64", unimplementedFunc), + /* 155 */ SyscallDesc("fcntl64", unimplementedFunc), + /* 156 */ SyscallDesc("inotify_rm_watch", unimplementedFunc), + /* 157 */ SyscallDesc("statfs", unimplementedFunc), + /* 158 */ SyscallDesc("fstatfs", unimplementedFunc), + /* 159 */ SyscallDesc("umount", unimplementedFunc), + /* 160 */ SyscallDesc("sched_set_affinity", unimplementedFunc), + /* 161 */ SyscallDesc("sched_get_affinity", unimplementedFunc), + /* 162 */ SyscallDesc("getdomainname", unimplementedFunc), + /* 163 */ SyscallDesc("setdomainname", unimplementedFunc), + /* 164 */ SyscallDesc("utrap_install", unimplementedFunc), + /* 165 */ SyscallDesc("quotactl", unimplementedFunc), + /* 166 */ SyscallDesc("set_tid_address", unimplementedFunc), + /* 167 */ SyscallDesc("mount", unimplementedFunc), + /* 168 */ SyscallDesc("ustat", unimplementedFunc), + /* 169 */ SyscallDesc("setxattr", unimplementedFunc), + /* 170 */ SyscallDesc("lsetxattr", unimplementedFunc), + /* 171 */ SyscallDesc("fsetxattr", unimplementedFunc), + /* 172 */ SyscallDesc("getxattr", unimplementedFunc), + /* 173 */ SyscallDesc("lgetxattr", unimplementedFunc), + /* 174 */ SyscallDesc("getdents", unimplementedFunc), + /* 175 */ SyscallDesc("setsid", unimplementedFunc), + /* 176 */ SyscallDesc("fchdir", unimplementedFunc), + /* 177 */ SyscallDesc("fgetxattr", unimplementedFunc), + /* 178 */ SyscallDesc("listxattr", unimplementedFunc), + /* 179 */ SyscallDesc("llistxattr", unimplementedFunc), + /* 180 */ SyscallDesc("flistxattr", unimplementedFunc), + /* 181 */ SyscallDesc("removexattr", unimplementedFunc), + /* 182 */ SyscallDesc("lremovexattr", unimplementedFunc), + /* 183 */ SyscallDesc("sigpending", unimplementedFunc), + /* 184 */ SyscallDesc("query_module", unimplementedFunc), + /* 185 */ SyscallDesc("setpgid", unimplementedFunc), + /* 186 */ SyscallDesc("fremovexattr", unimplementedFunc), + /* 187 */ SyscallDesc("tkill", unimplementedFunc), + /* 188 */ SyscallDesc("exit_group", exitFunc), + /* 189 */ SyscallDesc("uname", unameFunc), + /* 190 */ SyscallDesc("init_module", unimplementedFunc), + /* 191 */ SyscallDesc("personality", unimplementedFunc), + /* 192 */ SyscallDesc("remap_file_pages", unimplementedFunc), + /* 193 */ SyscallDesc("epoll_create", unimplementedFunc), + /* 194 */ SyscallDesc("epoll_ctl", unimplementedFunc), + /* 195 */ SyscallDesc("epoll_wait", unimplementedFunc), + /* 196 */ SyscallDesc("ioprio_set", unimplementedFunc), + /* 197 */ SyscallDesc("getppid", getppidFunc), + /* 198 */ SyscallDesc("sigaction", unimplementedFunc), + /* 199 */ SyscallDesc("sgetmask", unimplementedFunc), + /* 200 */ SyscallDesc("ssetmask", unimplementedFunc), + /* 201 */ SyscallDesc("sigsuspend", unimplementedFunc), + /* 202 */ SyscallDesc("oldlstat", unimplementedFunc), + /* 203 */ SyscallDesc("uselib", unimplementedFunc), + /* 204 */ SyscallDesc("readdir", unimplementedFunc), + /* 205 */ SyscallDesc("readahead", unimplementedFunc), + /* 206 */ SyscallDesc("socketcall", unimplementedFunc), + /* 207 */ SyscallDesc("syslog", unimplementedFunc), + /* 208 */ SyscallDesc("lookup_dcookie", unimplementedFunc), + /* 209 */ SyscallDesc("fadvise64", unimplementedFunc), + /* 210 */ SyscallDesc("fadvise64_64", unimplementedFunc), + /* 211 */ SyscallDesc("tgkill", unimplementedFunc), + /* 212 */ SyscallDesc("waitpid", unimplementedFunc), + /* 213 */ SyscallDesc("swapoff", unimplementedFunc), + /* 214 */ SyscallDesc("sysinfo", unimplementedFunc), + /* 215 */ SyscallDesc("ipc", unimplementedFunc), + /* 216 */ SyscallDesc("sigreturn", unimplementedFunc), + /* 217 */ SyscallDesc("clone", unimplementedFunc), + /* 218 */ SyscallDesc("ioprio_get", unimplementedFunc), + /* 219 */ SyscallDesc("adjtimex", unimplementedFunc), + /* 220 */ SyscallDesc("sigprocmask", unimplementedFunc), + /* 221 */ SyscallDesc("create_module", unimplementedFunc), + /* 222 */ SyscallDesc("delete_module", unimplementedFunc), + /* 223 */ SyscallDesc("get_kernel_syms", unimplementedFunc), + /* 224 */ SyscallDesc("getpgid", unimplementedFunc), + /* 225 */ SyscallDesc("bdflush", unimplementedFunc), + /* 226 */ SyscallDesc("sysfs", unimplementedFunc), + /* 227 */ SyscallDesc("afs_syscall", unimplementedFunc), + /* 228 */ SyscallDesc("setfsuid", unimplementedFunc), + /* 229 */ SyscallDesc("setfsgid", unimplementedFunc), + /* 230 */ SyscallDesc("_newselect", unimplementedFunc), + /* 231 */ SyscallDesc("time", unimplementedFunc), + /* 232 */ SyscallDesc("oldstat", unimplementedFunc), + /* 233 */ SyscallDesc("stime", unimplementedFunc), + /* 234 */ SyscallDesc("statfs64", unimplementedFunc), + /* 235 */ SyscallDesc("fstatfs64", unimplementedFunc), + /* 236 */ SyscallDesc("_llseek", unimplementedFunc), + /* 237 */ SyscallDesc("mlock", unimplementedFunc), + /* 238 */ SyscallDesc("munlock", unimplementedFunc), + /* 239 */ SyscallDesc("mlockall", unimplementedFunc), + /* 240 */ SyscallDesc("munlockall", unimplementedFunc), + /* 241 */ SyscallDesc("sched_setparam", unimplementedFunc), + /* 242 */ SyscallDesc("sched_getparam", unimplementedFunc), + /* 243 */ SyscallDesc("sched_setscheduler", unimplementedFunc), + /* 244 */ SyscallDesc("sched_getscheduler", unimplementedFunc), + /* 245 */ SyscallDesc("sched_yield", unimplementedFunc), + /* 246 */ SyscallDesc("sched_get_priority_max", unimplementedFunc), + /* 247 */ SyscallDesc("sched_get_priority_min", unimplementedFunc), + /* 248 */ SyscallDesc("sched_rr_get_interval", unimplementedFunc), + /* 249 */ SyscallDesc("nanosleep", unimplementedFunc), + /* 250 */ SyscallDesc("mremap", unimplementedFunc), + /* 251 */ SyscallDesc("_sysctl", unimplementedFunc), + /* 252 */ SyscallDesc("getsid", unimplementedFunc), + /* 253 */ SyscallDesc("fdatasync", unimplementedFunc), + /* 254 */ SyscallDesc("nfsservctl", unimplementedFunc), + /* 255 */ SyscallDesc("aplib", unimplementedFunc), + /* 256 */ SyscallDesc("clock_settime", unimplementedFunc), + /* 257 */ SyscallDesc("clock_gettime", unimplementedFunc), + /* 258 */ SyscallDesc("clock_getres", unimplementedFunc), + /* 259 */ SyscallDesc("clock_nanosleep", unimplementedFunc), + /* 260 */ SyscallDesc("sched_getaffinity", unimplementedFunc), + /* 261 */ SyscallDesc("sched_setaffinity", unimplementedFunc), + /* 262 */ SyscallDesc("timer_settime", unimplementedFunc), + /* 263 */ SyscallDesc("timer_gettime", unimplementedFunc), + /* 264 */ SyscallDesc("timer_getoverrun", unimplementedFunc), + /* 265 */ SyscallDesc("timer_delete", unimplementedFunc), + /* 266 */ SyscallDesc("timer_create", unimplementedFunc), + /* 267 */ SyscallDesc("vserver", unimplementedFunc), + /* 268 */ SyscallDesc("io_setup", unimplementedFunc), + /* 269 */ SyscallDesc("io_destroy", unimplementedFunc), + /* 270 */ SyscallDesc("io_submit", unimplementedFunc), + /* 271 */ SyscallDesc("io_cancel", unimplementedFunc), + /* 272 */ SyscallDesc("io_getevents", unimplementedFunc), + /* 273 */ SyscallDesc("mq_open", unimplementedFunc), + /* 274 */ SyscallDesc("mq_unlink", unimplementedFunc), + /* 275 */ SyscallDesc("mq_timedsend", unimplementedFunc), + /* 276 */ SyscallDesc("mq_timedreceive", unimplementedFunc), + /* 277 */ SyscallDesc("mq_notify", unimplementedFunc), + /* 278 */ SyscallDesc("mq_getsetattr", unimplementedFunc), + /* 279 */ SyscallDesc("waitid", unimplementedFunc), + /* 280 */ SyscallDesc("sys_setaltroot", unimplementedFunc), + /* 281 */ SyscallDesc("add_key", unimplementedFunc), + /* 282 */ SyscallDesc("request_key", unimplementedFunc), + /* 283 */ SyscallDesc("keyctl", unimplementedFunc) +}; + +SparcLinuxProcess::SparcLinuxProcess(const std::string &name, + ObjectFile *objFile, + System * system, + int stdin_fd, + int stdout_fd, + int stderr_fd, + std::vector<std::string> &argv, + std::vector<std::string> &envp) + : SparcLiveProcess(name, objFile, system, + stdin_fd, stdout_fd, stderr_fd, argv, envp), + Num_Syscall_Descs(sizeof(syscallDescs) / sizeof(SyscallDesc)) +{ + // The sparc syscall table must be <= 284 entries because that is all there + // is space for. + assert(Num_Syscall_Descs <= 284); +} + + + +SyscallDesc* +SparcLinuxProcess::getDesc(int callnum) +{ + if (callnum < 0 || callnum > Num_Syscall_Descs) + return NULL; + return &syscallDescs[callnum]; +} diff --git a/src/arch/sparc/linux/process.hh b/src/arch/sparc/linux/process.hh new file mode 100644 index 000000000..23ce66d02 --- /dev/null +++ b/src/arch/sparc/linux/process.hh @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2003-2004 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __SPARC_LINUX_PROCESS_HH__ +#define __SPARC_LINUX_PROCESS_HH__ + +#include "arch/sparc/linux/linux.hh" +#include "arch/sparc/process.hh" +#include "sim/process.hh" + +namespace SparcISA { + +/// A process with emulated SPARC/Linux syscalls. +class SparcLinuxProcess : public SparcLiveProcess +{ + public: + /// Constructor. + SparcLinuxProcess(const std::string &name, + ObjectFile *objFile, + System * system, + int stdin_fd, int stdout_fd, int stderr_fd, + std::vector<std::string> &argv, + std::vector<std::string> &envp); + + virtual SyscallDesc* getDesc(int callnum); + + /// The target system's hostname. + static const char *hostname; + + /// Array of syscall descriptors, indexed by call number. + static SyscallDesc syscallDescs[]; + + const int Num_Syscall_Descs; +}; + +SyscallReturn getresuidFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + +} // namespace SparcISA +#endif // __ALPHA_LINUX_PROCESS_HH__ diff --git a/src/arch/sparc/process.cc b/src/arch/sparc/process.cc new file mode 100644 index 000000000..fe6692cc3 --- /dev/null +++ b/src/arch/sparc/process.cc @@ -0,0 +1,379 @@ +/* + * Copyright (c) 2003-2004 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "arch/sparc/isa_traits.hh" +#include "arch/sparc/process.hh" +#include "arch/sparc/linux/process.hh" +#include "arch/sparc/solaris/process.hh" +#include "base/loader/object_file.hh" +#include "base/misc.hh" +#include "cpu/exec_context.hh" +#include "mem/page_table.hh" +#include "mem/translating_port.hh" +#include "sim/builder.hh" +#include "sim/system.hh" + +using namespace std; +using namespace SparcISA; + +SparcLiveProcess * +SparcLiveProcess::create(const std::string &nm, System *system, int stdin_fd, + int stdout_fd, int stderr_fd, std::string executable, + std::vector<std::string> &argv, std::vector<std::string> &envp) +{ + SparcLiveProcess *process = NULL; + + ObjectFile *objFile = createObjectFile(executable); + if (objFile == NULL) { + fatal("Can't load object file %s", executable); + } + + + if (objFile->getArch() != ObjectFile::SPARC) + fatal("Object file with arch %x does not match architecture %x.", + objFile->getArch(), ObjectFile::SPARC); + switch (objFile->getOpSys()) { + case ObjectFile::Linux: + process = new SparcLinuxProcess(nm, objFile, system, + stdin_fd, stdout_fd, stderr_fd, + argv, envp); + break; + + + case ObjectFile::Solaris: + process = new SparcSolarisProcess(nm, objFile, system, + stdin_fd, stdout_fd, stderr_fd, + argv, envp); + break; + default: + fatal("Unknown/unsupported operating system."); + } + + if (process == NULL) + fatal("Unknown error creating process object."); + return process; +} + +SparcLiveProcess::SparcLiveProcess(const std::string &nm, ObjectFile *objFile, + System *_system, int stdin_fd, int stdout_fd, int stderr_fd, + std::vector<std::string> &argv, std::vector<std::string> &envp) + : LiveProcess(nm, objFile, _system, stdin_fd, stdout_fd, stderr_fd, + argv, envp) +{ + + // XXX all the below need to be updated for SPARC - Ali + brk_point = objFile->dataBase() + objFile->dataSize() + objFile->bssSize(); + brk_point = roundUp(brk_point, VMPageSize); + + // Set up stack. On SPARC Linux, stack goes from the top of memory + // downward, less the hole for the kernel address space. + stack_base = ((Addr)0x80000000000ULL); + + // Set up region for mmaps. Tru64 seems to start just above 0 and + // grow up from there. + mmap_start = mmap_end = 0x800000; + + // Set pointer for next thread stack. Reserve 8M for main stack. + next_thread_stack_base = stack_base - (8 * 1024 * 1024); +} + +void +SparcLiveProcess::startup() +{ + argsInit(MachineBytes, VMPageSize); + + //From the SPARC ABI + + //The process runs in user mode + execContexts[0]->setMiscRegWithEffect(MISCREG_PSTATE, 0x02); + + //Setup default FP state + execContexts[0]->setMiscReg(MISCREG_FSR, 0); + + execContexts[0]->setMiscReg(MISCREG_TICK, 0); + // + /* + * Register window management registers + */ + + //No windows contain info from other programs + execContexts[0]->setMiscRegWithEffect(MISCREG_OTHERWIN, 0); + //There are no windows to pop + execContexts[0]->setMiscRegWithEffect(MISCREG_CANRESTORE, 0); + //All windows are available to save into + execContexts[0]->setMiscRegWithEffect(MISCREG_CANSAVE, NWindows - 2); + //All windows are "clean" + execContexts[0]->setMiscRegWithEffect(MISCREG_CLEANWIN, NWindows); + //Start with register window 0 + execContexts[0]->setMiscRegWithEffect(MISCREG_CWP, 0); +} + +m5_auxv_t buildAuxVect(int64_t type, int64_t val) +{ + m5_auxv_t result; + result.a_type = TheISA::htog(type); + result.a_val = TheISA::htog(val); + return result; +} + +void +SparcLiveProcess::argsInit(int intSize, int pageSize) +{ + Process::startup(); + + Addr alignmentMask = ~(intSize - 1); + + // load object file into target memory + objFile->loadSections(initVirtMem); + + //These are the auxilliary vector types + enum auxTypes + { + SPARC_AT_HWCAP = 16, + SPARC_AT_PAGESZ = 6, + SPARC_AT_CLKTCK = 17, + SPARC_AT_PHDR = 3, + SPARC_AT_PHENT = 4, + SPARC_AT_PHNUM = 5, + SPARC_AT_BASE = 7, + SPARC_AT_FLAGS = 8, + SPARC_AT_ENTRY = 9, + SPARC_AT_UID = 11, + SPARC_AT_EUID = 12, + SPARC_AT_GID = 13, + SPARC_AT_EGID = 14 + }; + + enum hardwareCaps + { + M5_HWCAP_SPARC_FLUSH = 1, + M5_HWCAP_SPARC_STBAR = 2, + M5_HWCAP_SPARC_SWAP = 4, + M5_HWCAP_SPARC_MULDIV = 8, + M5_HWCAP_SPARC_V9 = 16, + //This one should technically only be set + //if there is a cheetah or cheetah_plus tlb, + //but we'll use it all the time + M5_HWCAP_SPARC_ULTRA3 = 32 + }; + + const int64_t hwcap = + M5_HWCAP_SPARC_FLUSH | + M5_HWCAP_SPARC_STBAR | + M5_HWCAP_SPARC_SWAP | + M5_HWCAP_SPARC_MULDIV | + M5_HWCAP_SPARC_V9 | + M5_HWCAP_SPARC_ULTRA3; + + //Setup the auxilliary vectors. These will already have + //endian conversion. + auxv.push_back(buildAuxVect(SPARC_AT_EGID, 100)); + auxv.push_back(buildAuxVect(SPARC_AT_GID, 100)); + auxv.push_back(buildAuxVect(SPARC_AT_EUID, 100)); + auxv.push_back(buildAuxVect(SPARC_AT_UID, 100)); + //This would work, but the entry point is a protected member + //auxv.push_back(buildAuxVect(SPARC_AT_ENTRY, objFile->entry)); + auxv.push_back(buildAuxVect(SPARC_AT_FLAGS, 0)); + //This is the address of the elf "interpreter", which I don't + //think we currently set up. It should be set to 0 (I think) + //auxv.push_back(buildAuxVect(SPARC_AT_BASE, 0)); + //This is the number of headers which were in the original elf + //file. This information isn't avaibale by this point. + //auxv.push_back(buildAuxVect(SPARC_AT_PHNUM, 3)); + //This is the size of a program header entry. This isn't easy + //to compute here. + //auxv.push_back(buildAuxVect(SPARC_AT_PHENT, blah)); + //This is should be set to load_addr (whatever that is) + + //e_phoff. I think it's a pointer to the program headers. + //auxv.push_back(buildAuxVect(SPARC_AT_PHDR, blah)); + //This should be easy to get right, but I won't set it for now + //auxv.push_back(buildAuxVect(SPARC_AT_CLKTCK, blah)); + auxv.push_back(buildAuxVect(SPARC_AT_PAGESZ, SparcISA::VMPageSize)); + auxv.push_back(buildAuxVect(SPARC_AT_HWCAP, hwcap)); + + //Figure out how big the initial stack needs to be + + //Each auxilliary vector is two 8 byte words + int aux_data_size = 2 * intSize * auxv.size(); + int env_data_size = 0; + for (int i = 0; i < envp.size(); ++i) { + env_data_size += envp[i].size() + 1; + } + int arg_data_size = 0; + for (int i = 0; i < argv.size(); ++i) { + arg_data_size += argv[i].size() + 1; + } + + int aux_array_size = intSize * 2 * (auxv.size() + 1); + + int argv_array_size = intSize * (argv.size() + 1); + int envp_array_size = intSize * (envp.size() + 1); + + int argc_size = intSize; + int window_save_size = intSize * 16; + + int info_block_size = + (aux_data_size + + env_data_size + + arg_data_size + + ~alignmentMask) & alignmentMask; + + int info_block_padding = + info_block_size - + aux_data_size - + env_data_size - + arg_data_size; + + int space_needed = + info_block_size + + aux_array_size + + envp_array_size + + argv_array_size + + argc_size + + window_save_size; + + stack_min = stack_base - space_needed; + stack_min &= alignmentMask; + stack_size = stack_base - stack_min; + + // map memory + pTable->allocate(roundDown(stack_min, pageSize), + roundUp(stack_size, pageSize)); + + // map out initial stack contents + Addr aux_data_base = stack_base - aux_data_size - info_block_padding; + Addr env_data_base = aux_data_base - env_data_size; + Addr arg_data_base = env_data_base - arg_data_size; + Addr auxv_array_base = arg_data_base - aux_array_size; + Addr envp_array_base = auxv_array_base - envp_array_size; + Addr argv_array_base = envp_array_base - argv_array_size; + Addr argc_base = argv_array_base - argc_size; + Addr window_save_base = argc_base - window_save_size; + + DPRINTF(Sparc, "The addresses of items on the initial stack:\n"); + DPRINTF(Sparc, "0x%x - aux data\n", aux_data_base); + DPRINTF(Sparc, "0x%x - env data\n", env_data_base); + DPRINTF(Sparc, "0x%x - arg data\n", arg_data_base); + DPRINTF(Sparc, "0x%x - auxv array\n", auxv_array_base); + DPRINTF(Sparc, "0x%x - envp array\n", envp_array_base); + DPRINTF(Sparc, "0x%x - argv array\n", argv_array_base); + DPRINTF(Sparc, "0x%x - argc \n", argc_base); + DPRINTF(Sparc, "0x%x - window save\n", window_save_base); + DPRINTF(Sparc, "0x%x - stack min\n", stack_min); + + // write contents to stack + uint64_t argc = argv.size(); + uint64_t guestArgc = TheISA::htog(argc); + + //Copy the aux stuff + for(int x = 0; x < auxv.size(); x++) + { + initVirtMem->writeBlob(auxv_array_base + x * 2 * intSize, + (uint8_t*)&(auxv[x].a_type), intSize); + initVirtMem->writeBlob(auxv_array_base + (x * 2 + 1) * intSize, + (uint8_t*)&(auxv[x].a_val), intSize); + } + //Write out the terminating zeroed auxilliary vector + const uint64_t zero = 0; + initVirtMem->writeBlob(auxv_array_base + 2 * intSize * auxv.size(), + (uint8_t*)&zero, 2 * intSize); + + copyStringArray(envp, envp_array_base, env_data_base, initVirtMem); + copyStringArray(argv, argv_array_base, arg_data_base, initVirtMem); + + initVirtMem->writeBlob(argc_base, (uint8_t*)&guestArgc, intSize); + + execContexts[0]->setIntReg(ArgumentReg0, argc); + execContexts[0]->setIntReg(ArgumentReg1, argv_array_base); + execContexts[0]->setIntReg(StackPointerReg, stack_min - StackBias); + + Addr prog_entry = objFile->entryPoint(); + execContexts[0]->setPC(prog_entry); + execContexts[0]->setNextPC(prog_entry + sizeof(MachInst)); + execContexts[0]->setNextNPC(prog_entry + (2 * sizeof(MachInst))); + +// num_processes++; +} + + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(SparcLiveProcess) + + VectorParam<string> cmd; + Param<string> executable; + Param<string> input; + Param<string> output; + VectorParam<string> env; + SimObjectParam<System *> system; + +END_DECLARE_SIM_OBJECT_PARAMS(SparcLiveProcess) + + +BEGIN_INIT_SIM_OBJECT_PARAMS(SparcLiveProcess) + + INIT_PARAM(cmd, "command line (executable plus arguments)"), + INIT_PARAM(executable, "executable (overrides cmd[0] if set)"), + INIT_PARAM(input, "filename for stdin (dflt: use sim stdin)"), + INIT_PARAM(output, "filename for stdout/stderr (dflt: use sim stdout)"), + INIT_PARAM(env, "environment settings"), + INIT_PARAM(system, "system") + +END_INIT_SIM_OBJECT_PARAMS(SparcLiveProcess) + + +CREATE_SIM_OBJECT(SparcLiveProcess) +{ + string in = input; + string out = output; + + // initialize file descriptors to default: same as simulator + int stdin_fd, stdout_fd, stderr_fd; + + if (in == "stdin" || in == "cin") + stdin_fd = STDIN_FILENO; + else + stdin_fd = Process::openInputFile(input); + + if (out == "stdout" || out == "cout") + stdout_fd = STDOUT_FILENO; + else if (out == "stderr" || out == "cerr") + stdout_fd = STDERR_FILENO; + else + stdout_fd = Process::openOutputFile(out); + + stderr_fd = (stdout_fd != STDOUT_FILENO) ? stdout_fd : STDERR_FILENO; + + return SparcLiveProcess::create(getInstanceName(), system, + stdin_fd, stdout_fd, stderr_fd, + (string)executable == "" ? cmd[0] : executable, + cmd, env); +} + + +REGISTER_SIM_OBJECT("SparcLiveProcess", SparcLiveProcess) + + diff --git a/src/arch/sparc/process.hh b/src/arch/sparc/process.hh new file mode 100644 index 000000000..c177f20a5 --- /dev/null +++ b/src/arch/sparc/process.hh @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2003-2004 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __SPARC_PROCESS_HH__ +#define __SPARC_PROCESS_HH__ + +#include <string> +#include <vector> +#include "sim/process.hh" + +class ObjectFile; +class System; + +typedef struct +{ + int64_t a_type; + union { + int64_t a_val; + Addr a_ptr; + Addr a_fcn; + }; +} m5_auxv_t; + +class SparcLiveProcess : public LiveProcess +{ + protected: + + static const Addr StackBias = 2047; + + std::vector<m5_auxv_t> auxv; + + SparcLiveProcess(const std::string &nm, ObjectFile *objFile, + System *_system, int stdin_fd, int stdout_fd, int stderr_fd, + std::vector<std::string> &argv, + std::vector<std::string> &envp); + + void startup(); + + public: + // this function is used to create the LiveProcess object, since + // we can't tell which subclass of LiveProcess to use until we + // open and look at the object file. + static SparcLiveProcess *create(const std::string &nm, + System *_system, + int stdin_fd, int stdout_fd, int stderr_fd, + std::string executable, + std::vector<std::string> &argv, + std::vector<std::string> &envp); + + void argsInit(int intSize, int pageSize); + +}; + +#endif // __SPARC_PROCESS_HH__ diff --git a/src/arch/sparc/regfile.hh b/src/arch/sparc/regfile.hh new file mode 100644 index 000000000..5322ffb37 --- /dev/null +++ b/src/arch/sparc/regfile.hh @@ -0,0 +1,861 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ARCH_SPARC_REGFILE_HH__ +#define __ARCH_SPARC_REGFILE_HH__ + +#include "arch/sparc/exceptions.hh" +#include "arch/sparc/faults.hh" +#include "base/trace.hh" +#include "sim/byteswap.hh" +#include "cpu/cpuevent.hh" +#include "sim/host.hh" + +class Checkpoint; + +namespace SparcISA +{ + + typedef uint8_t RegIndex; + + // MAXTL - maximum trap level + const int MaxPTL = 2; + const int MaxTL = 6; + const int MaxGL = 3; + const int MaxPGL = 2; + + // NWINDOWS - number of register windows, can be 3 to 32 + const int NWindows = 32; + + + const int AsrStart = 0; + const int PrStart = 32; + const int HprStart = 64; + const int MiscStart = 96; + + + const uint64_t Bit64 = 0x8000000000000000; + + class IntRegFile + { + protected: + static const int FrameOffsetBits = 3; + static const int FrameNumBits = 2; + + static const int RegsPerFrame = 1 << FrameOffsetBits; + static const int FrameNumMask = + (FrameNumBits == sizeof(int)) ? + (unsigned int)(-1) : + (1 << FrameNumBits) - 1; + static const int FrameOffsetMask = + (FrameOffsetBits == sizeof(int)) ? + (unsigned int)(-1) : + (1 << FrameOffsetBits) - 1; + + IntReg regGlobals[MaxGL][RegsPerFrame]; + IntReg regSegments[2 * NWindows][RegsPerFrame]; + + enum regFrame {Globals, Outputs, Locals, Inputs, NumFrames}; + + IntReg * regView[NumFrames]; + + static const int RegGlobalOffset = 0; + static const int FrameOffset = MaxGL * RegsPerFrame; + int offset[NumFrames]; + + public: + + int flattenIndex(int reg) + { + int flatIndex = offset[reg >> FrameOffsetBits] + | (reg & FrameOffsetMask); + DPRINTF(Sparc, "Flattened index %d into %d.\n", reg, flatIndex); + return flatIndex; + } + + void clear() + { + int x; + for (x = 0; x < MaxGL; x++) + memset(regGlobals[x], 0, sizeof(regGlobals[x])); + for(int x = 0; x < 2 * NWindows; x++) + bzero(regSegments[x], sizeof(regSegments[x])); + } + + IntRegFile() + { + offset[Globals] = 0; + regView[Globals] = regGlobals[0]; + setCWP(0); + clear(); + } + + IntReg readReg(int intReg) + { + IntReg val = + regView[intReg >> FrameOffsetBits][intReg & FrameOffsetMask]; + DPRINTF(Sparc, "Read register %d = 0x%x\n", intReg, val); + return val; + } + + Fault setReg(int intReg, const IntReg &val) + { + if(intReg) + DPRINTF(Sparc, "Wrote register %d = 0x%x\n", intReg, val); + regView[intReg >> FrameOffsetBits][intReg & FrameOffsetMask] = val; + return NoFault; + } + + //This doesn't effect the actual CWP register. + //It's purpose is to adjust the view of the register file + //to what it would be if CWP = cwp. + void setCWP(int cwp) + { + int index = ((NWindows - cwp) % NWindows) * 2; + offset[Outputs] = FrameOffset + (index * RegsPerFrame); + offset[Locals] = FrameOffset + ((index+1) * RegsPerFrame); + offset[Inputs] = FrameOffset + + (((index+2) % (NWindows * 2)) * RegsPerFrame); + regView[Outputs] = regSegments[index]; + regView[Locals] = regSegments[index+1]; + regView[Inputs] = regSegments[(index+2) % (NWindows * 2)]; + + DPRINTF(Sparc, "Changed the CWP value to %d\n", cwp); + } + + void setGlobals(int gl) + { + + DPRINTF(Sparc, "Now using %d globals", gl); + + regView[Globals] = regGlobals[gl]; + offset[Globals] = RegGlobalOffset + gl * RegsPerFrame; + } + + void serialize(std::ostream &os); + + void unserialize(Checkpoint *cp, const std::string §ion); + }; + + typedef float float32_t; + typedef double float64_t; + //FIXME long double refers to a 10 byte float, rather than a + //16 byte float as required. This data type may have to be emulated. + typedef double float128_t; + + class FloatRegFile + { + public: + static const int SingleWidth = 32; + static const int DoubleWidth = 64; + static const int QuadWidth = 128; + + protected: + + //Since the floating point registers overlap each other, + //A generic storage space is used. The float to be returned is + //pulled from the appropriate section of this region. + char regSpace[SingleWidth / 8 * NumFloatRegs]; + + public: + + void clear() + { + bzero(regSpace, sizeof(regSpace)); + } + + FloatReg readReg(int floatReg, int width) + { + //In each of these cases, we have to copy the value into a temporary + //variable. This is because we may otherwise try to access an + //unaligned portion of memory. + switch(width) + { + case SingleWidth: + float32_t result32; + memcpy(&result32, regSpace + 4 * floatReg, width); + return htog(result32); + case DoubleWidth: + float64_t result64; + memcpy(&result64, regSpace + 4 * floatReg, width); + return htog(result64); + case QuadWidth: + float128_t result128; + memcpy(&result128, regSpace + 4 * floatReg, width); + return htog(result128); + default: + panic("Attempted to read a %d bit floating point register!", width); + } + } + + FloatRegBits readRegBits(int floatReg, int width) + { + //In each of these cases, we have to copy the value into a temporary + //variable. This is because we may otherwise try to access an + //unaligned portion of memory. + switch(width) + { + case SingleWidth: + uint32_t result32; + memcpy(&result32, regSpace + 4 * floatReg, width); + return htog(result32); + case DoubleWidth: + uint64_t result64; + memcpy(&result64, regSpace + 4 * floatReg, width); + return htog(result64); + case QuadWidth: + uint64_t result128; + memcpy(&result128, regSpace + 4 * floatReg, width); + return htog(result128); + default: + panic("Attempted to read a %d bit floating point register!", width); + } + } + + Fault setReg(int floatReg, const FloatReg &val, int width) + { + //In each of these cases, we have to copy the value into a temporary + //variable. This is because we may otherwise try to access an + //unaligned portion of memory. + switch(width) + { + case SingleWidth: + uint32_t result32 = gtoh((uint32_t)val); + memcpy(regSpace + 4 * floatReg, &result32, width); + case DoubleWidth: + uint64_t result64 = gtoh((uint64_t)val); + memcpy(regSpace + 4 * floatReg, &result64, width); + case QuadWidth: + uint64_t result128 = gtoh((uint64_t)val); + memcpy(regSpace + 4 * floatReg, &result128, width); + default: + panic("Attempted to read a %d bit floating point register!", width); + } + return NoFault; + } + + Fault setRegBits(int floatReg, const FloatRegBits &val, int width) + { + //In each of these cases, we have to copy the value into a temporary + //variable. This is because we may otherwise try to access an + //unaligned portion of memory. + switch(width) + { + case SingleWidth: + uint32_t result32 = gtoh((uint32_t)val); + memcpy(regSpace + 4 * floatReg, &result32, width); + case DoubleWidth: + uint64_t result64 = gtoh((uint64_t)val); + memcpy(regSpace + 4 * floatReg, &result64, width); + case QuadWidth: + uint64_t result128 = gtoh((uint64_t)val); + memcpy(regSpace + 4 * floatReg, &result128, width); + default: + panic("Attempted to read a %d bit floating point register!", width); + } + return NoFault; + } + + void serialize(std::ostream &os); + + void unserialize(Checkpoint *cp, const std::string §ion); + }; + + enum MiscRegIndex + { + /** Ancillary State Registers */ + MISCREG_Y = AsrStart + 0, + MISCREG_CCR = AsrStart + 2, + MISCREG_ASI = AsrStart + 3, + MISCREG_TICK = AsrStart + 4, + MISCREG_PC = AsrStart + 5, + MISCREG_FPRS = AsrStart + 6, + MISCREG_PCR = AsrStart + 16, + MISCREG_PIC = AsrStart + 17, + MISCREG_GSR = AsrStart + 19, + MISCREG_SOFTINT_SET = AsrStart + 20, + MISCREG_SOFTINT_CLR = AsrStart + 21, + MISCREG_SOFTINT = AsrStart + 22, + MISCREG_TICK_CMPR = AsrStart + 23, + MISCREG_STICK = AsrStart + 24, + MISCREG_STICK_CMPR = AsrStart + 25, + + /** Privilged Registers */ + MISCREG_TPC = PrStart + 0, + MISCREG_TNPC = PrStart + 1, + MISCREG_TSTATE = PrStart + 2, + MISCREG_TT = PrStart + 3, + MISCREG_PRIVTICK = PrStart + 4, + MISCREG_TBA = PrStart + 5, + MISCREG_PSTATE = PrStart + 6, + MISCREG_TL = PrStart + 7, + MISCREG_PIL = PrStart + 8, + MISCREG_CWP = PrStart + 9, + MISCREG_CANSAVE = PrStart + 10, + MISCREG_CANRESTORE = PrStart + 11, + MISCREG_CLEANWIN = PrStart + 12, + MISCREG_OTHERWIN = PrStart + 13, + MISCREG_WSTATE = PrStart + 14, + MISCREG_GL = PrStart + 16, + + /** Hyper privileged registers */ + MISCREG_HPSTATE = HprStart + 0, + MISCREG_HTSTATE = HprStart + 1, + MISCREG_HINTP = HprStart + 3, + MISCREG_HTBA = HprStart + 5, + MISCREG_HVER = HprStart + 6, + MISCREG_STRAND_STS_REG = HprStart + 16, + MISCREG_HSTICK_CMPR = HprStart + 31, + + /** Floating Point Status Register */ + MISCREG_FSR = MiscStart + 0 + + }; + + // The control registers, broken out into fields + class MiscRegFile + { + private: + + /* ASR Registers */ + union { + uint64_t y; // Y (used in obsolete multiplication) + struct { + uint64_t value:32; // The actual value stored in y + uint64_t :32; // reserved bits + } yFields; + }; + union { + uint8_t ccr; // Condition Code Register + struct { + union { + uint8_t icc:4; // 32-bit condition codes + struct { + uint8_t c:1; // Carry + uint8_t v:1; // Overflow + uint8_t z:1; // Zero + uint8_t n:1; // Negative + } iccFields; + }; + union { + uint8_t xcc:4; // 64-bit condition codes + struct { + uint8_t c:1; // Carry + uint8_t v:1; // Overflow + uint8_t z:1; // Zero + uint8_t n:1; // Negative + } xccFields; + }; + } ccrFields; + }; + uint8_t asi; // Address Space Identifier + union { + uint64_t tick; // Hardware clock-tick counter + struct { + int64_t counter:63; // Clock-tick count + uint64_t npt:1; // Non-priveleged trap + } tickFields; + }; + union { + uint8_t fprs; // Floating-Point Register State + struct { + uint8_t dl:1; // Dirty lower + uint8_t du:1; // Dirty upper + uint8_t fef:1; // FPRS enable floating-Point + } fprsFields; + }; + union { + uint64_t softint; + struct { + uint64_t tm:1; + uint64_t int_level:14; + uint64_t sm:1; + } softintFields; + }; + union { + uint64_t tick_cmpr; // Hardware tick compare registers + struct { + uint64_t tick_cmpr:63; // Clock-tick count + uint64_t int_dis:1; // Non-priveleged trap + } tick_cmprFields; + }; + union { + uint64_t stick; // Hardware clock-tick counter + struct { + int64_t :63; // Not used, storage in SparcSystem + uint64_t npt:1; // Non-priveleged trap + } stickFields; + }; + union { + uint64_t stick_cmpr; // Hardware tick compare registers + struct { + uint64_t tick_cmpr:63; // Clock-tick count + uint64_t int_dis:1; // Non-priveleged trap + } stick_cmprFields; + }; + + + /* Privileged Registers */ + uint64_t tpc[MaxTL]; // Trap Program Counter (value from + // previous trap level) + uint64_t tnpc[MaxTL]; // Trap Next Program Counter (value from + // previous trap level) + union { + uint64_t tstate[MaxTL]; // Trap State + struct { + //Values are from previous trap level + uint64_t cwp:5; // Current Window Pointer + uint64_t :3; // Reserved bits + uint64_t pstate:13; // Process State + uint64_t :3; // Reserved bits + uint64_t asi:8; // Address Space Identifier + uint64_t ccr:8; // Condition Code Register + uint64_t gl:8; // Global level + } tstateFields[MaxTL]; + }; + uint16_t tt[MaxTL]; // Trap Type (Type of trap which occured + // on the previous level) + uint64_t tba; // Trap Base Address + + union { + uint16_t pstate; // Process State Register + struct { + uint16_t :1; // reserved + uint16_t ie:1; // Interrupt enable + uint16_t priv:1; // Privelege mode + uint16_t am:1; // Address mask + uint16_t pef:1; // PSTATE enable floating-point + uint16_t :1; // reserved2 + uint16_t mm:2; // Memory Model + uint16_t tle:1; // Trap little-endian + uint16_t cle:1; // Current little-endian + } pstateFields; + }; + uint8_t tl; // Trap Level + uint8_t pil; // Process Interrupt Register + uint8_t cwp; // Current Window Pointer + uint8_t cansave; // Savable windows + uint8_t canrestore; // Restorable windows + uint8_t cleanwin; // Clean windows + uint8_t otherwin; // Other windows + union { + uint8_t wstate; // Window State + struct { + uint8_t normal:3; // Bits TT<4:2> are set to on a normal + // register window trap + uint8_t other:3; // Bits TT<4:2> are set to on an "otherwin" + // register window trap + } wstateFields; + }; + uint8_t gl; // Global level register + + + /** Hyperprivileged Registers */ + union { + uint64_t hpstate; // Hyperprivileged State Register + struct { + uint8_t tlz: 1; + uint8_t :1; + uint8_t hpriv:1; + uint8_t :2; + uint8_t red:1; + uint8_t :4; + uint8_t ibe:1; + uint8_t id:1; + } hpstateFields; + }; + + uint64_t htstate[MaxTL]; // Hyperprivileged Trap State Register + uint64_t hintp; + uint64_t htba; // Hyperprivileged Trap Base Address register + union { + uint64_t hstick_cmpr; // Hardware tick compare registers + struct { + uint64_t tick_cmpr:63; // Clock-tick count + uint64_t int_dis:1; // Non-priveleged trap + } hstick_cmprFields; + }; + + uint64_t strandStatusReg; // Per strand status register + + + /** Floating point misc registers. */ + union { + uint64_t fsr; // Floating-Point State Register + struct { + union { + uint64_t cexc:5; // Current excpetion + struct { + uint64_t nxc:1; // Inexact + uint64_t dzc:1; // Divide by zero + uint64_t ufc:1; // Underflow + uint64_t ofc:1; // Overflow + uint64_t nvc:1; // Invalid operand + } cexcFields; + }; + union { + uint64_t aexc:5; // Accrued exception + struct { + uint64_t nxc:1; // Inexact + uint64_t dzc:1; // Divide by zero + uint64_t ufc:1; // Underflow + uint64_t ofc:1; // Overflow + uint64_t nvc:1; // Invalid operand + } aexcFields; + }; + uint64_t fcc0:2; // Floating-Point condtion codes + uint64_t :1; // Reserved bits + uint64_t qne:1; // Deferred trap queue not empty + // with no queue, it should read 0 + uint64_t ftt:3; // Floating-Point trap type + uint64_t ver:3; // Version (of the FPU) + uint64_t :2; // Reserved bits + uint64_t ns:1; // Nonstandard floating point + union { + uint64_t tem:5; // Trap Enable Mask + struct { + uint64_t nxm:1; // Inexact + uint64_t dzm:1; // Divide by zero + uint64_t ufm:1; // Underflow + uint64_t ofm:1; // Overflow + uint64_t nvm:1; // Invalid operand + } temFields; + }; + uint64_t :2; // Reserved bits + uint64_t rd:2; // Rounding direction + uint64_t fcc1:2; // Floating-Point condition codes + uint64_t fcc2:2; // Floating-Point condition codes + uint64_t fcc3:2; // Floating-Point condition codes + uint64_t :26; // Reserved bits + } fsrFields; + }; + + // These need to check the int_dis field and if 0 then + // set appropriate bit in softint and checkinterrutps on the cpu +#if FULL_SYSTEM + /** Process a tick compare event and generate an interrupt on the cpu if + * appropriate. */ + void processTickCompare(ExecContext *xc); + void processSTickCompare(ExecContext *xc); + void processHSTickCompare(ExecContext *xc); + + typedef CpuEventWrapper<MiscRegFile, + &MiscRegFile::processTickCompare> TickCompareEvent; + TickCompareEvent *tickCompare; + + typedef CpuEventWrapper<MiscRegFile, + &MiscRegFile::processSTickCompare> STickCompareEvent; + STickCompareEvent *sTickCompare; + + typedef CpuEventWrapper<MiscRegFile, + &MiscRegFile::processHSTickCompare> HSTickCompareEvent; + HSTickCompareEvent *hSTickCompare; + + /** Fullsystem only register version of ReadRegWithEffect() */ + MiscReg readFSRegWithEffect(int miscReg, Fault &fault, ExecContext *xc); + /** Fullsystem only register version of SetRegWithEffect() */ + Fault setFSRegWithEffect(int miscReg, const MiscReg &val, + ExecContext * xc); +#endif + public: + + void reset() + { + pstateFields.pef = 0; //No FPU + //pstateFields.pef = 1; //FPU +#if FULL_SYSTEM + //For SPARC, when a system is first started, there is a power + //on reset Trap which sets the processor into the following state. + //Bits that aren't set aren't defined on startup. + tl = MaxTL; + gl = MaxGL; + + tickFields.counter = 0; //The TICK register is unreadable bya + tickFields.npt = 1; //The TICK register is unreadable by by !priv + + softint = 0; // Clear all the soft interrupt bits + tick_cmprFields.int_dis = 1; // disable timer compare interrupts + tick_cmprFields.tick_cmpr = 0; // Reset to 0 for pretty printing + stickFields.npt = 1; //The TICK register is unreadable by by !priv + stick_cmprFields.int_dis = 1; // disable timer compare interrupts + stick_cmprFields.tick_cmpr = 0; // Reset to 0 for pretty printing + + + tt[tl] = power_on_reset; + pstate = 0; // fields 0 but pef + pstateFields.pef = 1; + + hpstate = 0; + hpstateFields.red = 1; + hpstateFields.hpriv = 1; + hpstateFields.tlz = 0; // this is a guess + + hintp = 0; // no interrupts pending + hstick_cmprFields.int_dis = 1; // disable timer compare interrupts + hstick_cmprFields.tick_cmpr = 0; // Reset to 0 for pretty printing + +#else +/* //This sets up the initial state of the processor for usermode processes + pstateFields.priv = 0; //Process runs in user mode + pstateFields.ie = 1; //Interrupts are enabled + fsrFields.rd = 0; //Round to nearest + fsrFields.tem = 0; //Floating point traps not enabled + fsrFields.ns = 0; //Non standard mode off + fsrFields.qne = 0; //Floating point queue is empty + fsrFields.aexc = 0; //No accrued exceptions + fsrFields.cexc = 0; //No current exceptions + + //Register window management registers + otherwin = 0; //No windows contain info from other programs + canrestore = 0; //There are no windows to pop + cansave = MaxTL - 2; //All windows are available to save into + cleanwin = MaxTL;*/ +#endif + } + + MiscRegFile() + { + reset(); + } + + /** read a value out of an either an SE or FS IPR. No checking is done + * about SE vs. FS as this is mostly used to copy the regfile. Thus more + * register are copied that are necessary for FS. However this prevents + * a bunch of ifdefs and is rarely called so is not performance + * criticial. */ + MiscReg readReg(int miscReg); + + /** Read a value from an IPR. Only the SE iprs are here and the rest + * are are readFSRegWithEffect (which is called by readRegWithEffect()). + * Checking is done for permission based on state bits in the miscreg + * file. */ + MiscReg readRegWithEffect(int miscReg, Fault &fault, ExecContext *xc); + + /** write a value into an either an SE or FS IPR. No checking is done + * about SE vs. FS as this is mostly used to copy the regfile. Thus more + * register are copied that are necessary for FS. However this prevents + * a bunch of ifdefs and is rarely called so is not performance + * criticial.*/ + Fault setReg(int miscReg, const MiscReg &val); + + /** Write a value into an IPR. Only the SE iprs are here and the rest + * are are setFSRegWithEffect (which is called by setRegWithEffect()). + * Checking is done for permission based on state bits in the miscreg + * file. */ + Fault setRegWithEffect(int miscReg, + const MiscReg &val, ExecContext * xc); + + void serialize(std::ostream & os); + + void unserialize(Checkpoint * cp, const std::string & section); + + void copyMiscRegs(ExecContext * xc); + + bool isHyperPriv() { return hpstateFields.hpriv; } + bool isPriv() { return hpstateFields.hpriv || pstateFields.priv; } + bool isNonPriv() { return !isPriv(); } + }; + + typedef union + { + IntReg intreg; + FloatReg fpreg; + MiscReg ctrlreg; + } AnyReg; + + class RegFile + { + protected: + Addr pc; // Program Counter + Addr npc; // Next Program Counter + Addr nnpc; + + public: + Addr readPC() + { + return pc; + } + + void setPC(Addr val) + { + pc = val; + } + + Addr readNextPC() + { + return npc; + } + + void setNextPC(Addr val) + { + npc = val; + } + + Addr readNextNPC() + { + return nnpc; + } + + void setNextNPC(Addr val) + { + nnpc = val; + } + + protected: + IntRegFile intRegFile; // integer register file + FloatRegFile floatRegFile; // floating point register file + MiscRegFile miscRegFile; // control register file + + public: + + void clear() + { + intRegFile.clear(); + floatRegFile.clear(); + } + + int FlattenIntIndex(int reg) + { + return intRegFile.flattenIndex(reg); + } + + MiscReg readMiscReg(int miscReg) + { + return miscRegFile.readReg(miscReg); + } + + MiscReg readMiscRegWithEffect(int miscReg, + Fault &fault, ExecContext *xc) + { + return miscRegFile.readRegWithEffect(miscReg, fault, xc); + } + + Fault setMiscReg(int miscReg, const MiscReg &val) + { + return miscRegFile.setReg(miscReg, val); + } + + Fault setMiscRegWithEffect(int miscReg, const MiscReg &val, + ExecContext * xc) + { + return miscRegFile.setRegWithEffect(miscReg, val, xc); + } + + FloatReg readFloatReg(int floatReg, int width) + { + return floatRegFile.readReg(floatReg, width); + } + + FloatReg readFloatReg(int floatReg) + { + //Use the "natural" width of a single float + return floatRegFile.readReg(floatReg, FloatRegFile::SingleWidth); + } + + FloatRegBits readFloatRegBits(int floatReg, int width) + { + return floatRegFile.readRegBits(floatReg, width); + } + + FloatRegBits readFloatRegBits(int floatReg) + { + //Use the "natural" width of a single float + return floatRegFile.readRegBits(floatReg, + FloatRegFile::SingleWidth); + } + + Fault setFloatReg(int floatReg, const FloatReg &val, int width) + { + return floatRegFile.setReg(floatReg, val, width); + } + + Fault setFloatReg(int floatReg, const FloatReg &val) + { + //Use the "natural" width of a single float + return setFloatReg(floatReg, val, FloatRegFile::SingleWidth); + } + + Fault setFloatRegBits(int floatReg, const FloatRegBits &val, int width) + { + return floatRegFile.setRegBits(floatReg, val, width); + } + + Fault setFloatRegBits(int floatReg, const FloatRegBits &val) + { + //Use the "natural" width of a single float + return floatRegFile.setRegBits(floatReg, val, + FloatRegFile::SingleWidth); + } + + IntReg readIntReg(int intReg) + { + return intRegFile.readReg(intReg); + } + + Fault setIntReg(int intReg, const IntReg &val) + { + return intRegFile.setReg(intReg, val); + } + + void serialize(std::ostream &os); + void unserialize(Checkpoint *cp, const std::string §ion); + + public: + + enum ContextParam + { + CONTEXT_CWP, + CONTEXT_GLOBALS + }; + typedef int ContextVal; + + void changeContext(ContextParam param, ContextVal val) + { + switch(param) + { + case CONTEXT_CWP: + intRegFile.setCWP(val); + break; + case CONTEXT_GLOBALS: + intRegFile.setGlobals(val); + break; + default: + panic("Tried to set illegal context parameter in the SPARC regfile.\n"); + } + } + }; + + void copyRegs(ExecContext *src, ExecContext *dest); + + void copyMiscRegs(ExecContext *src, ExecContext *dest); + + int InterruptLevel(uint64_t softint); + +} // namespace SparcISA + +#endif diff --git a/src/arch/sparc/solaris/process.cc b/src/arch/sparc/solaris/process.cc new file mode 100644 index 000000000..95cdb0bd5 --- /dev/null +++ b/src/arch/sparc/solaris/process.cc @@ -0,0 +1,347 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "arch/sparc/isa_traits.hh" +#include "arch/sparc/solaris/process.hh" +#include "arch/sparc/regfile.hh" + +#include "base/trace.hh" +#include "cpu/exec_context.hh" +#include "kern/solaris/solaris.hh" + +#include "sim/process.hh" +#include "sim/syscall_emul.hh" + +using namespace std; +using namespace SparcISA; + + +/// Target uname() handler. +static SyscallReturn +unameFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + TypedBufferArg<Solaris::utsname> name(xc->getSyscallArg(0)); + + strcpy(name->sysname, "SunOS"); + strcpy(name->nodename, "m5.eecs.umich.edu"); + strcpy(name->release, "5.9"); //?? do we want this or something newer? + strcpy(name->version, "Generic_118558-21"); + strcpy(name->machine, "sun4u"); + + name.copyOut(xc->getMemPort()); + + return 0; +} + + +SyscallDesc SparcSolarisProcess::syscallDescs[] = { + /* 0 */ SyscallDesc("syscall", unimplementedFunc), + /* 1 */ SyscallDesc("exit", exitFunc), + /* 2 */ SyscallDesc("fork", unimplementedFunc), + /* 3 */ SyscallDesc("read", readFunc), + /* 4 */ SyscallDesc("write", writeFunc), + /* 5 */ SyscallDesc("open", openFunc<SparcSolaris>), + /* 6 */ SyscallDesc("close", closeFunc), + /* 7 */ SyscallDesc("wait", unimplementedFunc), + /* 8 */ SyscallDesc("creat", unimplementedFunc), + /* 9 */ SyscallDesc("link", unimplementedFunc), + /* 10 */ SyscallDesc("unlink", unlinkFunc), + /* 11 */ SyscallDesc("exec", unimplementedFunc), + /* 12 */ SyscallDesc("chdir", unimplementedFunc), + /* 13 */ SyscallDesc("time", unimplementedFunc), + /* 14 */ SyscallDesc("mknod", unimplementedFunc), + /* 15 */ SyscallDesc("chmod", chmodFunc<Solaris>), + /* 16 */ SyscallDesc("chown", chownFunc), + /* 17 */ SyscallDesc("brk", obreakFunc), + /* 18 */ SyscallDesc("stat", unimplementedFunc), + /* 19 */ SyscallDesc("lseek", lseekFunc), + /* 20 */ SyscallDesc("getpid", getpidFunc), + /* 21 */ SyscallDesc("mount", unimplementedFunc), + /* 22 */ SyscallDesc("umount", unimplementedFunc), + /* 23 */ SyscallDesc("setuid", setuidFunc), + /* 24 */ SyscallDesc("getuid", getuidFunc), + /* 25 */ SyscallDesc("stime", unimplementedFunc), + /* 26 */ SyscallDesc("pcsample", unimplementedFunc), + /* 27 */ SyscallDesc("alarm", unimplementedFunc), + /* 28 */ SyscallDesc("fstat", fstatFunc<SparcSolaris>), + /* 29 */ SyscallDesc("pause", unimplementedFunc), + /* 30 */ SyscallDesc("utime", unimplementedFunc), + /* 31 */ SyscallDesc("stty", unimplementedFunc), + /* 32 */ SyscallDesc("gtty", unimplementedFunc), + /* 33 */ SyscallDesc("access", unimplementedFunc), + /* 34 */ SyscallDesc("nice", unimplementedFunc), + /* 35 */ SyscallDesc("statfs", unimplementedFunc), + /* 36 */ SyscallDesc("sync", unimplementedFunc), + /* 37 */ SyscallDesc("kill", unimplementedFunc), + /* 38 */ SyscallDesc("fstatfs", unimplementedFunc), + /* 39 */ SyscallDesc("pgrpsys", unimplementedFunc), + /* 40 */ SyscallDesc("xenix", unimplementedFunc), + /* 41 */ SyscallDesc("dup", unimplementedFunc), + /* 42 */ SyscallDesc("pipe", pipePseudoFunc), + /* 43 */ SyscallDesc("times", unimplementedFunc), + /* 44 */ SyscallDesc("profil", unimplementedFunc), + /* 45 */ SyscallDesc("plock", unimplementedFunc), + /* 46 */ SyscallDesc("setgid", unimplementedFunc), + /* 47 */ SyscallDesc("getgid", getgidFunc), + /* 48 */ SyscallDesc("signal", unimplementedFunc), + /* 49 */ SyscallDesc("msgsys", unimplementedFunc), + /* 50 */ SyscallDesc("syssun", unimplementedFunc), + /* 51 */ SyscallDesc("acct", unimplementedFunc), + /* 52 */ SyscallDesc("shmsys", unimplementedFunc), + /* 53 */ SyscallDesc("semsys", unimplementedFunc), + /* 54 */ SyscallDesc("ioctl", unimplementedFunc), + /* 55 */ SyscallDesc("uadmin", unimplementedFunc), + /* 56 */ SyscallDesc("RESERVED", unimplementedFunc), + /* 57 */ SyscallDesc("utssys", unimplementedFunc), + /* 58 */ SyscallDesc("fdsync", unimplementedFunc), + /* 59 */ SyscallDesc("execve", unimplementedFunc), + /* 60 */ SyscallDesc("umask", unimplementedFunc), + /* 61 */ SyscallDesc("chroot", unimplementedFunc), + /* 62 */ SyscallDesc("fcntl", unimplementedFunc), + /* 63 */ SyscallDesc("ulimit", unimplementedFunc), + /* 64 */ SyscallDesc("reserved_64", unimplementedFunc), + /* 65 */ SyscallDesc("reserved_65", unimplementedFunc), + /* 66 */ SyscallDesc("reserved_66", unimplementedFunc), + /* 67 */ SyscallDesc("reserved_67", unimplementedFunc), + /* 68 */ SyscallDesc("reserved_68", unimplementedFunc), + /* 69 */ SyscallDesc("reserved_69", unimplementedFunc), + /* 70 */ SyscallDesc("tasksys", unimplementedFunc), + /* 71 */ SyscallDesc("acctctl", unimplementedFunc), + /* 72 */ SyscallDesc("reserved_72", unimplementedFunc), + /* 73 */ SyscallDesc("getpagesizes", unimplementedFunc), + /* 74 */ SyscallDesc("rctlsys", unimplementedFunc), + /* 75 */ SyscallDesc("issetugid", unimplementedFunc), + /* 76 */ SyscallDesc("fsat", unimplementedFunc), + /* 77 */ SyscallDesc("lwp_park", unimplementedFunc), + /* 78 */ SyscallDesc("sendfilev", unimplementedFunc), + /* 79 */ SyscallDesc("rmdir", unimplementedFunc), + /* 80 */ SyscallDesc("mkdir", unimplementedFunc), + /* 81 */ SyscallDesc("getdents", unimplementedFunc), + /* 82 */ SyscallDesc("reserved_82", unimplementedFunc), + /* 83 */ SyscallDesc("reserved_83", unimplementedFunc), + /* 84 */ SyscallDesc("sysfs", unimplementedFunc), + /* 85 */ SyscallDesc("getmsg", unimplementedFunc), + /* 86 */ SyscallDesc("putmsg", unimplementedFunc), + /* 87 */ SyscallDesc("poll", unimplementedFunc), + /* 88 */ SyscallDesc("lstat", unimplementedFunc), + /* 89 */ SyscallDesc("symlink", unimplementedFunc), + /* 90 */ SyscallDesc("readlink", unimplementedFunc), + /* 91 */ SyscallDesc("setgroups", unimplementedFunc), + /* 92 */ SyscallDesc("getgroups", unimplementedFunc), + /* 93 */ SyscallDesc("fchmod", unimplementedFunc), + /* 94 */ SyscallDesc("fchown", unimplementedFunc), + /* 95 */ SyscallDesc("sigprocmask", unimplementedFunc), + /* 96 */ SyscallDesc("sigsuspend", unimplementedFunc), + /* 97 */ SyscallDesc("sigaltstack", unimplementedFunc), + /* 98 */ SyscallDesc("sigaction", unimplementedFunc), + /* 99 */ SyscallDesc("sigpending", unimplementedFunc), + /* 100 */ SyscallDesc("context", unimplementedFunc), + /* 101 */ SyscallDesc("evsys", unimplementedFunc), + /* 102 */ SyscallDesc("evtrapret", unimplementedFunc), + /* 103 */ SyscallDesc("statvfs", unimplementedFunc), + /* 104 */ SyscallDesc("fstatvfs", unimplementedFunc), + /* 105 */ SyscallDesc("getloadavg", unimplementedFunc), + /* 106 */ SyscallDesc("nfssys", unimplementedFunc), + /* 107 */ SyscallDesc("waitsys", unimplementedFunc), + /* 108 */ SyscallDesc("sigsendsys", unimplementedFunc), + /* 109 */ SyscallDesc("hrtsys", unimplementedFunc), + /* 110 */ SyscallDesc("acancel", unimplementedFunc), + /* 111 */ SyscallDesc("async", unimplementedFunc), + /* 112 */ SyscallDesc("priocntlsys", unimplementedFunc), + /* 113 */ SyscallDesc("pathconf", unimplementedFunc), + /* 114 */ SyscallDesc("mincore", unimplementedFunc), + /* 115 */ SyscallDesc("mmap", mmapFunc<SparcSolaris>), + /* 116 */ SyscallDesc("mprotect", unimplementedFunc), + /* 117 */ SyscallDesc("munmap", munmapFunc), + /* 118 */ SyscallDesc("fpathconf", unimplementedFunc), + /* 119 */ SyscallDesc("vfork", unimplementedFunc), + /* 120 */ SyscallDesc("fchdir", unimplementedFunc), + /* 121 */ SyscallDesc("readv", unimplementedFunc), + /* 122 */ SyscallDesc("writev", unimplementedFunc), + /* 123 */ SyscallDesc("xstat", unimplementedFunc), + /* 124 */ SyscallDesc("lxstat", unimplementedFunc), + /* 125 */ SyscallDesc("fxstat", unimplementedFunc), + /* 126 */ SyscallDesc("xmknod", unimplementedFunc), + /* 127 */ SyscallDesc("clocal", unimplementedFunc), + /* 128 */ SyscallDesc("setrlimit", unimplementedFunc), + /* 129 */ SyscallDesc("getrlimit", unimplementedFunc), + /* 130 */ SyscallDesc("lchown", unimplementedFunc), + /* 131 */ SyscallDesc("memcntl", unimplementedFunc), + /* 132 */ SyscallDesc("getpmsg", unimplementedFunc), + /* 133 */ SyscallDesc("putpmsg", unimplementedFunc), + /* 134 */ SyscallDesc("rename", unimplementedFunc), + /* 135 */ SyscallDesc("uname", unameFunc), + /* 136 */ SyscallDesc("setegid", unimplementedFunc), + /* 137 */ SyscallDesc("sysconfig", unimplementedFunc), + /* 138 */ SyscallDesc("adjtime", unimplementedFunc), + /* 139 */ SyscallDesc("systeminfo", unimplementedFunc), + /* 140 */ SyscallDesc("reserved_140", unimplementedFunc), + /* 141 */ SyscallDesc("seteuid", unimplementedFunc), + /* 142 */ SyscallDesc("vtrace", unimplementedFunc), + /* 143 */ SyscallDesc("fork1", unimplementedFunc), + /* 144 */ SyscallDesc("sigtimedwait", unimplementedFunc), + /* 145 */ SyscallDesc("lwp_info", unimplementedFunc), + /* 146 */ SyscallDesc("yield", unimplementedFunc), + /* 147 */ SyscallDesc("lwp_sema_wait", unimplementedFunc), + /* 148 */ SyscallDesc("lwp_sema_post", unimplementedFunc), + /* 149 */ SyscallDesc("lwp_sema_trywait", unimplementedFunc), + /* 150 */ SyscallDesc("lwp_detach", unimplementedFunc), + /* 151 */ SyscallDesc("corectl", unimplementedFunc), + /* 152 */ SyscallDesc("modctl", unimplementedFunc), + /* 153 */ SyscallDesc("fchroot", unimplementedFunc), + /* 154 */ SyscallDesc("utimes", unimplementedFunc), + /* 155 */ SyscallDesc("vhangup", unimplementedFunc), + /* 156 */ SyscallDesc("gettimeofday", unimplementedFunc), + /* 157 */ SyscallDesc("getitimer", unimplementedFunc), + /* 158 */ SyscallDesc("setitimer", unimplementedFunc), + /* 159 */ SyscallDesc("lwp_create", unimplementedFunc), + /* 160 */ SyscallDesc("lwp_exit", unimplementedFunc), + /* 161 */ SyscallDesc("lwp_suspend", unimplementedFunc), + /* 162 */ SyscallDesc("lwp_continue", unimplementedFunc), + /* 163 */ SyscallDesc("lwp_kill", unimplementedFunc), + /* 164 */ SyscallDesc("lwp_self", unimplementedFunc), + /* 165 */ SyscallDesc("lwp_setprivate", unimplementedFunc), + /* 166 */ SyscallDesc("lwp_getprivate", unimplementedFunc), + /* 167 */ SyscallDesc("lwp_wait", unimplementedFunc), + /* 168 */ SyscallDesc("lwp_mutex_wakeup", unimplementedFunc), + /* 169 */ SyscallDesc("lwp_mutex_lock", unimplementedFunc), + /* 170 */ SyscallDesc("lwp_cond_wait", unimplementedFunc), + /* 171 */ SyscallDesc("lwp_cond_signal", unimplementedFunc), + /* 172 */ SyscallDesc("lwp_cond_broadcast", unimplementedFunc), + /* 173 */ SyscallDesc("pread", unimplementedFunc), + /* 174 */ SyscallDesc("pwrite", unimplementedFunc), + /* 175 */ SyscallDesc("llseek", unimplementedFunc), + /* 176 */ SyscallDesc("inst_sync", unimplementedFunc), + /* 177 */ SyscallDesc("srmlimitsys", unimplementedFunc), + /* 178 */ SyscallDesc("kaio", unimplementedFunc), + /* 179 */ SyscallDesc("cpc", unimplementedFunc), + /* 180 */ SyscallDesc("lgrpsys_meminfosys", unimplementedFunc), + /* 181 */ SyscallDesc("rusagesys", unimplementedFunc), + /* 182 */ SyscallDesc("reserved_182", unimplementedFunc), + /* 183 */ SyscallDesc("reserved_183", unimplementedFunc), + /* 184 */ SyscallDesc("tsolsys", unimplementedFunc), + /* 185 */ SyscallDesc("acl", unimplementedFunc), + /* 186 */ SyscallDesc("auditsys", unimplementedFunc), + /* 187 */ SyscallDesc("processor_bind", unimplementedFunc), + /* 188 */ SyscallDesc("processor_info", unimplementedFunc), + /* 189 */ SyscallDesc("p_online", unimplementedFunc), + /* 190 */ SyscallDesc("sigqueue", unimplementedFunc), + /* 191 */ SyscallDesc("clock_gettime", unimplementedFunc), + /* 192 */ SyscallDesc("clock_settime", unimplementedFunc), + /* 193 */ SyscallDesc("clock_getres", unimplementedFunc), + /* 194 */ SyscallDesc("timer_create", unimplementedFunc), + /* 195 */ SyscallDesc("timer_delete", unimplementedFunc), + /* 196 */ SyscallDesc("timer_settime", unimplementedFunc), + /* 197 */ SyscallDesc("timer_gettime", unimplementedFunc), + /* 198 */ SyscallDesc("timer_getoverrun", unimplementedFunc), + /* 199 */ SyscallDesc("nanosleep", unimplementedFunc), + /* 200 */ SyscallDesc("facl", unimplementedFunc), + /* 201 */ SyscallDesc("door", unimplementedFunc), + /* 202 */ SyscallDesc("setreuid", unimplementedFunc), + /* 203 */ SyscallDesc("setregid", unimplementedFunc), + /* 204 */ SyscallDesc("install_utrap", unimplementedFunc), + /* 205 */ SyscallDesc("signotify", unimplementedFunc), + /* 206 */ SyscallDesc("schedctl", unimplementedFunc), + /* 207 */ SyscallDesc("pset", unimplementedFunc), + /* 208 */ SyscallDesc("sparc_utrap_install", unimplementedFunc), + /* 209 */ SyscallDesc("resolvepath", unimplementedFunc), + /* 210 */ SyscallDesc("signotifywait", unimplementedFunc), + /* 211 */ SyscallDesc("lwp_sigredirect", unimplementedFunc), + /* 212 */ SyscallDesc("lwp_alarm", unimplementedFunc), + /* 213 */ SyscallDesc("getdents64", unimplementedFunc), + /* 214 */ SyscallDesc("mmap64", unimplementedFunc), + /* 215 */ SyscallDesc("stat64", unimplementedFunc), + /* 216 */ SyscallDesc("lstat64", unimplementedFunc), + /* 217 */ SyscallDesc("fstat64", unimplementedFunc), + /* 218 */ SyscallDesc("statvfs64", unimplementedFunc), + /* 219 */ SyscallDesc("fstatvfs64", unimplementedFunc), + /* 220 */ SyscallDesc("setrlimit64", unimplementedFunc), + /* 221 */ SyscallDesc("getrlimit64", unimplementedFunc), + /* 222 */ SyscallDesc("pread64", unimplementedFunc), + /* 223 */ SyscallDesc("pwrite64", unimplementedFunc), + /* 224 */ SyscallDesc("creat64", unimplementedFunc), + /* 225 */ SyscallDesc("open64", unimplementedFunc), + /* 226 */ SyscallDesc("rpcsys", unimplementedFunc), + /* 227 */ SyscallDesc("reserved_227", unimplementedFunc), + /* 228 */ SyscallDesc("reserved_228", unimplementedFunc), + /* 229 */ SyscallDesc("reserved_229", unimplementedFunc), + /* 230 */ SyscallDesc("so_socket", unimplementedFunc), + /* 231 */ SyscallDesc("so_socketpair", unimplementedFunc), + /* 232 */ SyscallDesc("bind", unimplementedFunc), + /* 233 */ SyscallDesc("listen", unimplementedFunc), + /* 234 */ SyscallDesc("accept", unimplementedFunc), + /* 235 */ SyscallDesc("connect", unimplementedFunc), + /* 236 */ SyscallDesc("shutdown", unimplementedFunc), + /* 237 */ SyscallDesc("recv", unimplementedFunc), + /* 238 */ SyscallDesc("recvfrom", unimplementedFunc), + /* 239 */ SyscallDesc("recvmsg", unimplementedFunc), + /* 240 */ SyscallDesc("send", unimplementedFunc), + /* 241 */ SyscallDesc("sendmsg", unimplementedFunc), + /* 242 */ SyscallDesc("sendto", unimplementedFunc), + /* 243 */ SyscallDesc("getpeername", unimplementedFunc), + /* 244 */ SyscallDesc("getsockname", unimplementedFunc), + /* 245 */ SyscallDesc("getsockopt", unimplementedFunc), + /* 246 */ SyscallDesc("setsockopt", unimplementedFunc), + /* 247 */ SyscallDesc("sockconfig", unimplementedFunc), + /* 248 */ SyscallDesc("ntp_gettime", unimplementedFunc), + /* 249 */ SyscallDesc("ntp_adjtime", unimplementedFunc), + /* 250 */ SyscallDesc("lwp_mutex_unlock", unimplementedFunc), + /* 251 */ SyscallDesc("lwp_mutex_trylock", unimplementedFunc), + /* 252 */ SyscallDesc("lwp_mutex_init", unimplementedFunc), + /* 253 */ SyscallDesc("cladm", unimplementedFunc), + /* 254 */ SyscallDesc("lwp_sigtimedwait", unimplementedFunc), + /* 255 */ SyscallDesc("umount2", unimplementedFunc) +}; + +SparcSolarisProcess::SparcSolarisProcess(const std::string &name, + ObjectFile *objFile, + System * system, + int stdin_fd, + int stdout_fd, + int stderr_fd, + std::vector<std::string> &argv, + std::vector<std::string> &envp) + : SparcLiveProcess(name, objFile, system, + stdin_fd, stdout_fd, stderr_fd, argv, envp), + Num_Syscall_Descs(sizeof(syscallDescs) / sizeof(SyscallDesc)) +{ + // The sparc syscall table must be <= 284 entries because that is all there + // is space for. + assert(Num_Syscall_Descs <= 284); +} + + + +SyscallDesc* +SparcSolarisProcess::getDesc(int callnum) +{ + if (callnum < 0 || callnum > Num_Syscall_Descs) + return NULL; + return &syscallDescs[callnum]; +} diff --git a/src/arch/sparc/solaris/process.hh b/src/arch/sparc/solaris/process.hh new file mode 100644 index 000000000..24dffdaf0 --- /dev/null +++ b/src/arch/sparc/solaris/process.hh @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2003-2004 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __SPARC_SOLARIS_PROCESS_HH__ +#define __SPARC_SOLARIS_PROCESS_HH__ + +#include "arch/sparc/solaris/solaris.hh" +#include "arch/sparc/process.hh" +#include "sim/process.hh" + +namespace SparcISA { + +/// A process with emulated SPARC/Solaris syscalls. +class SparcSolarisProcess : public SparcLiveProcess +{ + public: + /// Constructor. + SparcSolarisProcess(const std::string &name, + ObjectFile *objFile, + System * system, + int stdin_fd, int stdout_fd, int stderr_fd, + std::vector<std::string> &argv, + std::vector<std::string> &envp); + + virtual SyscallDesc* getDesc(int callnum); + + /// The target system's hostname. + static const char *hostname; + + /// Array of syscall descriptors, indexed by call number. + static SyscallDesc syscallDescs[]; + + const int Num_Syscall_Descs; +}; + + +} // namespace SparcISA +#endif // __ALPHA_SOLARIS_PROCESS_HH__ diff --git a/src/arch/sparc/solaris/solaris.cc b/src/arch/sparc/solaris/solaris.cc new file mode 100644 index 000000000..a56f10740 --- /dev/null +++ b/src/arch/sparc/solaris/solaris.cc @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "arch/sparc/solaris/solaris.hh" + +// open(2) flags translation table +OpenFlagTransTable SparcSolaris::openFlagTable[] = { +#ifdef _MSC_VER + { SparcSolaris::TGT_O_RDONLY, _O_RDONLY }, + { SparcSolaris::TGT_O_WRONLY, _O_WRONLY }, + { SparcSolaris::TGT_O_RDWR, _O_RDWR }, + { SparcSolaris::TGT_O_APPEND, _O_APPEND }, + { SparcSolaris::TGT_O_CREAT, _O_CREAT }, + { SparcSolaris::TGT_O_TRUNC, _O_TRUNC }, + { SparcSolaris::TGT_O_EXCL, _O_EXCL }, +#ifdef _O_NONBLOCK + { SparcSolaris::TGT_O_NONBLOCK, _O_NONBLOCK }, + { SparcSolaris::TGT_O_NDELAY , _O_NONBLOCK }, +#endif +#ifdef _O_NOCTTY + { SparcSolaris::TGT_O_NOCTTY, _O_NOCTTY }, +#endif +#ifdef _O_SYNC + { SparcSolaris::TGT_O_SYNC, _O_SYNC }, + { SparcSolaris::TGT_O_DSYNC, _O_SYNC }, + { SparcSolaris::TGT_O_RSYNC, _O_SYNC }, +#endif +#else /* !_MSC_VER */ + { SparcSolaris::TGT_O_RDONLY, O_RDONLY }, + { SparcSolaris::TGT_O_WRONLY, O_WRONLY }, + { SparcSolaris::TGT_O_RDWR, O_RDWR }, + { SparcSolaris::TGT_O_APPEND, O_APPEND }, + { SparcSolaris::TGT_O_CREAT, O_CREAT }, + { SparcSolaris::TGT_O_TRUNC, O_TRUNC }, + { SparcSolaris::TGT_O_EXCL, O_EXCL }, + { SparcSolaris::TGT_O_NONBLOCK, O_NONBLOCK }, + { SparcSolaris::TGT_O_NDELAY , O_NONBLOCK }, + { SparcSolaris::TGT_O_NOCTTY, O_NOCTTY }, +#ifdef O_SYNC + { SparcSolaris::TGT_O_SYNC, O_SYNC }, + { SparcSolaris::TGT_O_DSYNC, O_SYNC }, + { SparcSolaris::TGT_O_RSYNC, O_SYNC }, +#endif +#endif /* _MSC_VER */ +}; + +const int SparcSolaris::NUM_OPEN_FLAGS = + (sizeof(SparcSolaris::openFlagTable)/sizeof(SparcSolaris::openFlagTable[0])); + diff --git a/src/arch/sparc/solaris/solaris.hh b/src/arch/sparc/solaris/solaris.hh new file mode 100644 index 000000000..6833a2d6a --- /dev/null +++ b/src/arch/sparc/solaris/solaris.hh @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ARCH_SPARC_SOLARIS_SOLARIS_HH__ +#define __ARCH_SPARC_SOLARIS_SOLARIS_HH__ + +#include "kern/solaris/solaris.hh" + +class SparcSolaris : public Solaris +{ + public: + + static OpenFlagTransTable openFlagTable[]; + + static const int TGT_O_RDONLY = 0x00000000; //!< O_RDONLY + static const int TGT_O_WRONLY = 0x00000001; //!< O_WRONLY + static const int TGT_O_RDWR = 0x00000002; //!< O_RDWR + static const int TGT_O_NDELAY = 0x00000004; //!< O_NONBLOCK + static const int TGT_O_APPEND = 0x00000008; //!< O_APPEND + static const int TGT_O_SYNC = 0x00000010; //!< O_SYNC + static const int TGT_O_DSYNC = 0x00000040; //!< O_SYNC + static const int TGT_O_RSYNC = 0x00008000; //!< O_SYNC + static const int TGT_O_NONBLOCK = 0x00000080; //!< O_NONBLOCK + static const int TGT_O_PRIV = 0x00001000; //?? + static const int TGT_O_LARGEFILE = 0x00002000; //?? + static const int TGT_O_CREAT = 0x00000100; //!< O_CREAT + static const int TGT_O_TRUNC = 0x00000200; //!< O_TRUNC + static const int TGT_O_EXCL = 0x00000400; //!< O_EXCL + static const int TGT_O_NOCTTY = 0x00000800; //!< O_NOCTTY + static const int TGT_O_XATTR = 0x00004000; //?? + + static const int NUM_OPEN_FLAGS; + + static const unsigned TGT_MAP_ANONYMOUS = 0x100; +}; + +#endif diff --git a/arch/sparc/stacktrace.hh b/src/arch/sparc/stacktrace.hh index 1d8d97a79..1d8d97a79 100644 --- a/arch/sparc/stacktrace.hh +++ b/src/arch/sparc/stacktrace.hh diff --git a/src/arch/sparc/system.cc b/src/arch/sparc/system.cc new file mode 100644 index 000000000..44413e339 --- /dev/null +++ b/src/arch/sparc/system.cc @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2002-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "arch/sparc/system.hh" +#include "arch/vtophys.hh" +#include "base/remote_gdb.hh" +#include "base/loader/object_file.hh" +#include "base/loader/symtab.hh" +#include "base/trace.hh" +#include "mem/physical.hh" +#include "sim/byteswap.hh" +#include "sim/builder.hh" + + +using namespace BigEndianGuest; + +SparcSystem::SparcSystem(Params *p) + : System(p), sysTick(0) + +{ + resetSymtab = new SymbolTable; + hypervisorSymtab = new SymbolTable; + openbootSymtab = new SymbolTable; + + + /** + * Load the boot code, and hypervisor into memory. + */ + // Read the reset binary + reset = createObjectFile(params()->reset_bin); + if (reset == NULL) + fatal("Could not load reset binary %s", params()->reset_bin); + + // Read the openboot binary + openboot = createObjectFile(params()->openboot_bin); + if (openboot == NULL) + fatal("Could not load openboot bianry %s", params()->openboot_bin); + + // Read the hypervisor binary + hypervisor = createObjectFile(params()->hypervisor_bin); + if (hypervisor == NULL) + fatal("Could not load hypervisor binary %s", params()->hypervisor_bin); + + + // Load reset binary into memory + reset->loadSections(&functionalPort, SparcISA::LoadAddrMask); + // Load the openboot binary + openboot->loadSections(&functionalPort, SparcISA::LoadAddrMask); + // Load the hypervisor binary + hypervisor->loadSections(&functionalPort, SparcISA::LoadAddrMask); + + // load symbols + if (!reset->loadGlobalSymbols(reset)) + panic("could not load reset symbols\n"); + + if (!openboot->loadGlobalSymbols(openbootSymtab)) + panic("could not load openboot symbols\n"); + + if (!hypervisor->loadLocalSymbols(hypervisorSymtab)) + panic("could not load hypervisor symbols\n"); + + // load symbols into debug table + if (!reset->loadGlobalSymbols(debugSymbolTable)) + panic("could not load reset symbols\n"); + + if (!openboot->loadGlobalSymbols(debugSymbolTable)) + panic("could not load openboot symbols\n"); + + if (!hypervisor->loadLocalSymbols(debugSymbolTable)) + panic("could not load hypervisor symbols\n"); + + + // @todo any fixup code over writing data in binaries on setting break + // events on functions should happen here. + +} + +SparcSystem::~SparcSystem() +{ + delete resetSymtab; + delete hypervisorSymtab; + delete openbootSymtab; + delete reset; + delete openboot; + delete hypervisor; +} + +bool +SparcSystem::breakpoint() +{ + panic("Need to implement"); +} + +void +SparcSystem::serialize(std::ostream &os) +{ + System::serialize(os); + resetSymtab->serialize("reset_symtab", os); + hypervisorSymtab->serialize("hypervisor_symtab", os); + openbootSymtab->serialize("openboot_symtab", os); +} + + +void +SparcSystem::unserialize(Checkpoint *cp, const std::string §ion) +{ + System::unserialize(cp,section); + resetSymtab->unserialize("reset_symtab", cp, section); + hypervisorSymtab->unserialize("hypervisor_symtab", cp, section); + openbootSymtab->unserialize("openboot_symtab", cp, section); +} + + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(SparcSystem) + + SimObjectParam<PhysicalMemory *> physmem; + + Param<std::string> kernel; + Param<std::string> reset_bin; + Param<std::string> hypervisor_bin; + Param<std::string> openboot_bin; + + Param<std::string> boot_osflags; + Param<std::string> readfile; + Param<unsigned int> init_param; + + Param<bool> bin; + VectorParam<std::string> binned_fns; + Param<bool> bin_int; + +END_DECLARE_SIM_OBJECT_PARAMS(SparcSystem) + +BEGIN_INIT_SIM_OBJECT_PARAMS(SparcSystem) + + INIT_PARAM(boot_cpu_frequency, "Frequency of the boot CPU"), + INIT_PARAM(physmem, "phsyical memory"), + INIT_PARAM(kernel, "file that contains the kernel code"), + INIT_PARAM(reset_bin, "file that contains the reset code"), + INIT_PARAM(hypervisor_bin, "file that contains the hypervisor code"), + INIT_PARAM(openboot_bin, "file that contains the openboot code"), + INIT_PARAM_DFLT(boot_osflags, "flags to pass to the kernel during boot", + "a"), + INIT_PARAM_DFLT(readfile, "file to read startup script from", ""), + INIT_PARAM_DFLT(init_param, "numerical value to pass into simulator", 0), + INIT_PARAM_DFLT(system_type, "Type of system we are emulating", 34), + INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 1<<10), + INIT_PARAM_DFLT(bin, "is this system to be binned", false), + INIT_PARAM(binned_fns, "functions to be broken down and binned"), + INIT_PARAM_DFLT(bin_int, "is interrupt code binned seperately?", true) + +END_INIT_SIM_OBJECT_PARAMS(SparcSystem) + +CREATE_SIM_OBJECT(SparcSystem) +{ + SparcSystem::Params *p = new SparcSystem::Params; + p->name = getInstanceName(); + p->boot_cpu_frequency = boot_cpu_frequency; + p->physmem = physmem; + p->kernel_path = kernel; + p->reset_bin = reset_bin; + p->hypervisor_bin = hypervisor_bin; + p->openboot_bin = openboot_bin; + p->boot_osflags = boot_osflags; + p->init_param = init_param; + p->readfile = readfile; + p->system_type = system_type; + p->system_rev = system_rev; + p->bin = bin; + p->binned_fns = binned_fns; + p->bin_int = bin_int; + return new SparcSystem(p); +} + +REGISTER_SIM_OBJECT("SparcSystem", SparcSystem) + + diff --git a/src/arch/sparc/system.hh b/src/arch/sparc/system.hh new file mode 100644 index 000000000..a3eee7555 --- /dev/null +++ b/src/arch/sparc/system.hh @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ARCH_SPARC_SYSTEM_HH__ +#define __ARCH_SPARC_SYSTEM_HH__ + +#include <string> +#include <vector> + +#include "base/loader/symtab.hh" +#include "cpu/pc_event.hh" +#include "kern/system_events.hh" +#include "sim/sim_object.hh" +#include "sim/system.hh" + +class SparcSystem : public System +{ + public: + struct Params : public System::Params + { + std::string reset_bin; + std::string hypervison_bin; + std::string openboot_bin; + std::string boot_osflags; + uint64_t system_type; + uint64_t system_rev; + }; + + SparcSystem(Params *p); + + ~SparcSystem(); + + virtual bool breakpoint(); + +/** + * Serialization stuff + */ + public: + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); + + /** reset binary symbol table */ + SymbolTable *resetSymtab; + + /** hypervison binary symbol table */ + SymbolTable *hypervisorSymtab; + + /** openboot symbol table */ + SymbolTable *openbootSymtab; + + /** Object pointer for the reset binary */ + ObjectFile *reset; + + /** Object pointer for the hypervisor code */ + ObjectFile *hypervisor; + + /** Object pointer for the openboot code */ + ObjectFile *openboot; + + /** System Tick for syncronized tick across all cpus. */ + Tick sysTick; + + protected: + const Params *params() const { return (const Params *)_params; } + + /** Add a function-based event to reset binary. */ + template <class T> + T *SparcSystem::addResetFuncEvent(const char *lbl) + { + return addFuncEvent<T>(resetSymtab, lbl); + } + + /** Add a function-based event to the hypervisor. */ + template <class T> + T *SparcSystem::addHypervisorFuncEvent(const char *lbl) + { + return addFuncEvent<T>(hypervisorSymtab, lbl); + } + + /** Add a function-based event to the openboot. */ + template <class T> + T *SparcSystem::addOpenbootFuncEvent(const char *lbl) + { + return addFuncEvent<T>(openbootSymtab, lbl); + } + + virtual Addr fixFuncEventAddr(Addr addr); + +}; + +#endif + diff --git a/src/arch/sparc/tlb.hh b/src/arch/sparc/tlb.hh new file mode 100644 index 000000000..35ff08b43 --- /dev/null +++ b/src/arch/sparc/tlb.hh @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Ali Saidi + */ + +#ifndef __ARCH_SPARC_TLB_HH__ +#define __ARCH_SPARC_TLB_HH__ + + +#endif // __ARCH_SPARC_TLB_HH__ diff --git a/src/arch/sparc/ua2005.cc b/src/arch/sparc/ua2005.cc new file mode 100644 index 000000000..680e94080 --- /dev/null +++ b/src/arch/sparc/ua2005.cc @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "arch/sparc/regfile.hh" + +Fault +SparcISA::MiscRegFile::setFSRegWithEffect(int miscReg, const MiscReg &val, + ExecContext *xc) +{ + int64_t time; + SparcSystem *sys; + switch (miscReg) { + /** Full system only ASRs */ + case MISCREG_SOFTINT: + if (isNonPriv()) + return new PrivilegedOpcode; + // Check if we are going to interrupt because of something + int oldLevel = InterruptLevel(softint); + int newLevel = InterruptLevel(val); + setReg(miscReg, val); + if (newLevel > oldLevel) + ; // MUST DO SOMETHING HERE TO TELL CPU TO LOOK FOR INTERRUPTS XXX + //xc->getCpuPtr()->checkInterrupts = true; + return NoFault; + + case MISCREG_SOFTINT_CLR: + return setRegWithEffect(miscReg, ~val & softint, xc); + case MISCREG_SOFTINT_SET: + return setRegWithEffect(miscReg, val | softint, xc); + + case MISCREG_TICK_CMPR: + if (isNonPriv()) + return new PrivilegedOpcode; + if (tickCompare == NULL) + tickCompare = new TickCompareEvent(this, xc); + setReg(miscReg, val); + if (tick_cmprFields.int_dis && tickCompare.scheduled()) + tickCompare.deschedule(); + time = tick_cmprFields.tick_cmpr - tickFields.counter; + if (!tick_cmprFields.int_dis && time > 0) + tickCompare.schedule(time * xc->getCpuPtr()->cycles(1)); + return NoFault; + + case MISCREG_STICK: + if (isNonPriv()) + return new PrivilegedOpcode; + if (isPriv()) + return new PrivilegedAction; + sys = dynamic_cast<SparcSystem*>(xc->getSystemPtr()); + assert(sys != NULL); + sys->sysTick = curTick/Clock::Int::ns - val & ~Bit64; + stickFields.npt = val & Bit64 ? 1 : 0; + return NoFault; + + case MISCREG_STICK_CMPR: + if (isNonPriv()) + return new PrivilegedOpcode; + if (sTickCompare == NULL) + sTickCompare = new STickCompareEvent(this, xc); + sys = dynamic_cast<SparcSystem*>(xc->getSystemPtr()); + assert(sys != NULL); + setReg(miscReg, val); + if (stick_cmprFields.int_dis && sTickCompare.scheduled()) + sTickCompare.deschedule(); + time = stick_cmprFields.tick_cmpr - sys->sysTick; + if (!stick_cmprFields.int_dis && time > 0) + sTickCompare.schedule(time * Clock::Int::ns); + return NoFault; + + /** Fullsystem only Priv registers. */ + case MISCREG_PIL: + if (FULL_SYSTEM) { + setReg(miscReg, val); + //xc->getCpuPtr()->checkInterrupts; + // MUST DO SOMETHING HERE TO TELL CPU TO LOOK FOR INTERRUPTS XXX + return NoFault; + } else + panic("PIL not implemented for syscall emulation\n"); + + /** Hyper privileged registers */ + case MISCREG_HPSTATE: + case MISCREG_HINTP: + setReg(miscReg, val); + return NoFault; + case MISCREG_HTSTATE: + if (tl == 0) + return new IllegalInstruction; + setReg(miscReg, val); + return NoFault; + + case MISCREG_HTBA: + // clear lower 7 bits on writes. + setReg(miscReg, val & ULL(~0x7FFF)); + return NoFault; + + case MISCREG_STRAND_STS_REG: + setReg(miscReg, strandStatusReg); + return NoFault; + case MISCREG_HSTICK_CMPR: + if (isNonPriv()) + return new PrivilegedOpcode; + if (hSTickCompare == NULL) + hSTickCompare = new HSTickCompareEvent(this, xc); + sys = dynamic_cast<SparcSystem*>(xc->getSystemPtr()); + assert(sys != NULL); + setReg(miscReg, val); + if (hstick_cmprFields.int_dis && hSTickCompare.scheduled()) + hSTickCompare.deschedule(); + int64_t time = hstick_cmprFields.tick_cmpr - sys->sysTick; + if (!hstick_cmprFields.int_dis && time > 0) + hSTickCompare.schedule(time * Clock::Int::ns); + return NoFault; + default: + return new IllegalInstruction; + } +} + +MiscReg +MiscRegFile::readFSRegWithEffect(int miscReg, Fault &fault, ExecContext * xc) +{ + switch (miscReg) { + + /** Privileged registers. */ + case MISCREG_SOFTINT: + if (isNonPriv()) { + fault = new PrivilegedOpcode; + return 0; + } + return readReg(miscReg); + case MISCREG_TICK_CMPR: + if (isNonPriv()) { + fault = new PrivilegedOpcode; + return 0; + } + return readReg(miscReg); + case MISCREG_STICK: + SparcSystem *sys; + if (stickFields.npt && !isNonPriv()) { + fault = new PrivilegedAction; + return 0; + } + sys = dynamic_cast<SparcSystem*>(xc->getSystemPtr()); + assert(sys != NULL); + return curTick/Clock::Int::ns - sys->sysTick | stickFields.npt << 63; + case MISCREG_STICK_CMPR: + if (isNonPriv()) { + fault = new PrivilegedOpcode; + return 0; + } + return readReg(miscReg); + + + /** Hyper privileged registers */ + case MISCREG_HPSTATE: + case MISCREG_HINTP: + return readReg(miscReg); + case MISCREG_HTSTATE: + if (tl == 0) { + fault = new IllegalInstruction; + return 0; + } + return readReg(miscReg); + + case MISCREG_HTBA: + return readReg(miscReg) & ULL(~0x7FFF); + case MISCREG_HVER: + return NWindows | MaxTL << 8 | MaxGL << 16; + case MISCREG_STRAND_STS_REG: + return strandStatusReg; + case MISCREG_HSTICK_CMPR: + return hstick_cmpr; + + default: + fault = new IllegalInstruction; + return 0; + } +} + +void +MiscRegFile::processTickCompare(ExecContext *xc) +{ + panic("tick compare not implemented\n"); +} + +void +MiscRegFile::processSTickCompare(ExecContext *xc) +{ + panic("tick compare not implemented\n"); +} + +void +MiscRegFile::processHSTickCompare(ExecContext *xc) +{ + panic("tick compare not implemented\n"); +} + +}; // namespace SparcISA diff --git a/src/arch/sparc/utility.hh b/src/arch/sparc/utility.hh new file mode 100644 index 000000000..1e67b3370 --- /dev/null +++ b/src/arch/sparc/utility.hh @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ARCH_SPARC_UTILITY_HH__ +#define __ARCH_SPARC_UTILITY_HH__ + +#include "arch/sparc/isa_traits.hh" +#include "base/misc.hh" + +namespace SparcISA +{ + inline ExtMachInst + makeExtMI(MachInst inst, const Addr &pc) { + return ExtMachInst(inst); + } + + inline bool isCallerSaveIntegerRegister(unsigned int reg) { + panic("register classification not implemented"); + return false; + } + + inline bool isCalleeSaveIntegerRegister(unsigned int reg) { + panic("register classification not implemented"); + return false; + } + + inline bool isCallerSaveFloatRegister(unsigned int reg) { + panic("register classification not implemented"); + return false; + } + + inline bool isCalleeSaveFloatRegister(unsigned int reg) { + panic("register classification not implemented"); + return false; + } + + // Instruction address compression hooks + inline Addr realPCToFetchPC(const Addr &addr) + { + return addr; + } + + inline Addr fetchPCToRealPC(const Addr &addr) + { + return addr; + } + + // the size of "fetched" instructions (not necessarily the size + // of real instructions for PISA) + inline size_t fetchInstSize() + { + return sizeof(MachInst); + } + + /** + * Function to insure ISA semantics about 0 registers. + * @param xc The execution context. + */ + template <class XC> + void zeroRegisters(XC *xc); + +} // namespace SparcISA + +#endif diff --git a/src/arch/sparc/vtophys.cc b/src/arch/sparc/vtophys.cc new file mode 100644 index 000000000..41e9b80a3 --- /dev/null +++ b/src/arch/sparc/vtophys.cc @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <string> + +#include "arch/alpha/ev5.hh" +#include "arch/alpha/vtophys.hh" +#include "base/chunk_generator.hh" +#include "base/trace.hh" +#include "cpu/exec_context.hh" +#include "mem/vport.hh" + +using namespace std; +using namespace AlphaISA; + +AlphaISA::PageTableEntry +AlphaISA::kernel_pte_lookup(FunctionalPort *mem, Addr ptbr, AlphaISA::VAddr vaddr) +{ + Addr level1_pte = ptbr + vaddr.level1(); + AlphaISA::PageTableEntry level1 = mem->read<uint64_t>(level1_pte); + if (!level1.valid()) { + DPRINTF(VtoPhys, "level 1 PTE not valid, va = %#\n", vaddr); + return 0; + } + + Addr level2_pte = level1.paddr() + vaddr.level2(); + AlphaISA::PageTableEntry level2 = mem->read<uint64_t>(level2_pte); + if (!level2.valid()) { + DPRINTF(VtoPhys, "level 2 PTE not valid, va = %#x\n", vaddr); + return 0; + } + + Addr level3_pte = level2.paddr() + vaddr.level3(); + AlphaISA::PageTableEntry level3 = mem->read<uint64_t>(level3_pte); + if (!level3.valid()) { + DPRINTF(VtoPhys, "level 3 PTE not valid, va = %#x\n", vaddr); + return 0; + } + return level3; +} + +Addr +AlphaISA::vtophys(Addr vaddr) +{ + Addr paddr = 0; + if (AlphaISA::IsUSeg(vaddr)) + DPRINTF(VtoPhys, "vtophys: invalid vaddr %#x", vaddr); + else if (AlphaISA::IsK0Seg(vaddr)) + paddr = AlphaISA::K0Seg2Phys(vaddr); + else + panic("vtophys: ptbr is not set on virtual lookup"); + + DPRINTF(VtoPhys, "vtophys(%#x) -> %#x\n", vaddr, paddr); + + return paddr; +} + +Addr +AlphaISA::vtophys(ExecContext *xc, Addr addr) +{ + AlphaISA::VAddr vaddr = addr; + Addr ptbr = xc->readMiscReg(AlphaISA::IPR_PALtemp20); + Addr paddr = 0; + //@todo Andrew couldn't remember why he commented some of this code + //so I put it back in. Perhaps something to do with gdb debugging? + if (AlphaISA::PcPAL(vaddr) && (vaddr < EV5::PalMax)) { + paddr = vaddr & ~ULL(1); + } else { + if (AlphaISA::IsK0Seg(vaddr)) { + paddr = AlphaISA::K0Seg2Phys(vaddr); + } else if (!ptbr) { + paddr = vaddr; + } else { + AlphaISA::PageTableEntry pte = + kernel_pte_lookup(xc->getPhysPort(), ptbr, vaddr); + if (pte.valid()) + paddr = pte.paddr() | vaddr.offset(); + } + } + + + DPRINTF(VtoPhys, "vtophys(%#x) -> %#x\n", vaddr, paddr); + + return paddr; +} + + +void +AlphaISA::CopyOut(ExecContext *xc, void *dest, Addr src, size_t cplen) +{ + uint8_t *dst = (uint8_t *)dest; + VirtualPort *vp = xc->getVirtPort(xc); + + vp->readBlob(src, dst, cplen); + + xc->delVirtPort(vp); + +} + +void +AlphaISA::CopyIn(ExecContext *xc, Addr dest, void *source, size_t cplen) +{ + uint8_t *src = (uint8_t *)source; + VirtualPort *vp = xc->getVirtPort(xc); + + vp->writeBlob(dest, src, cplen); + + xc->delVirtPort(vp); +} + +void +AlphaISA::CopyStringOut(ExecContext *xc, char *dst, Addr vaddr, size_t maxlen) +{ + int len = 0; + VirtualPort *vp = xc->getVirtPort(xc); + + do { + vp->readBlob(vaddr++, (uint8_t*)dst++, 1); + len++; + } while (len < maxlen && dst[len] != 0 ); + + xc->delVirtPort(vp); + dst[len] = 0; +} + +void +AlphaISA::CopyStringIn(ExecContext *xc, char *src, Addr vaddr) +{ + VirtualPort *vp = xc->getVirtPort(xc); + for (ChunkGenerator gen(vaddr, strlen(src), AlphaISA::PageBytes); !gen.done(); + gen.next()) + { + vp->writeBlob(gen.addr(), (uint8_t*)src, gen.size()); + src += gen.size(); + } + xc->delVirtPort(vp); +} diff --git a/src/arch/sparc/vtophys.hh b/src/arch/sparc/vtophys.hh new file mode 100644 index 000000000..dcd8839e6 --- /dev/null +++ b/src/arch/sparc/vtophys.hh @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ARCH_SPARC_VTOPHYS_H__ +#define __ARCH_SPARC_VTOPHYS_H__ + +#include "arch/sparc/isa_traits.hh" + +class ExecContext; +class FunctionalPort; + +namespace SparcISA { + +PageTableEntry +kernel_pte_lookup(FunctionalPort *mem, Addr ptbr, SparcISA::VAddr vaddr); + +Addr vtophys(Addr vaddr); +Addr vtophys(ExecContext *xc, Addr vaddr); + +void CopyOut(ExecContext *xc, void *dst, Addr src, size_t len); +void CopyIn(ExecContext *xc, Addr dst, void *src, size_t len); +void CopyStringOut(ExecContext *xc, char *dst, Addr vaddr, size_t maxlen); +void CopyStringIn(ExecContext *xc, char *src, Addr vaddr); + +}; +#endif // __ARCH_SPARC_VTOPHYS_H__ + diff --git a/base/bitfield.hh b/src/base/bitfield.hh index c59354c7d..c59354c7d 100644 --- a/base/bitfield.hh +++ b/src/base/bitfield.hh diff --git a/base/callback.hh b/src/base/callback.hh index 7b3023505..7b3023505 100644 --- a/base/callback.hh +++ b/src/base/callback.hh diff --git a/src/base/chunk_generator.hh b/src/base/chunk_generator.hh new file mode 100644 index 000000000..4f708bd4b --- /dev/null +++ b/src/base/chunk_generator.hh @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __BASE__CHUNK_GENERATOR_HH__ +#define __BASE__CHUNK_GENERATOR_HH__ + +/** + * @file + * Declaration and inline definition of ChunkGenerator object. + */ + +#include <algorithm> +#include "base/intmath.hh" +#include "arch/isa_traits.hh" // for Addr + +/** + * This class takes an arbitrary memory region (address/length pair) + * and generates a series of appropriately (e.g. block- or page-) + * aligned chunks covering the same region. + * + * Example usage: + +\code + for (ChunkGenerator gen(addr, size, chunkSize); !gen.done(); gen.next()) { + doSomethingChunky(gen.addr(), gen.size()); + } +\endcode + */ +class ChunkGenerator +{ + private: + /** The starting address of the current chunk. */ + Addr curAddr; + /** The starting address of the next chunk (after the current one). */ + Addr nextAddr; + /** The size of the current chunk (in bytes). */ + int curSize; + /** The number of bytes remaining in the region after the current chunk. */ + int sizeLeft; + /** The start address so we can calculate offset in writing block. */ + const Addr startAddr; + /** The maximum chunk size, e.g., the cache block size or page size. */ + const int chunkSize; + + public: + /** + * Constructor. + * @param startAddr The starting address of the region. + * @param totalSize The total size of the region. + * @param _chunkSize The size/alignment of chunks into which + * the region should be decomposed. + */ + ChunkGenerator(Addr _startAddr, int totalSize, int _chunkSize) + : startAddr(_startAddr), chunkSize(_chunkSize) + { + // chunkSize must be a power of two + assert(chunkSize == 0 || isPowerOf2(chunkSize)); + + // set up initial chunk. + curAddr = startAddr; + + if (chunkSize == 0) //Special Case, if we see 0, assume no chuncking + { + nextAddr = startAddr + totalSize; + } + else + { + // nextAddr should be *next* chunk start + nextAddr = roundUp(startAddr, chunkSize); + if (curAddr == nextAddr) { + // ... even if startAddr is already chunk-aligned + nextAddr += chunkSize; + } + } + + // how many bytes are left between curAddr and the end of this chunk? + int left_in_chunk = nextAddr - curAddr; + curSize = std::min(totalSize, left_in_chunk); + sizeLeft = totalSize - curSize; + } + + /** Return starting address of current chunk. */ + Addr addr() { return curAddr; } + /** Return size in bytes of current chunk. */ + int size() { return curSize; } + + /** Number of bytes we have already chunked up. */ + int complete() { return curAddr - startAddr; } + /** + * Are we done? That is, did the last call to next() advance + * past the end of the region? + * @return True if yes, false if more to go. + */ + bool done() { return (curSize == 0); } + + /** + * Advance generator to next chunk. + * @return True if successful, false if unsuccessful + * (because we were at the last chunk). + */ + bool next() + { + if (sizeLeft == 0) { + curSize = 0; + return false; + } + + curAddr = nextAddr; + curSize = std::min(sizeLeft, chunkSize); + sizeLeft -= curSize; + nextAddr += curSize; + return true; + } +}; + +#endif // __BASE__CHUNK_GENERATOR_HH__ diff --git a/base/circlebuf.cc b/src/base/circlebuf.cc index 89bbfd822..89bbfd822 100644 --- a/base/circlebuf.cc +++ b/src/base/circlebuf.cc diff --git a/base/circlebuf.hh b/src/base/circlebuf.hh index 8a64cb5f5..8a64cb5f5 100644 --- a/base/circlebuf.hh +++ b/src/base/circlebuf.hh diff --git a/base/compression/lzss_compression.cc b/src/base/compression/lzss_compression.cc index 3ffdf7e95..3ffdf7e95 100644 --- a/base/compression/lzss_compression.cc +++ b/src/base/compression/lzss_compression.cc diff --git a/base/compression/lzss_compression.hh b/src/base/compression/lzss_compression.hh index c136c6d60..c136c6d60 100644 --- a/base/compression/lzss_compression.hh +++ b/src/base/compression/lzss_compression.hh diff --git a/base/compression/null_compression.hh b/src/base/compression/null_compression.hh index 5fbcf562b..5fbcf562b 100644 --- a/base/compression/null_compression.hh +++ b/src/base/compression/null_compression.hh diff --git a/base/cprintf.cc b/src/base/cprintf.cc index cf332ebf2..cf332ebf2 100644 --- a/base/cprintf.cc +++ b/src/base/cprintf.cc diff --git a/src/base/cprintf.hh b/src/base/cprintf.hh new file mode 100644 index 000000000..c468c375f --- /dev/null +++ b/src/base/cprintf.hh @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __CPRINTF_HH__ +#define __CPRINTF_HH__ + +#include <iostream> +#include <list> +#include <string> + +#include "base/cprintf_formats.hh" + +namespace cp { + +class ArgList +{ + private: + class Base + { + public: + virtual ~Base() {} + virtual void process(std::ostream &out, Format &fmt) = 0; + }; + + template <typename T> + class Node : public Base + { + public: + const T &data; + + public: + Node(const T &d) : data(d) {} + virtual void process(std::ostream &out, Format &fmt) { + switch (fmt.format) { + case Format::character: + format_char(out, data, fmt); + break; + + case Format::integer: + format_integer(out, data, fmt); + break; + + case Format::floating: + format_float(out, data, fmt); + break; + + case Format::string: + format_string(out, data, fmt); + break; + + default: + out << "<bad format>"; + break; + } + } + }; + + typedef std::list<Base *> list_t; + + protected: + list_t objects; + std::ostream *stream; + + public: + ArgList() : stream(&std::cout) {} + ~ArgList(); + + template<class T> + void append(const T &data) { + Base *obj = new ArgList::Node<T>(data); + objects.push_back(obj); + } + + template<class T> + void prepend(const T &data) { + Base *obj = new ArgList::Node<T>(data); + objects.push_front(obj); + } + + void dump(const std::string &format); + void dump(std::ostream &strm, const std::string &fmt) + { stream = &strm; dump(fmt); } + + std::string dumpToString(const std::string &format); + + friend ArgList &operator<<(std::ostream &str, ArgList &list); +}; + +template<class T> +inline ArgList & +operator,(ArgList &alist, const T &data) +{ + alist.append(data); + return alist; +} + +class ArgListNull { +}; + +inline ArgList & +operator,(ArgList &alist, ArgListNull) +{ return alist; } + +// +// cprintf(format, args, ...) prints to cout +// (analogous to printf()) +// +inline void +__cprintf(const std::string &format, ArgList &args) +{ args.dump(format); delete &args; } +#define __cprintf__(format, args...) \ + cp::__cprintf(format, (*(new cp::ArgList), args)) +#define cprintf(args...) \ + __cprintf__(args, cp::ArgListNull()) + +// +// ccprintf(stream, format, args, ...) prints to the specified stream +// (analogous to fprintf()) +// +inline void +__ccprintf(std::ostream &stream, const std::string &format, ArgList &args) +{ args.dump(stream, format); delete &args; } +#define __ccprintf__(stream, format, args...) \ + cp::__ccprintf(stream, format, (*(new cp::ArgList), args)) +#define ccprintf(stream, args...) \ + __ccprintf__(stream, args, cp::ArgListNull()) + +// +// csprintf(format, args, ...) returns a string +// (roughly analogous to sprintf()) +// +inline std::string +__csprintf(const std::string &format, ArgList &args) +{ std::string s = args.dumpToString(format); delete &args; return s; } +#define __csprintf__(format, args...) \ + cp::__csprintf(format, (*(new cp::ArgList), args)) +#define csprintf(args...) \ + __csprintf__(args, cp::ArgListNull()) + +template<class T> +inline ArgList & +operator<<(ArgList &list, const T &data) +{ + list.append(data); + return list; +} + +inline ArgList & +operator<<(std::ostream &str, ArgList &list) +{ + list.stream = &str; + return list; +} + +class ArgListTemp +{ + private: + std::string format; + ArgList *args; + + public: + ArgListTemp(const std::string &f) : format(f) { args = new ArgList; } + ~ArgListTemp() { args->dump(format); delete args; } + + operator ArgList *() { return args; } +}; + +#define cformat(format) \ + (*((cp::ArgList *)cp::ArgListTemp(format))) +} + +#endif // __CPRINTF_HH__ diff --git a/src/base/cprintf_formats.hh b/src/base/cprintf_formats.hh new file mode 100644 index 000000000..05a8723a4 --- /dev/null +++ b/src/base/cprintf_formats.hh @@ -0,0 +1,353 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __CPRINTF_FORMATS_HH__ +#define __CPRINTF_FORMATS_HH__ + +#include <sstream> +#include <ostream> + +namespace cp { + +struct Format +{ + bool alternate_form; + bool flush_left; + bool print_sign; + bool blank_space; + bool fill_zero; + bool uppercase; + enum { dec, hex, oct } base; + enum { none, string, integer, character, floating } format; + enum { best, fixed, scientific } float_format; + int precision; + int width; + + Format() { clear(); } + + void clear() + { + alternate_form = false; + flush_left = false; + print_sign = false; + blank_space = false; + fill_zero = false; + uppercase = false; + base = dec; + format = none; + precision = -1; + width = 0; + } +}; + +template <typename T> +inline void +_format_char(std::ostream &out, const T &data, Format &fmt) +{ + using namespace std; + + out << data; +} + +template <typename T> +inline void +_format_integer(std::ostream &out, const T &data, Format &fmt) +{ + using namespace std; + + switch (fmt.base) { + case Format::hex: + out.setf(ios::hex, ios::basefield); + break; + + case Format::oct: + out.setf(ios::oct, ios::basefield); + break; + + case Format::dec: + out.setf(ios::dec, ios::basefield); + break; + } + + if (fmt.alternate_form) { + if (!fmt.fill_zero) + out.setf(ios::showbase); + else { + switch (fmt.base) { + case Format::hex: + out << "0x"; + fmt.width -= 2; + break; + case Format::oct: + out << "0"; + fmt.width -= 1; + break; + case Format::dec: + break; + } + } + } + + if (fmt.fill_zero) + out.fill('0'); + + if (fmt.width > 0) + out.width(fmt.width); + + if (fmt.flush_left && !fmt.fill_zero) + out.setf(ios::left); + + if (fmt.print_sign) + out.setf(ios::showpos); + + if (fmt.uppercase) + out.setf(ios::uppercase); + + out << data; +} + +template <typename T> +inline void +_format_float(std::ostream &out, const T &data, Format &fmt) +{ + using namespace std; + + switch (fmt.float_format) { + case Format::scientific: + if (fmt.precision != -1) { + if (fmt.width > 0) + out.width(fmt.width); + + if (fmt.precision == 0) + fmt.precision = 1; + else + out.setf(ios::scientific); + + out.precision(fmt.precision); + } else + if (fmt.width > 0) + out.width(fmt.width); + + if (fmt.uppercase) + out.setf(ios::uppercase); + break; + + case Format::fixed: + if (fmt.precision != -1) { + if (fmt.width > 0) + out.width(fmt.width); + + out.setf(ios::fixed); + out.precision(fmt.precision); + } else + if (fmt.width > 0) + out.width(fmt.width); + + break; + + default: + if (fmt.precision != -1) + out.precision(fmt.precision); + + if (fmt.width > 0) + out.width(fmt.width); + + break; + } + + out << data; +} + +template <typename T> +inline void +_format_string(std::ostream &out, const T &data, Format &fmt) +{ + using namespace std; + +#if defined(__GNUC__) && (__GNUC__ < 3) || 1 + if (fmt.width > 0) { + std::stringstream foo; + foo << data; + int flen = foo.str().size(); + + if (fmt.width > flen) { + char *spaces = new char[fmt.width - flen + 1]; + memset(spaces, ' ', fmt.width - flen); + spaces[fmt.width - flen] = 0; + + if (fmt.flush_left) + out << foo.str() << spaces; + else + out << spaces << foo.str(); + + delete [] spaces; + } else + out << data; + } else + out << data; +#else + if (fmt.width > 0) + out.width(fmt.width); + if (fmt.flush_left) + out.setf(ios::left); + + out << data; +#endif +} + +///////////////////////////////////////////////////////////////////////////// +// +// The code below controls the actual usage of formats for various types +// + +// +// character formats +// +template <typename T> +inline void +format_char(std::ostream &out, const T &data, Format &fmt) +{ out << "<bad arg type for char format>"; } + +inline void +format_char(std::ostream &out, char data, Format &fmt) +{ _format_char(out, data, fmt); } + +inline void +format_char(std::ostream &out, unsigned char data, Format &fmt) +{ _format_char(out, data, fmt); } + +inline void +format_char(std::ostream &out, signed char data, Format &fmt) +{ _format_char(out, data, fmt); } + +inline void +format_char(std::ostream &out, short data, Format &fmt) +{ _format_char(out, (char)data, fmt); } + +inline void +format_char(std::ostream &out, unsigned short data, Format &fmt) +{ _format_char(out, (char)data, fmt); } + +inline void +format_char(std::ostream &out, int data, Format &fmt) +{ _format_char(out, (char)data, fmt); } + +inline void +format_char(std::ostream &out, unsigned int data, Format &fmt) +{ _format_char(out, (char)data, fmt); } + +inline void +format_char(std::ostream &out, long data, Format &fmt) +{ _format_char(out, (char)data, fmt); } + +inline void +format_char(std::ostream &out, unsigned long data, Format &fmt) +{ _format_char(out, (char)data, fmt); } + +inline void +format_char(std::ostream &out, long long data, Format &fmt) +{ _format_char(out, (char)data, fmt); } + +inline void +format_char(std::ostream &out, unsigned long long data, Format &fmt) +{ _format_char(out, (char)data, fmt); } + +// +// integer formats +// +template <typename T> +inline void +format_integer(std::ostream &out, const T &data, Format &fmt) +{ _format_integer(out, data, fmt); } +inline void +format_integer(std::ostream &out, char data, Format &fmt) +{ _format_integer(out, data, fmt); } +inline void +format_integer(std::ostream &out, unsigned char data, Format &fmt) +{ _format_integer(out, data, fmt); } +inline void +format_integer(std::ostream &out, signed char data, Format &fmt) +{ _format_integer(out, data, fmt); } +#if 0 +inline void +format_integer(std::ostream &out, short data, Format &fmt) +{ _format_integer(out, data, fmt); } +inline void +format_integer(std::ostream &out, unsigned short data, Format &fmt) +{ _format_integer(out, data, fmt); } +inline void +format_integer(std::ostream &out, int data, Format &fmt) +{ _format_integer(out, data, fmt); } +inline void +format_integer(std::ostream &out, unsigned int data, Format &fmt) +{ _format_integer(out, data, fmt); } +inline void +format_integer(std::ostream &out, long data, Format &fmt) +{ _format_integer(out, data, fmt); } +inline void +format_integer(std::ostream &out, unsigned long data, Format &fmt) +{ _format_integer(out, data, fmt); } +inline void +format_integer(std::ostream &out, long long data, Format &fmt) +{ _format_integer(out, data, fmt); } +inline void +format_integer(std::ostream &out, unsigned long long data, Format &fmt) +{ _format_integer(out, data, fmt); } +#endif + +// +// floating point formats +// +template <typename T> +inline void +format_float(std::ostream &out, const T &data, Format &fmt) +{ out << "<bad arg type for float format>"; } + +inline void +format_float(std::ostream &out, float data, Format &fmt) +{ _format_float(out, data, fmt); } + +inline void +format_float(std::ostream &out, double data, Format &fmt) +{ _format_float(out, data, fmt); } + +// +// string formats +// +template <typename T> +inline void +format_string(std::ostream &out, const T &data, Format &fmt) +{ _format_string(out, data, fmt); } + +inline void +format_string(std::ostream &out, const std::stringstream &data, Format &fmt) +{ _format_string(out, data.str(), fmt); } + +} // namespace cp + +#endif // __CPRINTF_FORMATS_HH__ diff --git a/src/base/crc.cc b/src/base/crc.cc new file mode 100644 index 000000000..08f039577 --- /dev/null +++ b/src/base/crc.cc @@ -0,0 +1,114 @@ +/* + * Copyright (c) 1988, 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <string> + +#include "sim/host.hh" +#include "base/crc.hh" + +#define ETHER_CRC_POLY_LE 0xedb88320 +#define ETHER_CRC_POLY_BE 0x04c11db6 + +#if 0 +/* + * This is for reference. We have a table-driven version + * of the little-endian crc32 generator, which is faster + * than the double-loop. + */ +uint32_t +crc32le(const uint8_t *buf, size_t len) +{ + uint32_t c, crc, carry; + size_t i, j; + + crc = 0xffffffffU; /* initial value */ + + for (i = 0; i < len; i++) { + c = buf[i]; + for (j = 0; j < 8; j++) { + carry = ((crc & 0x01) ? 1 : 0) ^ (c & 0x01); + crc >>= 1; + c >>= 1; + if (carry) + crc = (crc ^ ETHER_CRC_POLY_LE); + } + } + + return (crc); +} +#else +uint32_t +crc32le(const uint8_t *buf, size_t len) +{ + static const uint32_t crctab[] = { + 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, + 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, + 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, + 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c + }; + uint32_t crc; + int i; + + crc = 0xffffffffU; /* initial value */ + + for (i = 0; i < len; i++) { + crc ^= buf[i]; + crc = (crc >> 4) ^ crctab[crc & 0xf]; + crc = (crc >> 4) ^ crctab[crc & 0xf]; + } + + return (crc); +} +#endif + +uint32_t +crc32be(const uint8_t *buf, size_t len) +{ + uint32_t c, crc, carry; + size_t i, j; + + crc = 0xffffffffU; /* initial value */ + + for (i = 0; i < len; i++) { + c = buf[i]; + for (j = 0; j < 8; j++) { + carry = ((crc & 0x80000000U) ? 1 : 0) ^ (c & 0x01); + crc <<= 1; + c >>= 1; + if (carry) + crc = (crc ^ ETHER_CRC_POLY_BE) | carry; + } + } + + return (crc); +} diff --git a/base/crc.hh b/src/base/crc.hh index 6ede07748..6ede07748 100644 --- a/base/crc.hh +++ b/src/base/crc.hh diff --git a/base/date.cc b/src/base/date.cc index ba7698c29..ba7698c29 100644 --- a/base/date.cc +++ b/src/base/date.cc diff --git a/base/dbl_list.hh b/src/base/dbl_list.hh index 1d06ff576..1d06ff576 100644 --- a/base/dbl_list.hh +++ b/src/base/dbl_list.hh diff --git a/base/endian.hh b/src/base/endian.hh index 499eb50c5..499eb50c5 100644 --- a/base/endian.hh +++ b/src/base/endian.hh diff --git a/base/fast_alloc.cc b/src/base/fast_alloc.cc index 6504e07c2..6504e07c2 100644 --- a/base/fast_alloc.cc +++ b/src/base/fast_alloc.cc diff --git a/base/fast_alloc.hh b/src/base/fast_alloc.hh index 54e35f8e0..54e35f8e0 100644 --- a/base/fast_alloc.hh +++ b/src/base/fast_alloc.hh diff --git a/base/fenv.hh b/src/base/fenv.hh index 3234f5dd3..3234f5dd3 100644 --- a/base/fenv.hh +++ b/src/base/fenv.hh diff --git a/base/fifo_buffer.cc b/src/base/fifo_buffer.cc index 85b306c25..85b306c25 100644 --- a/base/fifo_buffer.cc +++ b/src/base/fifo_buffer.cc diff --git a/base/fifo_buffer.hh b/src/base/fifo_buffer.hh index 03ce057c7..03ce057c7 100644 --- a/base/fifo_buffer.hh +++ b/src/base/fifo_buffer.hh diff --git a/base/hashmap.hh b/src/base/hashmap.hh index 712366829..712366829 100644 --- a/base/hashmap.hh +++ b/src/base/hashmap.hh diff --git a/src/base/hostinfo.cc b/src/base/hostinfo.cc new file mode 100644 index 000000000..d42c96732 --- /dev/null +++ b/src/base/hostinfo.cc @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <ctype.h> +#include <errno.h> +#include <math.h> +#include <unistd.h> + +#include <cstdlib> +#include <cstring> +#include <string> + +#include "base/misc.hh" +#include "sim/host.hh" + +using namespace std; + +string +__get_hostname() +{ + char host[256]; + if (gethostname(host, sizeof host) == -1) + warn("could not get host name!"); + return host; +} + +string & +hostname() +{ + static string hostname = __get_hostname(); + return hostname; +} + +uint64_t +procInfo(char *filename, char *target) +{ + int done = 0; + char line[80]; + char format[80]; + long usage; + + FILE *fp = fopen(filename, "r"); + + while (fp && !feof(fp) && !done) { + if (fgets(line, 80, fp)) { + if (strncmp(line, target, strlen(target)) == 0) { + snprintf(format, sizeof(format), "%s %%ld", target); + sscanf(line, format, &usage); + + fclose(fp); + return usage ; + } + } + } + + if (fp) + fclose(fp); + + return 0; +} diff --git a/base/hostinfo.hh b/src/base/hostinfo.hh index 21a6e5475..21a6e5475 100644 --- a/base/hostinfo.hh +++ b/src/base/hostinfo.hh diff --git a/base/hybrid_pred.cc b/src/base/hybrid_pred.cc index 21cbdb0fd..21cbdb0fd 100644 --- a/base/hybrid_pred.cc +++ b/src/base/hybrid_pred.cc diff --git a/base/hybrid_pred.hh b/src/base/hybrid_pred.hh index ea4a9d04c..ea4a9d04c 100644 --- a/base/hybrid_pred.hh +++ b/src/base/hybrid_pred.hh diff --git a/src/base/inet.cc b/src/base/inet.cc new file mode 100644 index 000000000..f2665bd2b --- /dev/null +++ b/src/base/inet.cc @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sstream> +#include <string> + +#include "base/cprintf.hh" +#include "sim/host.hh" +#include "base/inet.hh" + +using namespace std; +namespace Net { + +EthAddr::EthAddr() +{ + memset(data, 0, ETH_ADDR_LEN); +} + +EthAddr::EthAddr(const uint8_t ea[ETH_ADDR_LEN]) +{ + *data = *ea; +} + +EthAddr::EthAddr(const eth_addr &ea) +{ + *data = *ea.data; +} + +EthAddr::EthAddr(const std::string &addr) +{ + parse(addr); +} + +const EthAddr & +EthAddr::operator=(const eth_addr &ea) +{ + *data = *ea.data; + return *this; +} + +const EthAddr & +EthAddr::operator=(const std::string &addr) +{ + parse(addr); + return *this; +} + +void +EthAddr::parse(const std::string &addr) +{ + // the hack below is to make sure that ETH_ADDR_LEN is 6 otherwise + // the sscanf function won't work. + int bytes[ETH_ADDR_LEN == 6 ? ETH_ADDR_LEN : -1]; + if (sscanf(addr.c_str(), "%x:%x:%x:%x:%x:%x", &bytes[0], &bytes[1], + &bytes[2], &bytes[3], &bytes[4], &bytes[5]) != ETH_ADDR_LEN) { + memset(data, 0xff, ETH_ADDR_LEN); + return; + } + + for (int i = 0; i < ETH_ADDR_LEN; ++i) { + if (bytes[i] & ~0xff) { + memset(data, 0xff, ETH_ADDR_LEN); + return; + } + + data[i] = bytes[i]; + } +} + +string +EthAddr::string() const +{ + stringstream stream; + stream << *this; + return stream.str(); +} + +bool +operator==(const EthAddr &left, const EthAddr &right) +{ + return memcmp(left.bytes(), right.bytes(), ETH_ADDR_LEN); +} + +ostream & +operator<<(ostream &stream, const EthAddr &ea) +{ + const uint8_t *a = ea.addr(); + ccprintf(stream, "%x:%x:%x:%x:%x:%x", a[0], a[1], a[2], a[3], a[4], a[5]); + return stream; +} + +uint16_t +cksum(const IpPtr &ptr) +{ + int sum = ip_cksum_add(ptr->bytes(), ptr->hlen(), 0); + return ip_cksum_carry(sum); +} + +uint16_t +__tu_cksum(const IpPtr &ip) +{ + int tcplen = ip->len() - ip->hlen(); + int sum = ip_cksum_add(ip->payload(), tcplen, 0); + sum = ip_cksum_add(&ip->ip_src, 8, sum); // source and destination + sum += htons(ip->ip_p + tcplen); + return ip_cksum_carry(sum); +} + +uint16_t +cksum(const TcpPtr &tcp) +{ return __tu_cksum(IpPtr(tcp.packet())); } + +uint16_t +cksum(const UdpPtr &udp) +{ return __tu_cksum(IpPtr(udp.packet())); } + +bool +IpHdr::options(vector<const IpOpt *> &vec) const +{ + vec.clear(); + + const uint8_t *data = bytes() + sizeof(struct ip_hdr); + int all = hlen() - sizeof(struct ip_hdr); + while (all > 0) { + const IpOpt *opt = (const IpOpt *)data; + int len = opt->len(); + if (all < len) + return false; + + vec.push_back(opt); + all -= len; + data += len; + } + + return true; +} + +bool +TcpHdr::options(vector<const TcpOpt *> &vec) const +{ + vec.clear(); + + const uint8_t *data = bytes() + sizeof(struct tcp_hdr); + int all = off() - sizeof(struct tcp_hdr); + while (all > 0) { + const TcpOpt *opt = (const TcpOpt *)data; + int len = opt->len(); + if (all < len) + return false; + + vec.push_back(opt); + all -= len; + data += len; + } + + return true; +} + +bool +TcpOpt::sack(vector<SackRange> &vec) const +{ + vec.clear(); + + const uint8_t *data = bytes() + sizeof(struct tcp_hdr); + int all = len() - offsetof(tcp_opt, opt_data.sack); + while (all > 0) { + const uint16_t *sack = (const uint16_t *)data; + int len = sizeof(uint16_t) * 2; + if (all < len) { + vec.clear(); + return false; + } + + vec.push_back(RangeIn(ntohs(sack[0]), ntohs(sack[1]))); + all -= len; + data += len; + } + + return false; +} + +/* namespace Net */ } diff --git a/src/base/inet.hh b/src/base/inet.hh new file mode 100644 index 000000000..e5d0473f9 --- /dev/null +++ b/src/base/inet.hh @@ -0,0 +1,407 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __BASE_INET_HH__ +#define __BASE_INET_HH__ + +#include <iosfwd> +#include <string> +#include <utility> +#include <vector> + +#include "base/range.hh" +#include "dev/etherpkt.hh" +#include "sim/host.hh" + +#include "dnet/os.h" +#include "dnet/eth.h" +#include "dnet/ip.h" +#include "dnet/ip6.h" +#include "dnet/addr.h" +#include "dnet/arp.h" +#include "dnet/icmp.h" +#include "dnet/tcp.h" +#include "dnet/udp.h" +#include "dnet/intf.h" +#include "dnet/route.h" +#include "dnet/fw.h" +#include "dnet/blob.h" +#include "dnet/rand.h" + +namespace Net { + +/* + * Ethernet Stuff + */ +struct EthAddr : protected eth_addr +{ + protected: + void parse(const std::string &addr); + + public: + EthAddr(); + EthAddr(const uint8_t ea[ETH_ADDR_LEN]); + EthAddr(const eth_addr &ea); + EthAddr(const std::string &addr); + const EthAddr &operator=(const eth_addr &ea); + const EthAddr &operator=(const std::string &addr); + + int size() const { return sizeof(eth_addr); } + + const uint8_t *bytes() const { return &data[0]; } + uint8_t *bytes() { return &data[0]; } + + const uint8_t *addr() const { return &data[0]; } + bool unicast() const { return data[0] == 0x00; } + bool multicast() const { return data[0] == 0x01; } + bool broadcast() const { return data[0] == 0xff; } + std::string string() const; + + operator uint64_t() const + { + uint64_t reg = 0; + reg |= ((uint64_t)data[0]) << 40; + reg |= ((uint64_t)data[1]) << 32; + reg |= ((uint64_t)data[2]) << 24; + reg |= ((uint64_t)data[3]) << 16; + reg |= ((uint64_t)data[4]) << 8; + reg |= ((uint64_t)data[5]) << 0; + return reg; + } + +}; + +std::ostream &operator<<(std::ostream &stream, const EthAddr &ea); +bool operator==(const EthAddr &left, const EthAddr &right); + +struct EthHdr : public eth_hdr +{ + uint16_t type() const { return ntohs(eth_type); } + const EthAddr &src() const { return *(EthAddr *)ð_src; } + const EthAddr &dst() const { return *(EthAddr *)ð_dst; } + + int size() const { return sizeof(eth_hdr); } + + const uint8_t *bytes() const { return (const uint8_t *)this; } + const uint8_t *payload() const { return bytes() + size(); } + uint8_t *bytes() { return (uint8_t *)this; } + uint8_t *payload() { return bytes() + size(); } +}; + +class EthPtr +{ + protected: + friend class IpPtr; + EthPacketPtr p; + + public: + EthPtr() {} + EthPtr(const EthPacketPtr &ptr) : p(ptr) { } + + EthHdr *operator->() { return (EthHdr *)p->data; } + EthHdr &operator*() { return *(EthHdr *)p->data; } + operator EthHdr *() { return (EthHdr *)p->data; } + + const EthHdr *operator->() const { return (const EthHdr *)p->data; } + const EthHdr &operator*() const { return *(const EthHdr *)p->data; } + operator const EthHdr *() const { return (const EthHdr *)p->data; } + + const EthPtr &operator=(const EthPacketPtr &ptr) { p = ptr; return *this; } + + const EthPacketPtr packet() const { return p; } + EthPacketPtr packet() { return p; } + bool operator!() const { return !p; } + operator bool() const { return p; } +}; + +/* + * IP Stuff + */ +struct IpOpt; +struct IpHdr : public ip_hdr +{ + uint8_t version() const { return ip_v; } + uint8_t hlen() const { return ip_hl * 4; } + uint8_t tos() const { return ip_tos; } + uint16_t len() const { return ntohs(ip_len); } + uint16_t id() const { return ntohs(ip_id); } + uint16_t frag_flags() const { return ntohs(ip_off) >> 13; } + uint16_t frag_off() const { return ntohs(ip_off) & 0x1fff; } + uint8_t ttl() const { return ip_ttl; } + uint8_t proto() const { return ip_p; } + uint16_t sum() const { return ip_sum; } + uint32_t src() const { return ntohl(ip_src); } + uint32_t dst() const { return ntohl(ip_dst); } + + void sum(uint16_t sum) { ip_sum = sum; } + + bool options(std::vector<const IpOpt *> &vec) const; + + int size() const { return hlen(); } + const uint8_t *bytes() const { return (const uint8_t *)this; } + const uint8_t *payload() const { return bytes() + size(); } + uint8_t *bytes() { return (uint8_t *)this; } + uint8_t *payload() { return bytes() + size(); } +}; + +class IpPtr +{ + protected: + friend class TcpPtr; + friend class UdpPtr; + EthPacketPtr p; + + const IpHdr *h() const + { return (const IpHdr *)(p->data + sizeof(eth_hdr)); } + IpHdr *h() { return (IpHdr *)(p->data + sizeof(eth_hdr)); } + + void set(const EthPacketPtr &ptr) + { + EthHdr *eth = (EthHdr *)ptr->data; + if (eth->type() == ETH_TYPE_IP) + p = ptr; + else + p = 0; + } + + public: + IpPtr() {} + IpPtr(const EthPacketPtr &ptr) { set(ptr); } + IpPtr(const EthPtr &ptr) { set(ptr.p); } + IpPtr(const IpPtr &ptr) : p(ptr.p) { } + + IpHdr *operator->() { return h(); } + IpHdr &operator*() { return *h(); } + operator IpHdr *() { return h(); } + + const IpHdr *operator->() const { return h(); } + const IpHdr &operator*() const { return *h(); } + operator const IpHdr *() const { return h(); } + + const IpPtr &operator=(const EthPacketPtr &ptr) { set(ptr); return *this; } + const IpPtr &operator=(const EthPtr &ptr) { set(ptr.p); return *this; } + const IpPtr &operator=(const IpPtr &ptr) { p = ptr.p; return *this; } + + const EthPacketPtr packet() const { return p; } + EthPacketPtr packet() { return p; } + bool operator!() const { return !p; } + operator bool() const { return p; } + operator bool() { return p; } +}; + +uint16_t cksum(const IpPtr &ptr); + +struct IpOpt : public ip_opt +{ + uint8_t type() const { return opt_type; } + uint8_t typeNumber() const { return IP_OPT_NUMBER(opt_type); } + uint8_t typeClass() const { return IP_OPT_CLASS(opt_type); } + uint8_t typeCopied() const { return IP_OPT_COPIED(opt_type); } + uint8_t len() const { return IP_OPT_TYPEONLY(type()) ? 1 : opt_len; } + + bool isNumber(int num) const { return typeNumber() == IP_OPT_NUMBER(num); } + bool isClass(int cls) const { return typeClass() == IP_OPT_CLASS(cls); } + bool isCopied(int cpy) const { return typeCopied() == IP_OPT_COPIED(cpy); } + + const uint8_t *data() const { return opt_data.data8; } + void sec(ip_opt_data_sec &sec) const; + void lsrr(ip_opt_data_rr &rr) const; + void ssrr(ip_opt_data_rr &rr) const; + void ts(ip_opt_data_ts &ts) const; + uint16_t satid() const { return ntohs(opt_data.satid); } + uint16_t mtup() const { return ntohs(opt_data.mtu); } + uint16_t mtur() const { return ntohs(opt_data.mtu); } + void tr(ip_opt_data_tr &tr) const; + const uint32_t *addext() const { return &opt_data.addext[0]; } + uint16_t rtralt() const { return ntohs(opt_data.rtralt); } + void sdb(std::vector<uint32_t> &vec) const; +}; + +/* + * TCP Stuff + */ +struct TcpOpt; +struct TcpHdr : public tcp_hdr +{ + uint16_t sport() const { return ntohs(th_sport); } + uint16_t dport() const { return ntohs(th_dport); } + uint32_t seq() const { return ntohl(th_seq); } + uint32_t ack() const { return ntohl(th_ack); } + uint8_t off() const { return th_off; } + uint8_t flags() const { return th_flags & 0x3f; } + uint16_t win() const { return ntohs(th_win); } + uint16_t sum() const { return th_sum; } + uint16_t urp() const { return ntohs(th_urp); } + + void sum(uint16_t sum) { th_sum = sum; } + + bool options(std::vector<const TcpOpt *> &vec) const; + + int size() const { return off(); } + const uint8_t *bytes() const { return (const uint8_t *)this; } + const uint8_t *payload() const { return bytes() + size(); } + uint8_t *bytes() { return (uint8_t *)this; } + uint8_t *payload() { return bytes() + size(); } +}; + +class TcpPtr +{ + protected: + EthPacketPtr p; + int off; + + const TcpHdr *h() const { return (const TcpHdr *)(p->data + off); } + TcpHdr *h() { return (TcpHdr *)(p->data + off); } + + void set(const EthPacketPtr &ptr, int offset) { p = ptr; off = offset; } + void set(const IpPtr &ptr) + { + if (ptr->proto() == IP_PROTO_TCP) + set(ptr.p, sizeof(eth_hdr) + ptr->hlen()); + else + set(0, 0); + } + + public: + TcpPtr() {} + TcpPtr(const IpPtr &ptr) { set(ptr); } + TcpPtr(const TcpPtr &ptr) : p(ptr.p), off(ptr.off) {} + + TcpHdr *operator->() { return h(); } + TcpHdr &operator*() { return *h(); } + operator TcpHdr *() { return h(); } + + const TcpHdr *operator->() const { return h(); } + const TcpHdr &operator*() const { return *h(); } + operator const TcpHdr *() const { return h(); } + + const TcpPtr &operator=(const IpPtr &i) { set(i); return *this; } + const TcpPtr &operator=(const TcpPtr &t) { set(t.p, t.off); return *this; } + + const EthPacketPtr packet() const { return p; } + EthPacketPtr packet() { return p; } + bool operator!() const { return !p; } + operator bool() const { return p; } + operator bool() { return p; } +}; + +uint16_t cksum(const TcpPtr &ptr); + +typedef Range<uint16_t> SackRange; + +struct TcpOpt : public tcp_opt +{ + uint8_t type() const { return opt_type; } + uint8_t len() const { return TCP_OPT_TYPEONLY(type()) ? 1 : opt_len; } + + bool isopt(int opt) const { return type() == opt; } + + const uint8_t *data() const { return opt_data.data8; } + + uint16_t mss() const { return ntohs(opt_data.mss); } + uint8_t wscale() const { return opt_data.wscale; } + bool sack(std::vector<SackRange> &vec) const; + uint32_t echo() const { return ntohl(opt_data.echo); } + uint32_t tsval() const { return ntohl(opt_data.timestamp[0]); } + uint32_t tsecr() const { return ntohl(opt_data.timestamp[1]); } + uint32_t cc() const { return ntohl(opt_data.cc); } + uint8_t cksum() const{ return opt_data.cksum; } + const uint8_t *md5() const { return opt_data.md5; } + + int size() const { return len(); } + const uint8_t *bytes() const { return (const uint8_t *)this; } + const uint8_t *payload() const { return bytes() + size(); } + uint8_t *bytes() { return (uint8_t *)this; } + uint8_t *payload() { return bytes() + size(); } +}; + +/* + * UDP Stuff + */ +struct UdpHdr : public udp_hdr +{ + uint16_t sport() const { return ntohs(uh_sport); } + uint16_t dport() const { return ntohs(uh_dport); } + uint16_t len() const { return ntohs(uh_ulen); } + uint16_t sum() const { return uh_sum; } + + void sum(uint16_t sum) { uh_sum = sum; } + + int size() const { return sizeof(udp_hdr); } + const uint8_t *bytes() const { return (const uint8_t *)this; } + const uint8_t *payload() const { return bytes() + size(); } + uint8_t *bytes() { return (uint8_t *)this; } + uint8_t *payload() { return bytes() + size(); } +}; + +class UdpPtr +{ + protected: + EthPacketPtr p; + int off; + + const UdpHdr *h() const { return (const UdpHdr *)(p->data + off); } + UdpHdr *h() { return (UdpHdr *)(p->data + off); } + + void set(const EthPacketPtr &ptr, int offset) { p = ptr; off = offset; } + void set(const IpPtr &ptr) + { + if (ptr->proto() == IP_PROTO_UDP) + set(ptr.p, sizeof(eth_hdr) + ptr->hlen()); + else + set(0, 0); + } + + public: + UdpPtr() {} + UdpPtr(const IpPtr &ptr) { set(ptr); } + UdpPtr(const UdpPtr &ptr) : p(ptr.p), off(ptr.off) {} + + UdpHdr *operator->() { return h(); } + UdpHdr &operator*() { return *h(); } + operator UdpHdr *() { return h(); } + + const UdpHdr *operator->() const { return h(); } + const UdpHdr &operator*() const { return *h(); } + operator const UdpHdr *() const { return h(); } + + const UdpPtr &operator=(const IpPtr &i) { set(i); return *this; } + const UdpPtr &operator=(const UdpPtr &t) { set(t.p, t.off); return *this; } + + const EthPacketPtr packet() const { return p; } + EthPacketPtr packet() { return p; } + bool operator!() const { return !p; } + operator bool() const { return p; } + operator bool() { return p; } +}; + +uint16_t cksum(const UdpPtr &ptr); + +/* namespace Net */ } + +#endif // __BASE_INET_HH__ diff --git a/base/inifile.cc b/src/base/inifile.cc index eb5a1335f..eb5a1335f 100644 --- a/base/inifile.cc +++ b/src/base/inifile.cc diff --git a/base/inifile.hh b/src/base/inifile.hh index 3c6894978..3c6894978 100644 --- a/base/inifile.hh +++ b/src/base/inifile.hh diff --git a/base/intmath.cc b/src/base/intmath.cc index f1c1651ba..f1c1651ba 100644 --- a/base/intmath.cc +++ b/src/base/intmath.cc diff --git a/src/base/intmath.hh b/src/base/intmath.hh new file mode 100644 index 000000000..51baddb91 --- /dev/null +++ b/src/base/intmath.hh @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2001, 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __INTMATH_HH__ +#define __INTMATH_HH__ + +#include <assert.h> + +#include "sim/host.hh" + +// Returns the prime number one less than n. +int prevPrime(int n); + +// Determine if a number is prime +template <class T> +inline bool +isPrime(T n) +{ + T i; + + if (n == 2 || n == 3) + return true; + + // Don't try every odd number to prove if it is a prime. + // Toggle between every 2nd and 4th number. + // (This is because every 6th odd number is divisible by 3.) + for (i = 5; i*i <= n; i += 6) { + if (((n % i) == 0 ) || ((n % (i + 2)) == 0) ) { + return false; + } + } + + return true; +} + +template <class T> +inline T +leastSigBit(T n) +{ + return n & ~(n - 1); +} + +template <class T> +inline bool +isPowerOf2(T n) +{ + return n != 0 && leastSigBit(n) == n; +} + +inline int +floorLog2(unsigned x) +{ + assert(x > 0); + + int y = 0; + + if (x & 0xffff0000) { y += 16; x >>= 16; } + if (x & 0x0000ff00) { y += 8; x >>= 8; } + if (x & 0x000000f0) { y += 4; x >>= 4; } + if (x & 0x0000000c) { y += 2; x >>= 2; } + if (x & 0x00000002) { y += 1; } + + return y; +} + +inline int +floorLog2(unsigned long x) +{ + assert(x > 0); + + int y = 0; + +#if defined(__LP64__) + if (x & ULL(0xffffffff00000000)) { y += 32; x >>= 32; } +#endif + if (x & 0xffff0000) { y += 16; x >>= 16; } + if (x & 0x0000ff00) { y += 8; x >>= 8; } + if (x & 0x000000f0) { y += 4; x >>= 4; } + if (x & 0x0000000c) { y += 2; x >>= 2; } + if (x & 0x00000002) { y += 1; } + + return y; +} + +inline int +floorLog2(unsigned long long x) +{ + assert(x > 0); + + int y = 0; + + if (x & ULL(0xffffffff00000000)) { y += 32; x >>= 32; } + if (x & ULL(0x00000000ffff0000)) { y += 16; x >>= 16; } + if (x & ULL(0x000000000000ff00)) { y += 8; x >>= 8; } + if (x & ULL(0x00000000000000f0)) { y += 4; x >>= 4; } + if (x & ULL(0x000000000000000c)) { y += 2; x >>= 2; } + if (x & ULL(0x0000000000000002)) { y += 1; } + + return y; +} + +inline int +floorLog2(int x) +{ + assert(x > 0); + return floorLog2((unsigned)x); +} + +inline int +floorLog2(long x) +{ + assert(x > 0); + return floorLog2((unsigned long)x); +} + +inline int +floorLog2(long long x) +{ + assert(x > 0); + return floorLog2((unsigned long long)x); +} + +template <class T> +inline int +ceilLog2(T n) +{ + if (n == 1) + return 0; + + return floorLog2(n - (T)1) + 1; +} + +template <class T> +inline T +floorPow2(T n) +{ + return (T)1 << floorLog2(n); +} + +template <class T> +inline T +ceilPow2(T n) +{ + return (T)1 << ceilLog2(n); +} + +template <class T> +inline T +divCeil(T a, T b) +{ + return (a + b - 1) / b; +} + +template <class T> +inline T +roundUp(T val, int align) +{ + T mask = (T)align - 1; + return (val + mask) & ~mask; +} + +template <class T> +inline T +roundDown(T val, int align) +{ + T mask = (T)align - 1; + return val & ~mask; +} + +inline bool +isHex(char c) +{ + return c >= '0' && c <= '9' || + c >= 'A' && c <= 'F' || + c >= 'a' && c <= 'f'; +} + +inline bool +isOct(char c) +{ + return c >= '0' && c <= '7'; +} + +inline bool +isDec(char c) +{ + return c >= '0' && c <= '9'; +} + +inline int +hex2Int(char c) +{ + if (c >= '0' && c <= '9') + return (c - '0'); + + if (c >= 'A' && c <= 'F') + return (c - 'A') + 10; + + if (c >= 'a' && c <= 'f') + return (c - 'a') + 10; + + return 0; +} + +#endif // __INTMATH_HH__ diff --git a/base/kgdb.h b/src/base/kgdb.h index 104244d0b..104244d0b 100644 --- a/base/kgdb.h +++ b/src/base/kgdb.h diff --git a/src/base/loader/aout_object.cc b/src/base/loader/aout_object.cc new file mode 100644 index 000000000..564898ca3 --- /dev/null +++ b/src/base/loader/aout_object.cc @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <string> + +#include "base/loader/aout_object.hh" + +#include "base/loader/symtab.hh" + +#include "base/trace.hh" // for DPRINTF + +#include "base/loader/exec_aout.h" + +using namespace std; + +ObjectFile * +AoutObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data) +{ + if (!N_BADMAG(*(aout_exechdr *)data)) { + // right now this is only used for Alpha PAL code + return new AoutObject(fname, fd, len, data, + ObjectFile::Alpha, ObjectFile::UnknownOpSys); + } + else { + return NULL; + } +} + + +AoutObject::AoutObject(const string &_filename, int _fd, + size_t _len, uint8_t *_data, + Arch _arch, OpSys _opSys) + : ObjectFile(_filename, _fd, _len, _data, _arch, _opSys) +{ + execHdr = (aout_exechdr *)fileData; + + entry = execHdr->entry; + + text.baseAddr = N_TXTADDR(*execHdr); + text.size = execHdr->tsize; + text.fileImage = fileData + N_TXTOFF(*execHdr); + + data.baseAddr = N_DATADDR(*execHdr); + data.size = execHdr->dsize; + data.fileImage = fileData + N_DATOFF(*execHdr); + + bss.baseAddr = N_BSSADDR(*execHdr); + bss.size = execHdr->bsize; + bss.fileImage = NULL; + + DPRINTFR(Loader, "text: 0x%x %d\ndata: 0x%x %d\nbss: 0x%x %d\n", + text.baseAddr, text.size, data.baseAddr, data.size, + bss.baseAddr, bss.size); +} + + +bool +AoutObject::loadGlobalSymbols(SymbolTable *symtab) +{ + // a.out symbols not supported yet + return false; +} + +bool +AoutObject::loadLocalSymbols(SymbolTable *symtab) +{ + // a.out symbols not supported yet + return false; +} diff --git a/src/base/loader/aout_object.hh b/src/base/loader/aout_object.hh new file mode 100644 index 000000000..aeb710427 --- /dev/null +++ b/src/base/loader/aout_object.hh @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __AOUT_OBJECT_HH__ +#define __AOUT_OBJECT_HH__ + +#include "base/loader/object_file.hh" + +// forward decls: avoid including exec_aout.h here +struct aout_exechdr; + +class AoutObject : public ObjectFile +{ + protected: + aout_exechdr *execHdr; + + AoutObject(const std::string &_filename, int _fd, + size_t _len, uint8_t *_data, + Arch _arch, OpSys _opSys); + + public: + virtual ~AoutObject() {} + + virtual bool loadGlobalSymbols(SymbolTable *symtab); + virtual bool loadLocalSymbols(SymbolTable *symtab); + + static ObjectFile *tryFile(const std::string &fname, int fd, + size_t len, uint8_t *data); +}; + +#endif // __AOUT_OBJECT_HH__ diff --git a/src/base/loader/coff_sym.h b/src/base/loader/coff_sym.h new file mode 100644 index 000000000..4c6540395 --- /dev/null +++ b/src/base/loader/coff_sym.h @@ -0,0 +1,519 @@ +/* + * Copyright (c) 2003, 2005-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Steve Reinhardt + */ + +/* + * Taken from binutils-2.14.90.0.5 include/coff/sym.h + */ + +/* Declarations of internal format of MIPS ECOFF symbols. + Originally contributed by MIPS Computer Systems and Third Eye Software. + Changes contributed by Cygnus Support are in the public domain. + + This file is just aggregated with the files that make up the GNU + release; it is not considered part of GAS, GDB, or other GNU + programs. */ + +/* + * |-----------------------------------------------------------| + * | Copyright (c) 1992, 1991, 1990 MIPS Computer Systems, Inc.| + * | MIPS Computer Systems, Inc. grants reproduction and use | + * | rights to all parties, PROVIDED that this comment is | + * | maintained in the copy. | + * |-----------------------------------------------------------| + */ +#ifndef _SYM_H +#define _SYM_H + +/* (C) Copyright 1984 by Third Eye Software, Inc. + * + * Third Eye Software, Inc. grants reproduction and use rights to + * all parties, PROVIDED that this comment is maintained in the copy. + * + * Third Eye makes no claims about the applicability of this + * symbol table to a particular use. + */ + +/* + * This file contains the definition of the Third Eye Symbol Table. + * + * Symbols are assumed to be in 'encounter order' - i.e. the order that + * the things they represent were encountered by the compiler/assembler/loader. + * EXCEPT for globals! These are assumed to be bunched together, + * probably right after the last 'normal' symbol. Globals ARE sorted + * in ascending order. + * + * ----------------------------------------------------------------------- + * A brief word about Third Eye naming/use conventions: + * + * All arrays and index's are 0 based. + * All "ifooMax" values are the highest legal value PLUS ONE. This makes + * them good for allocating arrays, etc. All checks are "ifoo < ifooMax". + * + * "isym" Index into the SYMbol table. + * "ipd" Index into the Procedure Descriptor array. + * "ifd" Index into the File Descriptor array. + * "iss" Index into String Space. + * "cb" Count of Bytes. + * "rgPd" array whose domain is "0..ipdMax-1" and RanGe is PDR. + * "rgFd" array whose domain is "0..ifdMax-1" and RanGe is FDR. + */ + + +/* + * Symbolic Header (HDR) structure. + * As long as all the pointers are set correctly, + * we don't care WHAT order the various sections come out in! + * + * A file produced solely for the use of CDB will probably NOT have + * any instructions or data areas in it, as these are available + * in the original. + */ + +typedef struct ecoff_symhdr { + coff_short magic; /* to verify validity of the table */ + coff_short vstamp; /* version stamp */ + coff_int ilineMax; /* number of line number entries */ + coff_int idnMax; /* max index into dense number table */ + coff_int ipdMax; /* number of procedures */ + coff_int isymMax; /* number of local symbols */ + coff_int ioptMax; /* max index into optimization symbol entries */ + coff_int iauxMax; /* number of auxillary symbol entries */ + coff_int issMax; /* max index into local strings */ + coff_int issExtMax; /* max index into external strings */ + coff_int ifdMax; /* number of file descriptor entries */ + coff_int crfd; /* number of relative file descriptor entries */ + coff_int iextMax; /* max index into external symbols */ + coff_addr cbLine; /* number of bytes for line number entries */ + coff_addr cbLineOffset; /* offset to start of line number entries*/ + coff_addr cbDnOffset; /* offset to start dense number table */ + coff_addr cbPdOffset; /* offset to procedure descriptor table */ + coff_addr cbSymOffset; /* offset to start of local symbols*/ + coff_addr cbOptOffset; /* offset to optimization symbol entries */ + coff_addr cbAuxOffset; /* offset to start of auxillary symbol entries*/ + coff_addr cbSsOffset; /* offset to start of local strings */ + coff_addr cbSsExtOffset; /* offset to start of external strings */ + coff_addr cbFdOffset; /* offset to file descriptor table */ + coff_addr cbRfdOffset; /* offset to relative file descriptor table */ + coff_addr cbExtOffset; /* offset to start of external symbol entries*/ + /* If you add machine dependent fields, add them here */ +} HDRR, *pHDRR; +#define cbHDRR sizeof(HDRR) +#define hdrNil ((pHDRR)0) + +/* + * The FDR and PDR structures speed mapping of address <-> name. + * They are sorted in ascending memory order and are kept in + * memory by CDB at runtime. + */ + +/* + * File Descriptor + * + * There is one of these for EVERY FILE, whether compiled with + * full debugging symbols or not. The name of a file should be + * the path name given to the compiler. This allows the user + * to simply specify the names of the directories where the COMPILES + * were done, and we will be able to find their files. + * A field whose comment starts with "R - " indicates that it will be + * setup at runtime. + */ +typedef struct ecoff_fdr { + coff_addr adr; /* memory address of beginning of file */ + coff_addr cbLineOffset; /* byte offset from header for this file ln's */ + coff_addr cbLine; /* size of lines for this file */ + coff_addr cbSs; /* number of bytes in the ss */ + coff_int rss; /* file name (of source, if known) */ + coff_int issBase; /* file's string space */ + coff_int isymBase; /* beginning of symbols */ + coff_int csym; /* count file's of symbols */ + coff_int ilineBase; /* file's line symbols */ + coff_int cline; /* count of file's line symbols */ + coff_int ioptBase; /* file's optimization entries */ + coff_int copt; /* count of file's optimization entries */ + coff_int ipdFirst; /* start of procedures for this file */ + coff_int cpd; /* count of procedures for this file */ + coff_int iauxBase; /* file's auxiliary entries */ + coff_int caux; /* count of file's auxiliary entries */ + coff_int rfdBase; /* index into the file indirect table */ + coff_int crfd; /* count file indirect entries */ + unsigned lang: 5; /* language for this file */ + unsigned fMerge : 1; /* whether this file can be merged */ + unsigned fReadin : 1; /* true if it was read in (not just created) */ + unsigned fBigendian : 1;/* if set, was compiled on big endian machine */ + /* aux's will be in compile host's sex */ + unsigned glevel : 2; /* level this file was compiled with */ + unsigned reserved : 22; /* reserved for future use */ + coff_uint reserved2; +} FDR, *pFDR; +#define cbFDR sizeof(FDR) +#define fdNil ((pFDR)0) +#define ifdNil -1 +#define ifdTemp 0 +#define ilnNil -1 + + +/* + * Procedure Descriptor + * + * There is one of these for EVERY TEXT LABEL. + * If a procedure is in a file with full symbols, then isym + * will point to the PROC symbols, else it will point to the + * global symbol for the label. + */ + +typedef struct pdr { + coff_addr adr; /* memory address of start of procedure */ + coff_addr cbLineOffset; /* byte offset for this procedure from the fd base */ + coff_int isym; /* start of local symbol entries */ + coff_int iline; /* start of line number entries*/ + coff_uint regmask; /* save register mask */ + coff_int regoffset; /* save register offset */ + coff_int iopt; /* start of optimization symbol entries*/ + coff_uint fregmask; /* save floating point register mask */ + coff_int fregoffset; /* save floating point register offset */ + coff_int frameoffset; /* frame size */ + coff_int lnLow; /* lowest line in the procedure */ + coff_int lnHigh; /* highest line in the procedure */ + /* These fields are new for 64 bit ECOFF. */ + unsigned gp_prologue : 8; /* byte size of GP prologue */ + unsigned gp_used : 1; /* true if the procedure uses GP */ + unsigned reg_frame : 1; /* true if register frame procedure */ + unsigned prof : 1; /* true if compiled with -pg */ + unsigned reserved : 13; /* reserved: must be zero */ + unsigned localoff : 8; /* offset of local variables from vfp */ + coff_short framereg; /* frame pointer register */ + coff_short pcreg; /* offset or reg of return pc */ +} PDR, *pPDR; +#define cbPDR sizeof(PDR) +#define pdNil ((pPDR) 0) +#define ipdNil -1 + +/* + * The structure of the runtime procedure descriptor created by the loader + * for use by the static exception system. + */ +/* + * If 0'd out because exception_info chokes Visual C++ and because there + * don't seem to be any references to this structure elsewhere in gdb. + */ +#if 0 +typedef struct runtime_pdr { + coff_addr adr; /* memory address of start of procedure */ + coff_uint regmask; /* save register mask */ + coff_int regoffset; /* save register offset */ + coff_uint fregmask; /* save floating point register mask */ + coff_int fregoffset; /* save floating point register offset */ + coff_int frameoffset; /* frame size */ + coff_ushort framereg; /* frame pointer register */ + coff_ushort pcreg; /* offset or reg of return pc */ + coff_int irpss; /* index into the runtime string table */ + coff_uint reserved; + struct exception_info *exception_info;/* pointer to exception array */ +} RPDR, *pRPDR; +#define cbRPDR sizeof(RPDR) +#define rpdNil ((pRPDR) 0) +#endif + +/* + * Line Numbers + * + * Line Numbers are segregated from the normal symbols because they + * are [1] smaller , [2] are of no interest to your + * average loader, and [3] are never needed in the middle of normal + * scanning and therefore slow things down. + * + * By definition, the first LINER for any given procedure will have + * the first line of a procedure and represent the first address. + */ + +typedef coff_int LINER, *pLINER; +#define lineNil ((pLINER)0) +#define cbLINER sizeof(LINER) +#define ilineNil -1 + + + +/* + * The Symbol Structure (GFW, to those who Know!) + */ + +typedef struct ecoff_sym { + coff_long value; /* value of symbol */ + coff_int iss; /* index into String Space of name */ + unsigned st : 6; /* symbol type */ + unsigned sc : 5; /* storage class - text, data, etc */ + unsigned reserved : 1; /* reserved */ + unsigned index : 20; /* index into sym/aux table */ +} SYMR, *pSYMR; +#define symNil ((pSYMR)0) +#define cbSYMR sizeof(SYMR) +#define isymNil -1 +#define indexNil 0xfffff +#define issNil -1 +#define issNull 0 + + +/* The following converts a memory resident string to an iss. + * This hack is recognized in SbFIss, in sym.c of the debugger. + */ +#define IssFSb(sb) (0x80000000 | ((coff_ulong)(sb))) + +/* E X T E R N A L S Y M B O L R E C O R D + * + * Same as the SYMR except it contains file context to determine where + * the index is. + */ +typedef struct ecoff_extsym { + SYMR asym; /* symbol for the external */ + unsigned jmptbl:1; /* symbol is a jump table entry for shlibs */ + unsigned cobol_main:1; /* symbol is a cobol main procedure */ + unsigned weakext:1; /* symbol is weak external */ + unsigned reserved:29; /* reserved for future use */ + coff_int ifd; /* where the iss and index fields point into */ +} EXTR, *pEXTR; +#define extNil ((pEXTR)0) +#define cbEXTR sizeof(EXTR) + + +/* A U X I L L A R Y T Y P E I N F O R M A T I O N */ + +/* + * Type Information Record + */ +typedef struct { + unsigned fBitfield : 1; /* set if bit width is specified */ + unsigned continued : 1; /* indicates additional TQ info in next AUX */ + unsigned bt : 6; /* basic type */ + unsigned tq4 : 4; + unsigned tq5 : 4; + /* ---- 16 bit boundary ---- */ + unsigned tq0 : 4; + unsigned tq1 : 4; /* 6 type qualifiers - tqPtr, etc. */ + unsigned tq2 : 4; + unsigned tq3 : 4; +} TIR, *pTIR; +#define cbTIR sizeof(TIR) +#define tiNil ((pTIR)0) +#define itqMax 6 + +/* + * Relative symbol record + * + * If the rfd field is 4095, the index field indexes into the global symbol + * table. + */ + +typedef struct { + unsigned rfd : 12; /* index into the file indirect table */ + unsigned index : 20; /* index int sym/aux/iss tables */ +} RNDXR, *pRNDXR; +#define cbRNDXR sizeof(RNDXR) +#define rndxNil ((pRNDXR)0) + +/* dense numbers or sometimes called block numbers are stored in this type, + * a rfd of 0xffffffff is an index into the global table. + */ +typedef struct { + coff_uint rfd; /* index into the file table */ + coff_uint index; /* index int sym/aux/iss tables */ +} DNR, *pDNR; +#define cbDNR sizeof(DNR) +#define dnNil ((pDNR)0) + + + +/* + * Auxillary information occurs only if needed. + * It ALWAYS occurs in this order when present. + + isymMac used by stProc only + TIR type info + TIR additional TQ info (if first TIR was not enough) + rndx if (bt == btStruct,btUnion,btEnum,btSet,btRange, + btTypedef): + rsym.index == iaux for btSet or btRange + else rsym.index == isym + dimLow btRange, btSet + dimMac btRange, btSet + rndx0 As many as there are tq arrays + dimLow0 + dimHigh0 + ... + rndxMax-1 + dimLowMax-1 + dimHighMax-1 + width in bits if (bit field), width in bits. + */ +#define cAuxMax (6 + (idimMax*3)) + +/* a union of all possible info in the AUX universe */ +typedef union { + TIR ti; /* type information record */ + RNDXR rndx; /* relative index into symbol table */ + coff_int dnLow; /* low dimension */ + coff_int dnHigh; /* high dimension */ + coff_int isym; /* symbol table index (end of proc) */ + coff_int iss; /* index into string space (not used) */ + coff_int width; /* width for non-default sized struc fields */ + coff_int count; /* count of ranges for variant arm */ +} AUXU, *pAUXU; +#define cbAUXU sizeof(AUXU) +#define auxNil ((pAUXU)0) +#define iauxNil -1 + + +/* + * Optimization symbols + * + * Optimization symbols contain some overlap information with the normal + * symbol table. In particular, the proc information + * is somewhat redundant but necessary to easily find the other information + * present. + * + * All of the offsets are relative to the beginning of the last otProc + */ + +typedef struct { + unsigned ot: 8; /* optimization type */ + unsigned value: 24; /* address where we are moving it to */ + RNDXR rndx; /* points to a symbol or opt entry */ + coff_ulong offset; /* relative offset this occured */ +} OPTR, *pOPTR; +#define optNil ((pOPTR) 0) +#define cbOPTR sizeof(OPTR) +#define ioptNil -1 + +/* + * File Indirect + * + * When a symbol is referenced across files the following procedure is used: + * 1) use the file index to get the File indirect entry. + * 2) use the file indirect entry to get the File descriptor. + * 3) add the sym index to the base of that file's sym table + * + */ + +typedef coff_long RFDT, *pRFDT; +#define cbRFDT sizeof(RFDT) +#define rfdNil -1 + +/* + * The file indirect table in the mips loader is known as an array of FITs. + * This is done to keep the code in the loader readable in the area where + * these tables are merged. Note this is only a name change. + */ +typedef coff_int FIT, *pFIT; +#define cbFIT sizeof(FIT) +#define ifiNil -1 +#define fiNil ((pFIT) 0) + +#ifdef _LANGUAGE_PASCAL +#define ifdNil -1 +#define ilnNil -1 +#define ipdNil -1 +#define ilineNil -1 +#define isymNil -1 +#define indexNil 16#fffff +#define issNil -1 +#define issNull 0 +#define itqMax 6 +#define iauxNil -1 +#define ioptNil -1 +#define rfdNil -1 +#define ifiNil -1 +#endif /* _LANGUAGE_PASCAL */ + + +/* Dense numbers + * + * Rather than use file index, symbol index pairs to represent symbols + * and globals, we use dense number so that they can be easily embeded + * in intermediate code and the programs that process them can + * use direct access tabls instead of hash table (which would be + * necesary otherwise because of the sparse name space caused by + * file index, symbol index pairs. Dense number are represented + * by RNDXRs. + */ + +/* + * The following table defines the meaning of each SYM field as + * a function of the "st". (scD/B == scData OR scBss) + * + * Note: the value "isymMac" is used by symbols that have the concept + * of enclosing a block of related information. This value is the + * isym of the first symbol AFTER the end associated with the primary + * symbol. For example if a procedure was at isym==90 and had an + * isymMac==155, the associated end would be at isym==154, and the + * symbol at 155 would probably (although not necessarily) be the + * symbol for the next procedure. This allows rapid skipping over + * internal information of various sorts. "stEnd"s ALWAYS have the + * isym of the primary symbol that started the block. + * + +ST SC VALUE INDEX +-------- ------ -------- ------ +stFile scText address isymMac +stLabel scText address --- +stGlobal scD/B address iaux +stStatic scD/B address iaux +stParam scAbs offset iaux +stLocal scAbs offset iaux +stProc scText address iaux (isymMac is first AUX) +stStaticProc scText address iaux (isymMac is first AUX) + +stMember scNil ordinal --- (if member of enum) + (mipsread thinks the case below has a bit, not byte, offset.) +stMember scNil byte offset iaux (if member of struct/union) +stMember scBits bit offset iaux (bit field spec) + +stBlock scText address isymMac (text block) + (the code seems to think that rather than scNil, we see scInfo for + the two cases below.) +stBlock scNil cb isymMac (struct/union member define) +stBlock scNil cMembers isymMac (enum member define) + + (New types added by SGI to simplify things:) +stStruct scInfo cb isymMac (struct type define) +stUnion scInfo cb isymMac (union type define) +stEnum scInfo cMembers isymMac (enum type define) + +stEnd scText address isymStart +stEnd scNil ------- isymStart (struct/union/enum) + +stTypedef scNil ------- iaux +stRegReloc sc??? value old register number +stForward sc??? new address isym to original symbol + +stConstant scInfo value --- (scalar) +stConstant scInfo iss --- (complex, e.g. string) + + * + */ +#endif diff --git a/src/base/loader/coff_symconst.h b/src/base/loader/coff_symconst.h new file mode 100644 index 000000000..f383c19e6 --- /dev/null +++ b/src/base/loader/coff_symconst.h @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2003, 2005-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Steve Reinhardt + */ + +/* + * Taken from binutils-2.14.90.0.5 include/coff/symconst.h + */ + +/* Declarations of constants for internal format of MIPS ECOFF symbols. + Originally contributed by MIPS Computer Systems and Third Eye Software. + Changes contributed by Cygnus Support are in the public domain. + + This file is just aggregated with the files that make up the GNU + release; it is not considered part of GAS, GDB, or other GNU + programs. */ + +/* + * |-----------------------------------------------------------| + * | Copyright (c) 1992, 1991, 1990 MIPS Computer Systems, Inc.| + * | MIPS Computer Systems, Inc. grants reproduction and use | + * | rights to all parties, PROVIDED that this comment is | + * | maintained in the copy. | + * |-----------------------------------------------------------| + */ + +/* (C) Copyright 1984 by Third Eye Software, Inc. + * + * Third Eye Software, Inc. grants reproduction and use rights to + * all parties, PROVIDED that this comment is maintained in the copy. + * + * Third Eye makes no claims about the applicability of this + * symbol table to a particular use. + */ + +/* glevels for field in FDR */ +#define GLEVEL_0 2 +#define GLEVEL_1 1 +#define GLEVEL_2 0 /* for upward compat reasons. */ +#define GLEVEL_3 3 + +/* magic number fo symheader */ +#define magicSym 0x7009 +/* The Alpha uses this value instead, for some reason. */ +#define magicSym2 0x1992 + +/* Language codes */ +#define langC 0 +#define langPascal 1 +#define langFortran 2 +#define langAssembler 3 /* one Assembley inst might map to many mach */ +#define langMachine 4 +#define langNil 5 +#define langAda 6 +#define langPl1 7 +#define langCobol 8 +#define langStdc 9 /* FIXME: Collides with SGI langCplusplus */ +#define langCplusplus 9 /* FIXME: Collides with langStdc */ +#define langCplusplusV2 10 /* SGI addition */ +#define langMax 11 /* maximun allowed 32 -- 5 bits */ + +/* The following are value definitions for the fields in the SYMR */ + +/* + * Storage Classes + */ + +#define scNil 0 +#define scText 1 /* text symbol */ +#define scData 2 /* initialized data symbol */ +#define scBss 3 /* un-initialized data symbol */ +#define scRegister 4 /* value of symbol is register number */ +#define scAbs 5 /* value of symbol is absolute */ +#define scUndefined 6 /* who knows? */ +#define scCdbLocal 7 /* variable's value is IN se->va.?? */ +#define scBits 8 /* this is a bit field */ +#define scCdbSystem 9 /* variable's value is IN CDB's address space */ +#define scDbx 9 /* overlap dbx internal use */ +#define scRegImage 10 /* register value saved on stack */ +#define scInfo 11 /* symbol contains debugger information */ +#define scUserStruct 12 /* address in struct user for current process */ +#define scSData 13 /* load time only small data */ +#define scSBss 14 /* load time only small common */ +#define scRData 15 /* load time only read only data */ +#define scVar 16 /* Var parameter (fortran,pascal) */ +#define scCommon 17 /* common variable */ +#define scSCommon 18 /* small common */ +#define scVarRegister 19 /* Var parameter in a register */ +#define scVariant 20 /* Variant record */ +#define scSUndefined 21 /* small undefined(external) data */ +#define scInit 22 /* .init section symbol */ +#define scBasedVar 23 /* Fortran or PL/1 ptr based var */ +#define scXData 24 /* exception handling data */ +#define scPData 25 /* Procedure section */ +#define scFini 26 /* .fini section */ +#define scRConst 27 /* .rconst section */ +#define scMax 32 + + +/* + * Symbol Types + */ + +#define stNil 0 /* Nuthin' special */ +#define stGlobal 1 /* external symbol */ +#define stStatic 2 /* static */ +#define stParam 3 /* procedure argument */ +#define stLocal 4 /* local variable */ +#define stLabel 5 /* label */ +#define stProc 6 /* " " Procedure */ +#define stBlock 7 /* beginnning of block */ +#define stEnd 8 /* end (of anything) */ +#define stMember 9 /* member (of anything - struct/union/enum */ +#define stTypedef 10 /* type definition */ +#define stFile 11 /* file name */ +#define stRegReloc 12 /* register relocation */ +#define stForward 13 /* forwarding address */ +#define stStaticProc 14 /* load time only static procs */ +#define stConstant 15 /* const */ +#define stStaParam 16 /* Fortran static parameters */ + /* These new symbol types have been recently added to SGI machines. */ +#define stStruct 26 /* Beginning of block defining a struct type */ +#define stUnion 27 /* Beginning of block defining a union type */ +#define stEnum 28 /* Beginning of block defining an enum type */ +#define stIndirect 34 /* Indirect type specification */ + /* Pseudo-symbols - internal to debugger */ +#define stStr 60 /* string */ +#define stNumber 61 /* pure number (ie. 4 NOR 2+2) */ +#define stExpr 62 /* 2+2 vs. 4 */ +#define stType 63 /* post-coersion SER */ +#define stMax 64 + +/* definitions for fields in TIR */ + +/* type qualifiers for ti.tq0 -> ti.(itqMax-1) */ +#define tqNil 0 /* bt is what you see */ +#define tqPtr 1 /* pointer */ +#define tqProc 2 /* procedure */ +#define tqArray 3 /* duh */ +#define tqFar 4 /* longer addressing - 8086/8 land */ +#define tqVol 5 /* volatile */ +#define tqConst 6 /* const */ +#define tqMax 8 + +/* basic types as seen in ti.bt */ +#define btNil 0 /* undefined (also, enum members) */ +#define btAdr 1 /* address - integer same size as pointer */ +#define btChar 2 /* character */ +#define btUChar 3 /* unsigned character */ +#define btShort 4 /* short */ +#define btUShort 5 /* unsigned short */ +#define btInt 6 /* int */ +#define btUInt 7 /* unsigned int */ +#define btLong 8 /* long */ +#define btULong 9 /* unsigned long */ +#define btFloat 10 /* float (real) */ +#define btDouble 11 /* Double (real) */ +#define btStruct 12 /* Structure (Record) */ +#define btUnion 13 /* Union (variant) */ +#define btEnum 14 /* Enumerated */ +#define btTypedef 15 /* defined via a typedef, isymRef points */ +#define btRange 16 /* subrange of int */ +#define btSet 17 /* pascal sets */ +#define btComplex 18 /* fortran complex */ +#define btDComplex 19 /* fortran double complex */ +#define btIndirect 20 /* forward or unnamed typedef */ +#define btFixedDec 21 /* Fixed Decimal */ +#define btFloatDec 22 /* Float Decimal */ +#define btString 23 /* Varying Length Character String */ +#define btBit 24 /* Aligned Bit String */ +#define btPicture 25 /* Picture */ +#define btVoid 26 /* void */ +#define btLongLong 27 /* long long */ +#define btULongLong 28 /* unsigned long long */ +#define btMax 64 diff --git a/src/base/loader/ecoff_object.cc b/src/base/loader/ecoff_object.cc new file mode 100644 index 000000000..80917ee9c --- /dev/null +++ b/src/base/loader/ecoff_object.cc @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <string> + +#include "base/loader/ecoff_object.hh" +#include "base/misc.hh" +#include "base/loader/symtab.hh" + +#include "base/trace.hh" // for DPRINTF + +#include "base/loader/exec_ecoff.h" +#include "base/loader/coff_sym.h" +#include "base/loader/coff_symconst.h" + +using namespace std; + +ObjectFile * +EcoffObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data) +{ + if (((ecoff_filehdr *)data)->f_magic == ECOFF_MAGIC_ALPHA) { + // it's Alpha ECOFF + return new EcoffObject(fname, fd, len, data, + ObjectFile::Alpha, ObjectFile::Tru64); + } + else { + return NULL; + } +} + + +EcoffObject::EcoffObject(const string &_filename, int _fd, + size_t _len, uint8_t *_data, + Arch _arch, OpSys _opSys) + : ObjectFile(_filename, _fd, _len, _data, _arch, _opSys) +{ + execHdr = (ecoff_exechdr *)fileData; + fileHdr = &(execHdr->f); + aoutHdr = &(execHdr->a); + + entry = aoutHdr->entry; + + text.baseAddr = aoutHdr->text_start; + text.size = aoutHdr->tsize; + text.fileImage = fileData + ECOFF_TXTOFF(execHdr); + + data.baseAddr = aoutHdr->data_start; + data.size = aoutHdr->dsize; + data.fileImage = fileData + ECOFF_DATOFF(execHdr); + + bss.baseAddr = aoutHdr->bss_start; + bss.size = aoutHdr->bsize; + bss.fileImage = NULL; + + DPRINTFR(Loader, "text: 0x%x %d\ndata: 0x%x %d\nbss: 0x%x %d\n", + text.baseAddr, text.size, data.baseAddr, data.size, + bss.baseAddr, bss.size); +} + + +bool +EcoffObject::loadGlobalSymbols(SymbolTable *symtab) +{ + if (!symtab) + return false; + + if (fileHdr->f_magic != ECOFF_MAGIC_ALPHA) { + warn("loadGlobalSymbols: wrong magic on %s\n", filename); + return false; + } + + ecoff_symhdr *syms = (ecoff_symhdr *)(fileData + fileHdr->f_symptr); + if (syms->magic != magicSym2) { + warn("loadGlobalSymbols: bad symbol header magic on %s\n", filename); + return false; + } + + ecoff_extsym *ext_syms = (ecoff_extsym *)(fileData + syms->cbExtOffset); + + char *ext_strings = (char *)(fileData + syms->cbSsExtOffset); + for (int i = 0; i < syms->iextMax; i++) { + ecoff_sym *entry = &(ext_syms[i].asym); + if (entry->iss != -1) + symtab->insert(entry->value, ext_strings + entry->iss); + } + + return true; +} + +bool +EcoffObject::loadLocalSymbols(SymbolTable *symtab) +{ + if (!symtab) + return false; + + if (fileHdr->f_magic != ECOFF_MAGIC_ALPHA) { + warn("loadGlobalSymbols: wrong magic on %s\n", filename); + return false; + } + + ecoff_symhdr *syms = (ecoff_symhdr *)(fileData + fileHdr->f_symptr); + if (syms->magic != magicSym2) { + warn("loadGlobalSymbols: bad symbol header magic on %s\n", filename); + return false; + } + + ecoff_sym *local_syms = (ecoff_sym *)(fileData + syms->cbSymOffset); + char *local_strings = (char *)(fileData + syms->cbSsOffset); + ecoff_fdr *fdesc = (ecoff_fdr *)(fileData + syms->cbFdOffset); + + for (int i = 0; i < syms->ifdMax; i++) { + ecoff_sym *entry = (ecoff_sym *)(local_syms + fdesc[i].isymBase); + char *strings = (char *)(local_strings + fdesc[i].issBase); + for (int j = 0; j < fdesc[i].csym; j++) { + if (entry[j].st == stGlobal || entry[j].st == stProc) + if (entry[j].iss != -1) + symtab->insert(entry[j].value, strings + entry[j].iss); + } + } + + for (int i = 0; i < syms->isymMax; i++) { + ecoff_sym *entry = &(local_syms[i]); + if (entry->st == stProc) + symtab->insert(entry->value, local_strings + entry->iss); + } + + return true; +} diff --git a/src/base/loader/ecoff_object.hh b/src/base/loader/ecoff_object.hh new file mode 100644 index 000000000..603c70bec --- /dev/null +++ b/src/base/loader/ecoff_object.hh @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ECOFF_OBJECT_HH__ +#define __ECOFF_OBJECT_HH__ + +#include "base/loader/object_file.hh" + +// forward decls: avoid including exec_ecoff.h here +struct ecoff_exechdr; +struct ecoff_filehdr; +struct ecoff_aouthdr; + +class EcoffObject : public ObjectFile +{ + protected: + ecoff_exechdr *execHdr; + ecoff_filehdr *fileHdr; + ecoff_aouthdr *aoutHdr; + + EcoffObject(const std::string &_filename, int _fd, + size_t _len, uint8_t *_data, + Arch _arch, OpSys _opSys); + + public: + virtual ~EcoffObject() {} + + virtual bool loadGlobalSymbols(SymbolTable *symtab); + virtual bool loadLocalSymbols(SymbolTable *symtab); + + static ObjectFile *tryFile(const std::string &fname, int fd, + size_t len, uint8_t *data); +}; + +#endif // __ECOFF_OBJECT_HH__ diff --git a/src/base/loader/elf_object.cc b/src/base/loader/elf_object.cc new file mode 100644 index 000000000..79601e9d1 --- /dev/null +++ b/src/base/loader/elf_object.cc @@ -0,0 +1,309 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <string> + +// Because of the -Wundef flag we have to do this +#define __LIBELF_INTERNAL__ 0 +#define __LIBELF_NEED_LINK_H 0 +#define __LIBELF_SYMBOL_VERSIONS 0 + +#include "gelf.h" + +#include "base/loader/elf_object.hh" +#include "base/misc.hh" + +#include "base/loader/symtab.hh" + +#include "base/trace.hh" // for DPRINTF + +#include "sim/byteswap.hh" + + +using namespace std; + +ObjectFile * +ElfObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data) +{ + Elf *elf; + GElf_Ehdr ehdr; + Arch arch = UnknownArch; + OpSys opSys = UnknownOpSys; + + // check that header matches library version + if (elf_version(EV_CURRENT) == EV_NONE) + panic("wrong elf version number!"); + + // get a pointer to elf structure + elf = elf_memory((char*)data,len); + // will only fail if fd is invalid + assert(elf != NULL); + + // Check that we actually have a elf file + if (gelf_getehdr(elf, &ehdr) ==0) { + DPRINTFR(Loader, "Not ELF\n"); + elf_end(elf); + return NULL; + } else { + //Detect the architecture + //Since we don't know how to check for alpha right now, we'll + //just assume if it wasn't something else and it's 64 bit, that's + //what it must be. + if (ehdr.e_machine == EM_SPARC64 || + ehdr.e_machine == EM_SPARC || + ehdr.e_machine == EM_SPARCV9) { + arch = ObjectFile::SPARC; + } else if (ehdr.e_machine == EM_MIPS + && ehdr.e_ident[EI_CLASS] == ELFCLASS32) { + arch = ObjectFile::Mips; + } else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) { + arch = ObjectFile::Alpha; + } else { + warn("Unknown architecture: %d\n", ehdr.e_machine); + arch = ObjectFile::UnknownArch; + } + + //Detect the operating system + switch (ehdr.e_ident[EI_OSABI]) + { + + case ELFOSABI_LINUX: + opSys = ObjectFile::Linux; + break; + case ELFOSABI_SOLARIS: + opSys = ObjectFile::Solaris; + break; + case ELFOSABI_TRU64: + opSys = ObjectFile::Tru64; + break; + default: + opSys = ObjectFile::UnknownOpSys; + } + + //take a look at the .note.ABI section + //It can let us know what's what. + if (opSys == ObjectFile::UnknownOpSys) { + Elf_Scn *section; + GElf_Shdr shdr; + Elf_Data *data; + uint32_t osAbi;; + int secIdx = 1; + + // Get the first section + section = elf_getscn(elf, secIdx); + + // While there are no more sections + while (section != NULL && opSys == ObjectFile::UnknownOpSys) { + gelf_getshdr(section, &shdr); + if (shdr.sh_type == SHT_NOTE && !strcmp(".note.ABI-tag", + elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name))) { + // we have found a ABI note section + // Check the 5th 32bit word for OS 0 == linux, 1 == hurd, + // 2 == solaris, 3 == freebsd + data = elf_rawdata(section, NULL); + assert(data->d_buf); + if(ehdr.e_ident[EI_DATA] == ELFDATA2LSB) + osAbi = htole(((uint32_t*)data->d_buf)[4]); + else + osAbi = htobe(((uint32_t*)data->d_buf)[4]); + + switch(osAbi) { + case 0: + opSys = ObjectFile::Linux; + break; + case 2: + opSys = ObjectFile::Solaris; + break; + } + } // if section found + if (!strcmp(".SUNW_version", elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name))) + opSys = ObjectFile::Solaris; + if (!strcmp(".stab.index", elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name))) + opSys = ObjectFile::Solaris; + + section = elf_getscn(elf, ++secIdx); + } // while sections + } + + elf_end(elf); + return new ElfObject(fname, fd, len, data, arch, opSys); + } +} + + +ElfObject::ElfObject(const string &_filename, int _fd, + size_t _len, uint8_t *_data, + Arch _arch, OpSys _opSys) + : ObjectFile(_filename, _fd, _len, _data, _arch, _opSys) + +{ + Elf *elf; + GElf_Ehdr ehdr; + + // check that header matches library version + if (elf_version(EV_CURRENT) == EV_NONE) + panic("wrong elf version number!"); + + // get a pointer to elf structure + elf = elf_memory((char*)fileData,len); + // will only fail if fd is invalid + assert(elf != NULL); + + // Check that we actually have a elf file + if (gelf_getehdr(elf, &ehdr) ==0) { + panic("Not ELF, shouldn't be here"); + } + + entry = ehdr.e_entry; + + + // initialize segment sizes to 0 in case they're not present + text.size = data.size = bss.size = 0; + + for (int i = 0; i < ehdr.e_phnum; ++i) { + GElf_Phdr phdr; + if (gelf_getphdr(elf, i, &phdr) == 0) { + panic("gelf_getphdr failed for section %d", i); + } + + // for now we don't care about non-loadable segments + if (!(phdr.p_type & PT_LOAD)) + continue; + + // the headers don't explicitly distinguish text from data, + // but empirically the text segment comes first. + if (text.size == 0) { // haven't seen text segment yet + text.baseAddr = phdr.p_vaddr; + text.size = phdr.p_filesz; + text.fileImage = fileData + phdr.p_offset; + // if there's any padding at the end that's not in the + // file, call it the bss. This happens in the "text" + // segment if there's only one loadable segment (as for + // kernel images). + bss.size = phdr.p_memsz - phdr.p_filesz; + bss.baseAddr = phdr.p_vaddr + phdr.p_filesz; + bss.fileImage = NULL; + } else if (data.size == 0) { // have text, this must be data + data.baseAddr = phdr.p_vaddr; + data.size = phdr.p_filesz; + data.fileImage = fileData + phdr.p_offset; + // if there's any padding at the end that's not in the + // file, call it the bss. Warn if this happens for both + // the text & data segments (should only have one bss). + if (phdr.p_memsz - phdr.p_filesz > 0 && bss.size != 0) { + warn("Two implied bss segments in file!\n"); + } + bss.size = phdr.p_memsz - phdr.p_filesz; + bss.baseAddr = phdr.p_vaddr + phdr.p_filesz; + bss.fileImage = NULL; + } else { + warn("More than two loadable segments in ELF object."); + warn("Ignoring segment @ 0x%x length 0x%x.", + phdr.p_vaddr, phdr.p_filesz); + } + } + + // should have found at least one loadable segment + assert(text.size != 0); + + DPRINTFR(Loader, "text: 0x%x %d\ndata: 0x%x %d\nbss: 0x%x %d\n", + text.baseAddr, text.size, data.baseAddr, data.size, + bss.baseAddr, bss.size); + + elf_end(elf); + + // We will actually read the sections when we need to load them +} + + +bool +ElfObject::loadSomeSymbols(SymbolTable *symtab, int binding) +{ + Elf *elf; + int sec_idx = 1; // there is a 0 but it is nothing, go figure + Elf_Scn *section; + GElf_Shdr shdr; + Elf_Data *data; + int count, ii; + bool found = false; + GElf_Sym sym; + + if (!symtab) + return false; + + // check that header matches library version + if (elf_version(EV_CURRENT) == EV_NONE) + panic("wrong elf version number!"); + + // get a pointer to elf structure + elf = elf_memory((char*)fileData,len); + + assert(elf != NULL); + + // Get the first section + section = elf_getscn(elf, sec_idx); + + // While there are no more sections + while (section != NULL) { + gelf_getshdr(section, &shdr); + + if (shdr.sh_type == SHT_SYMTAB) { + found = true; + data = elf_getdata(section, NULL); + count = shdr.sh_size / shdr.sh_entsize; + DPRINTF(Loader, "Found Symbol Table, %d symbols present\n", count); + + // loop through all the symbols, only loading global ones + for (ii = 0; ii < count; ++ii) { + gelf_getsym(data, ii, &sym); + if (GELF_ST_BIND(sym.st_info) == binding) { + symtab->insert(sym.st_value, + elf_strptr(elf, shdr.sh_link, sym.st_name)); + } + } + } + ++sec_idx; + section = elf_getscn(elf, sec_idx); + } + + elf_end(elf); + + return found; +} + +bool +ElfObject::loadGlobalSymbols(SymbolTable *symtab) +{ + return loadSomeSymbols(symtab, STB_GLOBAL); +} + +bool +ElfObject::loadLocalSymbols(SymbolTable *symtab) +{ + return loadSomeSymbols(symtab, STB_LOCAL); +} diff --git a/src/base/loader/elf_object.hh b/src/base/loader/elf_object.hh new file mode 100644 index 000000000..72c265edd --- /dev/null +++ b/src/base/loader/elf_object.hh @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ELF_OBJECT_HH__ +#define __ELF_OBJECT_HH__ + +#include "base/loader/object_file.hh" + +class ElfObject : public ObjectFile +{ + protected: + + /// Helper functions for loadGlobalSymbols() and loadLocalSymbols(). + bool loadSomeSymbols(SymbolTable *symtab, int binding); + + ElfObject(const std::string &_filename, int _fd, + size_t _len, uint8_t *_data, + Arch _arch, OpSys _opSys); + + public: + virtual ~ElfObject() {} + + virtual bool loadGlobalSymbols(SymbolTable *symtab); + virtual bool loadLocalSymbols(SymbolTable *symtab); + + static ObjectFile *tryFile(const std::string &fname, int fd, + size_t len, uint8_t *data); +}; + +#endif // __ELF_OBJECT_HH__ diff --git a/base/loader/exec_aout.h b/src/base/loader/exec_aout.h index eed44baee..eed44baee 100644 --- a/base/loader/exec_aout.h +++ b/src/base/loader/exec_aout.h diff --git a/base/loader/exec_ecoff.h b/src/base/loader/exec_ecoff.h index 555589806..555589806 100644 --- a/base/loader/exec_ecoff.h +++ b/src/base/loader/exec_ecoff.h diff --git a/src/base/loader/object_file.cc b/src/base/loader/object_file.cc new file mode 100644 index 000000000..c6dfced1d --- /dev/null +++ b/src/base/loader/object_file.cc @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2002-2004 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <list> +#include <string> + +#include <sys/types.h> +#include <sys/mman.h> +#include <fcntl.h> +#include <stdio.h> +#include <unistd.h> + +#include "base/cprintf.hh" +#include "base/loader/object_file.hh" +#include "base/loader/symtab.hh" + +#include "base/loader/ecoff_object.hh" +#include "base/loader/aout_object.hh" +#include "base/loader/elf_object.hh" + +#include "mem/translating_port.hh" + +using namespace std; + +ObjectFile::ObjectFile(const string &_filename, int _fd, + size_t _len, uint8_t *_data, + Arch _arch, OpSys _opSys) + : filename(_filename), descriptor(_fd), fileData(_data), len(_len), + arch(_arch), opSys(_opSys) +{ +} + + +ObjectFile::~ObjectFile() +{ + close(); +} + + +bool +ObjectFile::loadSection(Section *sec, Port *memPort, Addr addrMask) +{ + if (sec->size != 0) { + Addr addr = sec->baseAddr & addrMask; + if (sec->fileImage) { + memPort->writeBlob(addr, sec->fileImage, sec->size); + } + else { + // no image: must be bss + memPort->memsetBlob(addr, 0, sec->size); + } + } + return true; +} + + +bool +ObjectFile::loadSections(Port *memPort, Addr addrMask) +{ + return (loadSection(&text, memPort, addrMask) + && loadSection(&data, memPort, addrMask) + && loadSection(&bss, memPort, addrMask)); +} + + +void +ObjectFile::close() +{ + if (descriptor >= 0) { + ::close(descriptor); + descriptor = -1; + } + + if (fileData) { + ::munmap(fileData, len); + fileData = NULL; + } +} + + +ObjectFile * +createObjectFile(const string &fname) +{ + // open the file + int fd = open(fname.c_str(), O_RDONLY); + if (fd < 0) { + return NULL; + } + + // find the length of the file by seeking to the end + size_t len = (size_t)lseek(fd, 0, SEEK_END); + + // mmap the whole shebang + uint8_t *fileData = + (uint8_t *)mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0); + if (fileData == MAP_FAILED) { + close(fd); + return NULL; + } + + ObjectFile *fileObj = NULL; + + // figure out what we have here + if ((fileObj = EcoffObject::tryFile(fname, fd, len, fileData)) != NULL) { + return fileObj; + } + + if ((fileObj = AoutObject::tryFile(fname, fd, len, fileData)) != NULL) { + return fileObj; + } + + if ((fileObj = ElfObject::tryFile(fname, fd, len, fileData)) != NULL) { + return fileObj; + } + + // don't know what it is + close(fd); + munmap(fileData, len); + return NULL; +} diff --git a/src/base/loader/object_file.hh b/src/base/loader/object_file.hh new file mode 100644 index 000000000..b43989cb5 --- /dev/null +++ b/src/base/loader/object_file.hh @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2002-2004 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __OBJECT_FILE_HH__ +#define __OBJECT_FILE_HH__ + +#include <limits> +#include <string> + +#include "sim/host.hh" // for Addr + +class Port; +class SymbolTable; + +class ObjectFile +{ + public: + + enum Arch { + UnknownArch, + Alpha, + SPARC, + Mips + }; + + enum OpSys { + UnknownOpSys, + Tru64, + Linux, + Solaris + }; + + protected: + const std::string filename; + int descriptor; + uint8_t *fileData; + size_t len; + + Arch arch; + OpSys opSys; + + ObjectFile(const std::string &_filename, int _fd, + size_t _len, uint8_t *_data, + Arch _arch, OpSys _opSys); + + public: + virtual ~ObjectFile(); + + void close(); + + virtual bool loadSections(Port *memPort, Addr addrMask = + std::numeric_limits<Addr>::max()); + virtual bool loadGlobalSymbols(SymbolTable *symtab) = 0; + virtual bool loadLocalSymbols(SymbolTable *symtab) = 0; + + Arch getArch() const { return arch; } + OpSys getOpSys() const { return opSys; } + + protected: + + struct Section { + Addr baseAddr; + uint8_t *fileImage; + size_t size; + }; + + Addr entry; + Addr globalPtr; + + Section text; + Section data; + Section bss; + + bool loadSection(Section *sec, Port *memPort, Addr addrMask); + void setGlobalPointer(Addr global_ptr) { globalPtr = global_ptr; } + + public: + Addr entryPoint() const { return entry; } + + Addr globalPointer() const { return globalPtr; } + + Addr textBase() const { return text.baseAddr; } + Addr dataBase() const { return data.baseAddr; } + Addr bssBase() const { return bss.baseAddr; } + + size_t textSize() const { return text.size; } + size_t dataSize() const { return data.size; } + size_t bssSize() const { return bss.size; } +}; + +ObjectFile *createObjectFile(const std::string &fname); + + +#endif // __OBJECT_FILE_HH__ diff --git a/base/loader/symtab.cc b/src/base/loader/symtab.cc index 25f54f9bf..25f54f9bf 100644 --- a/base/loader/symtab.cc +++ b/src/base/loader/symtab.cc diff --git a/src/base/loader/symtab.hh b/src/base/loader/symtab.hh new file mode 100644 index 000000000..931fd2cc2 --- /dev/null +++ b/src/base/loader/symtab.hh @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __SYMTAB_HH__ +#define __SYMTAB_HH__ + +#include <iosfwd> +#include <map> + +#include "sim/host.hh" // for Addr + +class Checkpoint; +class SymbolTable +{ + public: + typedef std::map<Addr, std::string> ATable; + typedef std::map<std::string, Addr> STable; + + private: + ATable addrTable; + STable symbolTable; + + private: + bool + upperBound(Addr addr, ATable::const_iterator &iter) const + { + // find first key *larger* than desired address + iter = addrTable.upper_bound(addr); + + // if very first key is larger, we're out of luck + if (iter == addrTable.begin()) + return false; + + return true; + } + + public: + SymbolTable() {} + SymbolTable(const std::string &file) { load(file); } + ~SymbolTable() {} + + void clear(); + bool insert(Addr address, std::string symbol); + bool load(const std::string &file); + + const ATable &getAddrTable() const { return addrTable; } + const STable &getSymbolTable() const { return symbolTable; } + + public: + void serialize(const std::string &base, std::ostream &os); + void unserialize(const std::string &base, Checkpoint *cp, + const std::string §ion); + + public: + bool + findSymbol(Addr address, std::string &symbol) const + { + ATable::const_iterator i = addrTable.find(address); + if (i == addrTable.end()) + return false; + + symbol = (*i).second; + return true; + } + + bool + findAddress(const std::string &symbol, Addr &address) const + { + STable::const_iterator i = symbolTable.find(symbol); + if (i == symbolTable.end()) + return false; + + address = (*i).second; + return true; + } + + /// Find the nearest symbol equal to or less than the supplied + /// address (e.g., the label for the enclosing function). + /// @param address The address to look up. + /// @param symbol Return reference for symbol string. + /// @param sym_address Return reference for symbol address. + /// @param next_sym_address Address of following symbol (for + /// determining valid range of symbol). + /// @retval True if a symbol was found. + bool + findNearestSymbol(Addr addr, std::string &symbol, Addr &symaddr, + Addr &nextaddr) const + { + ATable::const_iterator i; + if (!upperBound(addr, i)) + return false; + + nextaddr = i->first; + --i; + symaddr = i->first; + symbol = i->second; + return true; + } + + /// Overload for findNearestSymbol() for callers who don't care + /// about next_sym_address. + bool + findNearestSymbol(Addr addr, std::string &symbol, Addr &symaddr) const + { + ATable::const_iterator i; + if (!upperBound(addr, i)) + return false; + + --i; + symaddr = i->first; + symbol = i->second; + return true; + } + + + bool + findNearestAddr(Addr addr, Addr &symaddr, Addr &nextaddr) const + { + ATable::const_iterator i; + if (!upperBound(addr, i)) + return false; + + nextaddr = i->first; + --i; + symaddr = i->first; + return true; + } + + bool + findNearestAddr(Addr addr, Addr &symaddr) const + { + ATable::const_iterator i; + if (!upperBound(addr, i)) + return false; + + --i; + symaddr = i->first; + return true; + } +}; + +/// Global unified debugging symbol table (for target). Conceptually +/// there should be one of these per System object for full system, +/// and per Process object for non-full-system, but so far one big +/// global one has worked well enough. +extern SymbolTable *debugSymbolTable; + +#endif // __SYMTAB_HH__ diff --git a/base/match.cc b/src/base/match.cc index 4f1f49b57..4f1f49b57 100644 --- a/base/match.cc +++ b/src/base/match.cc diff --git a/base/match.hh b/src/base/match.hh index 1b0a083a7..1b0a083a7 100644 --- a/base/match.hh +++ b/src/base/match.hh diff --git a/base/misc.cc b/src/base/misc.cc index f3c86827b..f3c86827b 100644 --- a/base/misc.cc +++ b/src/base/misc.cc diff --git a/base/misc.hh b/src/base/misc.hh index 9255c69c6..9255c69c6 100644 --- a/base/misc.hh +++ b/src/base/misc.hh diff --git a/base/mod_num.hh b/src/base/mod_num.hh index fabbb56a9..fabbb56a9 100644 --- a/base/mod_num.hh +++ b/src/base/mod_num.hh diff --git a/base/mysql.cc b/src/base/mysql.cc index c8d6e933a..c8d6e933a 100644 --- a/base/mysql.cc +++ b/src/base/mysql.cc diff --git a/base/mysql.hh b/src/base/mysql.hh index ae28a9dfb..ae28a9dfb 100644 --- a/base/mysql.hh +++ b/src/base/mysql.hh diff --git a/base/output.cc b/src/base/output.cc index 2b1733f21..2b1733f21 100644 --- a/base/output.cc +++ b/src/base/output.cc diff --git a/base/output.hh b/src/base/output.hh index 3bbe73e3b..3bbe73e3b 100644 --- a/base/output.hh +++ b/src/base/output.hh diff --git a/base/pollevent.cc b/src/base/pollevent.cc index 99044fc09..99044fc09 100644 --- a/base/pollevent.cc +++ b/src/base/pollevent.cc diff --git a/base/pollevent.hh b/src/base/pollevent.hh index d39931797..d39931797 100644 --- a/base/pollevent.hh +++ b/src/base/pollevent.hh diff --git a/base/predictor.hh b/src/base/predictor.hh index 37aa29989..37aa29989 100644 --- a/base/predictor.hh +++ b/src/base/predictor.hh diff --git a/base/random.cc b/src/base/random.cc index 4aac14101..4aac14101 100644 --- a/base/random.cc +++ b/src/base/random.cc diff --git a/base/random.hh b/src/base/random.hh index def7a4bce..def7a4bce 100644 --- a/base/random.hh +++ b/src/base/random.hh diff --git a/base/range.cc b/src/base/range.cc index a4e50fc4f..a4e50fc4f 100644 --- a/base/range.cc +++ b/src/base/range.cc diff --git a/base/range.hh b/src/base/range.hh index 4e3e0fd6e..4e3e0fd6e 100644 --- a/base/range.hh +++ b/src/base/range.hh diff --git a/base/refcnt.hh b/src/base/refcnt.hh index de589f7c5..de589f7c5 100644 --- a/base/refcnt.hh +++ b/src/base/refcnt.hh diff --git a/src/base/remote_gdb.cc b/src/base/remote_gdb.cc new file mode 100644 index 000000000..41d0c1471 --- /dev/null +++ b/src/base/remote_gdb.cc @@ -0,0 +1,1175 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratories. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)kgdb_stub.c 8.4 (Berkeley) 1/12/94 + */ + +/*- + * Copyright (c) 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * $NetBSD: kgdb_stub.c,v 1.8 2001/07/07 22:58:00 wdk Exp $ + * + * Taken from NetBSD + * + * "Stub" to allow remote cpu to debug over a serial line using gdb. + */ + +#include <sys/signal.h> + +#include <string> +#include <unistd.h> + +#include "arch/vtophys.hh" +#include "base/intmath.hh" +#include "base/kgdb.h" +#include "base/remote_gdb.hh" +#include "base/socket.hh" +#include "base/trace.hh" +#include "config/full_system.hh" +#include "cpu/exec_context.hh" +#include "cpu/static_inst.hh" +#include "mem/physical.hh" +#include "mem/port.hh" +#include "sim/system.hh" + +using namespace std; +using namespace TheISA; + +#ifndef NDEBUG +vector<RemoteGDB *> debuggers; +int current_debugger = -1; + +void +debugger() +{ + if (current_debugger >= 0 && current_debugger < debuggers.size()) { + RemoteGDB *gdb = debuggers[current_debugger]; + if (!gdb->isattached()) + gdb->listener->accept(); + if (gdb->isattached()) + gdb->trap(ALPHA_KENTRY_IF); + } +} +#endif + +/////////////////////////////////////////////////////////// +// +// +// + +GDBListener::Event::Event(GDBListener *l, int fd, int e) + : PollEvent(fd, e), listener(l) +{} + +void +GDBListener::Event::process(int revent) +{ + listener->accept(); +} + +GDBListener::GDBListener(RemoteGDB *g, int p) + : event(NULL), gdb(g), port(p) +{ + assert(!gdb->listener); + gdb->listener = this; +} + +GDBListener::~GDBListener() +{ + if (event) + delete event; +} + +string +GDBListener::name() +{ + return gdb->name() + ".listener"; +} + +void +GDBListener::listen() +{ + while (!listener.listen(port, true)) { + DPRINTF(GDBMisc, "Can't bind port %d\n", port); + port++; + } + + event = new Event(this, listener.getfd(), POLLIN); + pollQueue.schedule(event); + +#ifndef NDEBUG + gdb->number = debuggers.size(); + debuggers.push_back(gdb); +#endif + +#ifndef NDEBUG + ccprintf(cerr, "%d: %s: listening for remote gdb #%d on port %d\n", + curTick, name(), gdb->number, port); +#else + ccprintf(cerr, "%d: %s: listening for remote gdb on port %d\n", + curTick, name(), port); +#endif +} + +void +GDBListener::accept() +{ + if (!listener.islistening()) + panic("GDBListener::accept(): cannot accept if we're not listening!"); + + int sfd = listener.accept(true); + + if (sfd != -1) { + if (gdb->isattached()) + close(sfd); + else + gdb->attach(sfd); + } +} + +/////////////////////////////////////////////////////////// +// +// +// +int digit2i(char); +char i2digit(int); +void mem2hex(void *, const void *, int); +const char *hex2mem(void *, const char *, int); +Addr hex2i(const char **); + +RemoteGDB::Event::Event(RemoteGDB *g, int fd, int e) + : PollEvent(fd, e), gdb(g) +{} + +void +RemoteGDB::Event::process(int revent) +{ + if (revent & POLLIN) + gdb->trap(ALPHA_KENTRY_IF); + else if (revent & POLLNVAL) + gdb->detach(); +} + +RemoteGDB::RemoteGDB(System *_system, ExecContext *c) + : event(NULL), listener(NULL), number(-1), fd(-1), + active(false), attached(false), + system(_system), pmem(_system->physmem), context(c) +{ + memset(gdbregs, 0, sizeof(gdbregs)); +} + +RemoteGDB::~RemoteGDB() +{ + if (event) + delete event; +} + +string +RemoteGDB::name() +{ + return system->name() + ".remote_gdb"; +} + +bool +RemoteGDB::isattached() +{ return attached; } + +void +RemoteGDB::attach(int f) +{ + fd = f; + + event = new Event(this, fd, POLLIN); + pollQueue.schedule(event); + + attached = true; + DPRINTFN("remote gdb attached\n"); +} + +void +RemoteGDB::detach() +{ + attached = false; + close(fd); + fd = -1; + + pollQueue.remove(event); + DPRINTFN("remote gdb detached\n"); +} + +const char * +gdb_command(char cmd) +{ + switch (cmd) { + case KGDB_SIGNAL: return "KGDB_SIGNAL"; + case KGDB_SET_BAUD: return "KGDB_SET_BAUD"; + case KGDB_SET_BREAK: return "KGDB_SET_BREAK"; + case KGDB_CONT: return "KGDB_CONT"; + case KGDB_ASYNC_CONT: return "KGDB_ASYNC_CONT"; + case KGDB_DEBUG: return "KGDB_DEBUG"; + case KGDB_DETACH: return "KGDB_DETACH"; + case KGDB_REG_R: return "KGDB_REG_R"; + case KGDB_REG_W: return "KGDB_REG_W"; + case KGDB_SET_THREAD: return "KGDB_SET_THREAD"; + case KGDB_CYCLE_STEP: return "KGDB_CYCLE_STEP"; + case KGDB_SIG_CYCLE_STEP: return "KGDB_SIG_CYCLE_STEP"; + case KGDB_KILL: return "KGDB_KILL"; + case KGDB_MEM_W: return "KGDB_MEM_W"; + case KGDB_MEM_R: return "KGDB_MEM_R"; + case KGDB_SET_REG: return "KGDB_SET_REG"; + case KGDB_READ_REG: return "KGDB_READ_REG"; + case KGDB_QUERY_VAR: return "KGDB_QUERY_VAR"; + case KGDB_SET_VAR: return "KGDB_SET_VAR"; + case KGDB_RESET: return "KGDB_RESET"; + case KGDB_STEP: return "KGDB_STEP"; + case KGDB_ASYNC_STEP: return "KGDB_ASYNC_STEP"; + case KGDB_THREAD_ALIVE: return "KGDB_THREAD_ALIVE"; + case KGDB_TARGET_EXIT: return "KGDB_TARGET_EXIT"; + case KGDB_BINARY_DLOAD: return "KGDB_BINARY_DLOAD"; + case KGDB_CLR_HW_BKPT: return "KGDB_CLR_HW_BKPT"; + case KGDB_SET_HW_BKPT: return "KGDB_SET_HW_BKPT"; + case KGDB_START: return "KGDB_START"; + case KGDB_END: return "KGDB_END"; + case KGDB_GOODP: return "KGDB_GOODP"; + case KGDB_BADP: return "KGDB_BADP"; + default: return "KGDB_UNKNOWN"; + } +} + +/////////////////////////////////////////////////////////// +// RemoteGDB::acc +// +// Determine if the mapping at va..(va+len) is valid. +// +bool +RemoteGDB::acc(Addr va, size_t len) +{ + Addr last_va; + + va = TheISA::TruncPage(va); + last_va = TheISA::RoundPage(va + len); + + do { + if (TheISA::IsK0Seg(va)) { + if (va < (TheISA::K0SegBase + pmem->size())) { + DPRINTF(GDBAcc, "acc: Mapping is valid K0SEG <= " + "%#x < K0SEG + size\n", va); + return true; + } else { + DPRINTF(GDBAcc, "acc: Mapping invalid %#x > K0SEG + size\n", + va); + return false; + } + } + + /** + * This code says that all accesses to palcode (instruction and data) + * are valid since there isn't a va->pa mapping because palcode is + * accessed physically. At some point this should probably be cleaned up + * but there is no easy way to do it. + */ + + if (AlphaISA::PcPAL(va) || va < 0x10000) + return true; + + Addr ptbr = context->readMiscReg(AlphaISA::IPR_PALtemp20); + TheISA::PageTableEntry pte = TheISA::kernel_pte_lookup(context->getPhysPort(), ptbr, va); + if (!pte.valid()) { + DPRINTF(GDBAcc, "acc: %#x pte is invalid\n", va); + return false; + } + va += TheISA::PageBytes; + } while (va < last_va); + + DPRINTF(GDBAcc, "acc: %#x mapping is valid\n", va); + return true; +} + +/////////////////////////////////////////////////////////// +// RemoteGDB::signal +// +// Translate a trap number into a Unix-compatible signal number. +// (GDB only understands Unix signal numbers.) +// +int +RemoteGDB::signal(int type) +{ + switch (type) { + case ALPHA_KENTRY_INT: + return (SIGTRAP); + + case ALPHA_KENTRY_UNA: + return (SIGBUS); + + case ALPHA_KENTRY_ARITH: + return (SIGFPE); + + case ALPHA_KENTRY_IF: + return (SIGILL); + + case ALPHA_KENTRY_MM: + return (SIGSEGV); + + default: + panic("unknown signal type"); + return 0; + } +} + +/////////////////////////////////////////////////////////// +// RemoteGDB::getregs +// +// Translate the kernel debugger register format into +// the GDB register format. +void +RemoteGDB::getregs() +{ + memset(gdbregs, 0, sizeof(gdbregs)); + + gdbregs[KGDB_REG_PC] = context->readPC(); + + // @todo: Currently this is very Alpha specific. + if (AlphaISA::PcPAL(gdbregs[KGDB_REG_PC])) { + for (int i = 0; i < TheISA::NumIntArchRegs; ++i) { + gdbregs[i] = context->readIntReg(AlphaISA::reg_redir[i]); + } + } else { + for (int i = 0; i < TheISA::NumIntArchRegs; ++i) { + gdbregs[i] = context->readIntReg(i); + } + } + +#ifdef KGDB_FP_REGS + for (int i = 0; i < TheISA::NumFloatArchRegs; ++i) { + gdbregs[i + KGDB_REG_F0] = context->readFloatRegBits(i); + } +#endif +} + +/////////////////////////////////////////////////////////// +// RemoteGDB::setregs +// +// Translate the GDB register format into the kernel +// debugger register format. +// +void +RemoteGDB::setregs() +{ + // @todo: Currently this is very Alpha specific. + if (AlphaISA::PcPAL(gdbregs[KGDB_REG_PC])) { + for (int i = 0; i < TheISA::NumIntArchRegs; ++i) { + context->setIntReg(AlphaISA::reg_redir[i], gdbregs[i]); + } + } else { + for (int i = 0; i < TheISA::NumIntArchRegs; ++i) { + context->setIntReg(i, gdbregs[i]); + } + } + +#ifdef KGDB_FP_REGS + for (int i = 0; i < TheISA::NumFloatArchRegs; ++i) { + context->setFloatRegBits(i, gdbregs[i + KGDB_REG_F0]); + } +#endif + context->setPC(gdbregs[KGDB_REG_PC]); +} + +void +RemoteGDB::setTempBreakpoint(TempBreakpoint &bkpt, Addr addr) +{ + DPRINTF(GDBMisc, "setTempBreakpoint: addr=%#x\n", addr); + + bkpt.address = addr; + insertHardBreak(addr, 4); +} + +void +RemoteGDB::clearTempBreakpoint(TempBreakpoint &bkpt) +{ + DPRINTF(GDBMisc, "setTempBreakpoint: addr=%#x\n", + bkpt.address); + + + removeHardBreak(bkpt.address, 4); + bkpt.address = 0; +} + +void +RemoteGDB::clearSingleStep() +{ + DPRINTF(GDBMisc, "clearSingleStep bt_addr=%#x nt_addr=%#x\n", + takenBkpt.address, notTakenBkpt.address); + + if (takenBkpt.address != 0) + clearTempBreakpoint(takenBkpt); + + if (notTakenBkpt.address != 0) + clearTempBreakpoint(notTakenBkpt); +} + +void +RemoteGDB::setSingleStep() +{ + Addr pc = context->readPC(); + Addr npc, bpc; + bool set_bt = false; + + npc = pc + sizeof(MachInst); + + // User was stopped at pc, e.g. the instruction at pc was not + // executed. + MachInst inst = read<MachInst>(pc); + StaticInstPtr si(inst); + if (si->hasBranchTarget(pc, context, bpc)) { + // Don't bother setting a breakpoint on the taken branch if it + // is the same as the next pc + if (bpc != npc) + set_bt = true; + } + + DPRINTF(GDBMisc, "setSingleStep bt_addr=%#x nt_addr=%#x\n", + takenBkpt.address, notTakenBkpt.address); + + setTempBreakpoint(notTakenBkpt, npc); + + if (set_bt) + setTempBreakpoint(takenBkpt, bpc); +} + +///////////////////////// +// +// + +uint8_t +RemoteGDB::getbyte() +{ + uint8_t b; + ::read(fd, &b, 1); + return b; +} + +void +RemoteGDB::putbyte(uint8_t b) +{ + ::write(fd, &b, 1); +} + +// Send a packet to gdb +void +RemoteGDB::send(const char *bp) +{ + const char *p; + uint8_t csum, c; + + DPRINTF(GDBSend, "send: %s\n", bp); + + do { + p = bp; + putbyte(KGDB_START); + for (csum = 0; (c = *p); p++) { + putbyte(c); + csum += c; + } + putbyte(KGDB_END); + putbyte(i2digit(csum >> 4)); + putbyte(i2digit(csum)); + } while ((c = getbyte() & 0x7f) == KGDB_BADP); +} + +// Receive a packet from gdb +int +RemoteGDB::recv(char *bp, int maxlen) +{ + char *p; + int c, csum; + int len; + + do { + p = bp; + csum = len = 0; + while ((c = getbyte()) != KGDB_START) + ; + + while ((c = getbyte()) != KGDB_END && len < maxlen) { + c &= 0x7f; + csum += c; + *p++ = c; + len++; + } + csum &= 0xff; + *p = '\0'; + + if (len >= maxlen) { + putbyte(KGDB_BADP); + continue; + } + + csum -= digit2i(getbyte()) * 16; + csum -= digit2i(getbyte()); + + if (csum == 0) { + putbyte(KGDB_GOODP); + // Sequence present? + if (bp[2] == ':') { + putbyte(bp[0]); + putbyte(bp[1]); + len -= 3; + bcopy(bp + 3, bp, len); + } + break; + } + putbyte(KGDB_BADP); + } while (1); + + DPRINTF(GDBRecv, "recv: %s: %s\n", gdb_command(*bp), bp); + + return (len); +} + +// Read bytes from kernel address space for debugger. +bool +RemoteGDB::read(Addr vaddr, size_t size, char *data) +{ + static Addr lastaddr = 0; + static size_t lastsize = 0; + + if (vaddr < 10) { + DPRINTF(GDBRead, "read: reading memory location zero!\n"); + vaddr = lastaddr + lastsize; + } + + DPRINTF(GDBRead, "read: addr=%#x, size=%d", vaddr, size); + + context->getVirtPort(context)->readBlob(vaddr, (uint8_t*)data, size); + +#if TRACING_ON + if (DTRACE(GDBRead)) { + if (DTRACE(GDBExtra)) { + char buf[1024]; + mem2hex(buf, data, size); + DPRINTFNR(": %s\n", buf); + } else + DPRINTFNR("\n"); + } +#endif + + return true; +} + +// Write bytes to kernel address space for debugger. +bool +RemoteGDB::write(Addr vaddr, size_t size, const char *data) +{ + static Addr lastaddr = 0; + static size_t lastsize = 0; + + if (vaddr < 10) { + DPRINTF(GDBWrite, "write: writing memory location zero!\n"); + vaddr = lastaddr + lastsize; + } + + if (DTRACE(GDBWrite)) { + DPRINTFN("write: addr=%#x, size=%d", vaddr, size); + if (DTRACE(GDBExtra)) { + char buf[1024]; + mem2hex(buf, data, size); + DPRINTFNR(": %s\n", buf); + } else + DPRINTFNR("\n"); + } + + context->getVirtPort(context)->writeBlob(vaddr, (uint8_t*)data, size); + +#ifdef IMB + alpha_pal_imb(); +#endif + + return true; +} + + +PCEventQueue *RemoteGDB::getPcEventQueue() +{ + return &system->pcEventQueue; +} + + +RemoteGDB::HardBreakpoint::HardBreakpoint(RemoteGDB *_gdb, Addr pc) + : PCEvent(_gdb->getPcEventQueue(), "HardBreakpoint Event", pc), + gdb(_gdb), refcount(0) +{ + DPRINTF(GDBMisc, "creating hardware breakpoint at %#x\n", evpc); +} + +void +RemoteGDB::HardBreakpoint::process(ExecContext *xc) +{ + DPRINTF(GDBMisc, "handling hardware breakpoint at %#x\n", pc()); + + if (xc == gdb->context) + gdb->trap(ALPHA_KENTRY_INT); +} + +bool +RemoteGDB::insertSoftBreak(Addr addr, size_t len) +{ + if (len != sizeof(MachInst)) + panic("invalid length\n"); + + return insertHardBreak(addr, len); +} + +bool +RemoteGDB::removeSoftBreak(Addr addr, size_t len) +{ + if (len != sizeof(MachInst)) + panic("invalid length\n"); + + return removeHardBreak(addr, len); +} + +bool +RemoteGDB::insertHardBreak(Addr addr, size_t len) +{ + if (len != sizeof(MachInst)) + panic("invalid length\n"); + + DPRINTF(GDBMisc, "inserting hardware breakpoint at %#x\n", addr); + + HardBreakpoint *&bkpt = hardBreakMap[addr]; + if (bkpt == 0) + bkpt = new HardBreakpoint(this, addr); + + bkpt->refcount++; + + return true; +} + +bool +RemoteGDB::removeHardBreak(Addr addr, size_t len) +{ + if (len != sizeof(MachInst)) + panic("invalid length\n"); + + DPRINTF(GDBMisc, "removing hardware breakpoint at %#x\n", addr); + + break_iter_t i = hardBreakMap.find(addr); + if (i == hardBreakMap.end()) + return false; + + HardBreakpoint *hbp = (*i).second; + if (--hbp->refcount == 0) { + delete hbp; + hardBreakMap.erase(i); + } + + return true; +} + +const char * +break_type(char c) +{ + switch(c) { + case '0': return "software breakpoint"; + case '1': return "hardware breakpoint"; + case '2': return "write watchpoint"; + case '3': return "read watchpoint"; + case '4': return "access watchpoint"; + default: return "unknown breakpoint/watchpoint"; + } +} + +// This function does all command processing for interfacing to a +// remote gdb. Note that the error codes are ignored by gdb at +// present, but might eventually become meaningful. (XXX) It might +// makes sense to use POSIX errno values, because that is what the +// gdb/remote.c functions want to return. +bool +RemoteGDB::trap(int type) +{ + uint64_t val; + size_t datalen, len; + char data[KGDB_BUFLEN + 1]; + char buffer[sizeof(gdbregs) * 2 + 256]; + char temp[KGDB_BUFLEN]; + const char *p; + char command, subcmd; + string var; + bool ret; + + if (!attached) + return false; + + DPRINTF(GDBMisc, "trap: PC=%#x NPC=%#x\n", + context->readPC(), context->readNextPC()); + + clearSingleStep(); + + /* + * The first entry to this function is normally through + * a breakpoint trap in kgdb_connect(), in which case we + * must advance past the breakpoint because gdb will not. + * + * On the first entry here, we expect that gdb is not yet + * listening to us, so just enter the interaction loop. + * After the debugger is "active" (connected) it will be + * waiting for a "signaled" message from us. + */ + if (!active) + active = true; + else + // Tell remote host that an exception has occurred. + snprintf((char *)buffer, sizeof(buffer), "S%02x", signal(type)); + send(buffer); + + // Stick frame regs into our reg cache. + getregs(); + + for (;;) { + datalen = recv(data, sizeof(data)); + data[sizeof(data) - 1] = 0; // Sentinel + command = data[0]; + subcmd = 0; + p = data + 1; + switch (command) { + + case KGDB_SIGNAL: + // if this command came from a running gdb, answer it -- + // the other guy has no way of knowing if we're in or out + // of this loop when he issues a "remote-signal". + snprintf((char *)buffer, sizeof(buffer), "S%02x", signal(type)); + send(buffer); + continue; + + case KGDB_REG_R: + if (2 * sizeof(gdbregs) > sizeof(buffer)) + panic("buffer too small"); + + mem2hex(buffer, gdbregs, sizeof(gdbregs)); + send(buffer); + continue; + + case KGDB_REG_W: + p = hex2mem(gdbregs, p, sizeof(gdbregs)); + if (p == NULL || *p != '\0') + send("E01"); + else { + setregs(); + send("OK"); + } + continue; + +#if 0 + case KGDB_SET_REG: + val = hex2i(&p); + if (*p++ != '=') { + send("E01"); + continue; + } + if (val < 0 && val >= KGDB_NUMREGS) { + send("E01"); + continue; + } + + gdbregs[val] = hex2i(&p); + setregs(); + send("OK"); + + continue; +#endif + + case KGDB_MEM_R: + val = hex2i(&p); + if (*p++ != ',') { + send("E02"); + continue; + } + len = hex2i(&p); + if (*p != '\0') { + send("E03"); + continue; + } + if (len > sizeof(buffer)) { + send("E04"); + continue; + } + if (!acc(val, len)) { + send("E05"); + continue; + } + + if (read(val, (size_t)len, (char *)buffer)) { + mem2hex(temp, buffer, len); + send(temp); + } else { + send("E05"); + } + continue; + + case KGDB_MEM_W: + val = hex2i(&p); + if (*p++ != ',') { + send("E06"); + continue; + } + len = hex2i(&p); + if (*p++ != ':') { + send("E07"); + continue; + } + if (len > datalen - (p - data)) { + send("E08"); + continue; + } + p = hex2mem(buffer, p, sizeof(buffer)); + if (p == NULL) { + send("E09"); + continue; + } + if (!acc(val, len)) { + send("E0A"); + continue; + } + if (write(val, (size_t)len, (char *)buffer)) + send("OK"); + else + send("E0B"); + continue; + + case KGDB_SET_THREAD: + subcmd = *p++; + val = hex2i(&p); + if (val == 0) + send("OK"); + else + send("E01"); + continue; + + case KGDB_DETACH: + case KGDB_KILL: + active = false; + clearSingleStep(); + detach(); + goto out; + + case KGDB_ASYNC_CONT: + subcmd = hex2i(&p); + if (*p++ == ';') { + val = hex2i(&p); + context->setPC(val); + context->setNextPC(val + sizeof(MachInst)); + } + clearSingleStep(); + goto out; + + case KGDB_CONT: + if (p - data < datalen) { + val = hex2i(&p); + context->setPC(val); + context->setNextPC(val + sizeof(MachInst)); + } + clearSingleStep(); + goto out; + + case KGDB_ASYNC_STEP: + subcmd = hex2i(&p); + if (*p++ == ';') { + val = hex2i(&p); + context->setPC(val); + context->setNextPC(val + sizeof(MachInst)); + } + setSingleStep(); + goto out; + + case KGDB_STEP: + if (p - data < datalen) { + val = hex2i(&p); + context->setPC(val); + context->setNextPC(val + sizeof(MachInst)); + } + setSingleStep(); + goto out; + + case KGDB_CLR_HW_BKPT: + subcmd = *p++; + if (*p++ != ',') send("E0D"); + val = hex2i(&p); + if (*p++ != ',') send("E0D"); + len = hex2i(&p); + + DPRINTF(GDBMisc, "clear %s, addr=%#x, len=%d\n", + break_type(subcmd), val, len); + + ret = false; + + switch (subcmd) { + case '0': // software breakpoint + ret = removeSoftBreak(val, len); + break; + + case '1': // hardware breakpoint + ret = removeHardBreak(val, len); + break; + + case '2': // write watchpoint + case '3': // read watchpoint + case '4': // access watchpoint + default: // unknown + send(""); + break; + } + + send(ret ? "OK" : "E0C"); + continue; + + case KGDB_SET_HW_BKPT: + subcmd = *p++; + if (*p++ != ',') send("E0D"); + val = hex2i(&p); + if (*p++ != ',') send("E0D"); + len = hex2i(&p); + + DPRINTF(GDBMisc, "set %s, addr=%#x, len=%d\n", + break_type(subcmd), val, len); + + ret = false; + + switch (subcmd) { + case '0': // software breakpoint + ret = insertSoftBreak(val, len); + break; + + case '1': // hardware breakpoint + ret = insertHardBreak(val, len); + break; + + case '2': // write watchpoint + case '3': // read watchpoint + case '4': // access watchpoint + default: // unknown + send(""); + break; + } + + send(ret ? "OK" : "E0C"); + continue; + + case KGDB_QUERY_VAR: + var = string(p, datalen - 1); + if (var == "C") + send("QC0"); + else + send(""); + continue; + + case KGDB_SET_BAUD: + case KGDB_SET_BREAK: + case KGDB_DEBUG: + case KGDB_CYCLE_STEP: + case KGDB_SIG_CYCLE_STEP: + case KGDB_READ_REG: + case KGDB_SET_VAR: + case KGDB_RESET: + case KGDB_THREAD_ALIVE: + case KGDB_TARGET_EXIT: + case KGDB_BINARY_DLOAD: + // Unsupported command + DPRINTF(GDBMisc, "Unsupported command: %s\n", + gdb_command(command)); + DDUMP(GDBMisc, (uint8_t *)data, datalen); + send(""); + continue; + + default: + // Unknown command. + DPRINTF(GDBMisc, "Unknown command: %c(%#x)\n", + command, command); + send(""); + continue; + + + } + } + + out: + return true; +} + +// Convert a hex digit into an integer. +// This returns -1 if the argument passed is no valid hex digit. +int +digit2i(char c) +{ + if (c >= '0' && c <= '9') + return (c - '0'); + else if (c >= 'a' && c <= 'f') + return (c - 'a' + 10); + else if (c >= 'A' && c <= 'F') + + return (c - 'A' + 10); + else + return (-1); +} + +// Convert the low 4 bits of an integer into an hex digit. +char +i2digit(int n) +{ + return ("0123456789abcdef"[n & 0x0f]); +} + +// Convert a byte array into an hex string. +void +mem2hex(void *vdst, const void *vsrc, int len) +{ + char *dst = (char *)vdst; + const char *src = (const char *)vsrc; + + while (len--) { + *dst++ = i2digit(*src >> 4); + *dst++ = i2digit(*src++); + } + *dst = '\0'; +} + +// Convert an hex string into a byte array. +// This returns a pointer to the character following the last valid +// hex digit. If the string ends in the middle of a byte, NULL is +// returned. +const char * +hex2mem(void *vdst, const char *src, int maxlen) +{ + char *dst = (char *)vdst; + int msb, lsb; + + while (*src && maxlen--) { + msb = digit2i(*src++); + if (msb < 0) + return (src - 1); + lsb = digit2i(*src++); + if (lsb < 0) + return (NULL); + *dst++ = (msb << 4) | lsb; + } + return (src); +} + +// Convert an hex string into an integer. +// This returns a pointer to the character following the last valid +// hex digit. +Addr +hex2i(const char **srcp) +{ + const char *src = *srcp; + Addr r = 0; + int nibble; + + while ((nibble = digit2i(*src)) >= 0) { + r *= 16; + r += nibble; + src++; + } + *srcp = src; + return (r); +} + diff --git a/base/remote_gdb.hh b/src/base/remote_gdb.hh index b7abf5116..b7abf5116 100644 --- a/base/remote_gdb.hh +++ b/src/base/remote_gdb.hh diff --git a/base/res_list.hh b/src/base/res_list.hh index 960ed108e..960ed108e 100644 --- a/base/res_list.hh +++ b/src/base/res_list.hh diff --git a/base/sat_counter.cc b/src/base/sat_counter.cc index 7920f6c81..7920f6c81 100644 --- a/base/sat_counter.cc +++ b/src/base/sat_counter.cc diff --git a/base/sat_counter.hh b/src/base/sat_counter.hh index d7be17b6f..d7be17b6f 100644 --- a/base/sat_counter.hh +++ b/src/base/sat_counter.hh diff --git a/base/sched_list.hh b/src/base/sched_list.hh index f794e3514..f794e3514 100644 --- a/base/sched_list.hh +++ b/src/base/sched_list.hh diff --git a/base/socket.cc b/src/base/socket.cc index 45a60e7e3..45a60e7e3 100644 --- a/base/socket.cc +++ b/src/base/socket.cc diff --git a/base/socket.hh b/src/base/socket.hh index 848405c09..848405c09 100644 --- a/base/socket.hh +++ b/src/base/socket.hh diff --git a/src/base/statistics.cc b/src/base/statistics.cc new file mode 100644 index 000000000..20de46347 --- /dev/null +++ b/src/base/statistics.cc @@ -0,0 +1,356 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <iomanip> +#include <fstream> +#include <list> +#include <map> +#include <string> + +#include "base/callback.hh" +#include "base/cprintf.hh" +#include "base/hostinfo.hh" +#include "base/misc.hh" +#include "base/statistics.hh" +#include "base/str.hh" +#include "base/time.hh" +#include "base/trace.hh" +#include "base/stats/statdb.hh" +#include "config/stats_binning.hh" + +using namespace std; + +namespace Stats { + +StatData * +DataAccess::find() const +{ + return Database::find(const_cast<void *>((const void *)this)); +} + +const StatData * +getStatData(const void *stat) +{ + return Database::find(const_cast<void *>(stat)); +} + +void +DataAccess::map(StatData *data) +{ + Database::regStat(this, data); +} + +StatData * +DataAccess::statData() +{ + StatData *ptr = find(); + assert(ptr); + return ptr; +} + +const StatData * +DataAccess::statData() const +{ + const StatData *ptr = find(); + assert(ptr); + return ptr; +} + +void +DataAccess::setInit() +{ + statData()->flags |= init; +} + +void +DataAccess::setPrint() +{ + Database::regPrint(this); +} + +StatData::StatData() + : flags(none), precision(-1), prereq(0) +{ + static int count = 0; + id = count++; +} + +StatData::~StatData() +{ +} + +bool +StatData::less(StatData *stat1, StatData *stat2) +{ + const string &name1 = stat1->name; + const string &name2 = stat2->name; + + vector<string> v1; + vector<string> v2; + + tokenize(v1, name1, '.'); + tokenize(v2, name2, '.'); + + int last = min(v1.size(), v2.size()) - 1; + for (int i = 0; i < last; ++i) + if (v1[i] != v2[i]) + return v1[i] < v2[i]; + + // Special compare for last element. + if (v1[last] == v2[last]) + return v1.size() < v2.size(); + else + return v1[last] < v2[last]; + + return false; +} + +bool +StatData::baseCheck() const +{ + if (!(flags & init)) { +#ifdef DEBUG + cprintf("this is stat number %d\n", id); +#endif + panic("Not all stats have been initialized"); + return false; + } + + if ((flags & print) && name.empty()) { + panic("all printable stats must be named"); + return false; + } + + return true; +} + + +void +FormulaBase::result(VResult &vec) const +{ + if (root) + vec = root->result(); +} + +Result +FormulaBase::total() const +{ + return root ? root->total() : 0.0; +} + +size_t +FormulaBase::size() const +{ + if (!root) + return 0; + else + return root->size(); +} + +bool +FormulaBase::binned() const +{ + return root && root->binned(); +} + +void +FormulaBase::reset() +{ +} + +bool +FormulaBase::zero() const +{ + VResult vec; + result(vec); + for (int i = 0; i < vec.size(); ++i) + if (vec[i] != 0.0) + return false; + return true; +} + +void +FormulaBase::update(StatData *) +{ +} + +string +FormulaBase::str() const +{ + return root ? root->str() : ""; +} + +Formula::Formula() +{ + setInit(); +} + +Formula::Formula(Temp r) +{ + root = r; + assert(size()); +} + +const Formula & +Formula::operator=(Temp r) +{ + assert(!root && "Can't change formulas"); + root = r; + assert(size()); + return *this; +} + +const Formula & +Formula::operator+=(Temp r) +{ + if (root) + root = NodePtr(new BinaryNode<std::plus<Result> >(root, r)); + else + root = r; + assert(size()); + return *this; +} + +MainBin::MainBin(const string &name) + : _name(name), mem(NULL), memsize(-1) +{ + Database::regBin(this, name); +} + +MainBin::~MainBin() +{ + if (mem) + delete [] mem; +} + +char * +MainBin::memory(off_t off) +{ + if (memsize == -1) + memsize = ceilPow2((size_t) offset()); + + if (!mem) { + mem = new char[memsize]; + memset(mem, 0, memsize); + } + + assert(offset() <= size()); + return mem + off; +} + +void +check() +{ + typedef Database::stat_list_t::iterator iter_t; + + iter_t i, end = Database::stats().end(); + for (i = Database::stats().begin(); i != end; ++i) { + StatData *data = *i; + assert(data); + if (!data->check() || !data->baseCheck()) + panic("stat check failed for %s\n", data->name); + } + + int j = 0; + for (i = Database::stats().begin(); i != end; ++i) { + StatData *data = *i; + if (!(data->flags & print)) + data->name = "__Stat" + to_string(j++); + } + + Database::stats().sort(StatData::less); + +#if STATS_BINNING + if (MainBin::curBin() == NULL) { + static MainBin mainBin("main bin"); + mainBin.activate(); + } +#endif + + if (i == end) + return; + + iter_t last = i; + ++i; + + for (i = Database::stats().begin(); i != end; ++i) { + if ((*i)->name == (*last)->name) + panic("same name used twice! name=%s\n", (*i)->name); + + last = i; + } +} + +CallbackQueue resetQueue; + +void +reset() +{ + // reset non-binned stats + Database::stat_list_t::iterator i = Database::stats().begin(); + Database::stat_list_t::iterator end = Database::stats().end(); + while (i != end) { + StatData *data = *i; + if (!data->binned()) + data->reset(); + ++i; + } + + // save the bin so we can go back to where we were + MainBin *orig = MainBin::curBin(); + + // reset binned stats + Database::bin_list_t::iterator bi = Database::bins().begin(); + Database::bin_list_t::iterator be = Database::bins().end(); + while (bi != be) { + MainBin *bin = *bi; + bin->activate(); + + i = Database::stats().begin(); + while (i != end) { + StatData *data = *i; + if (data->binned()) + data->reset(); + ++i; + } + ++bi; + } + + // restore bin + MainBin::curBin() = orig; + + resetQueue.process(); +} + +void +registerResetCallback(Callback *cb) +{ + resetQueue.add(cb); +} + +/* namespace Stats */ } diff --git a/src/base/statistics.hh b/src/base/statistics.hh new file mode 100644 index 000000000..dd507c091 --- /dev/null +++ b/src/base/statistics.hh @@ -0,0 +1,2896 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file + * Declaration of Statistics objects. + */ + +/** +* @todo +* +* Generalized N-dimensinal vector +* documentation +* key stats +* interval stats +* -- these both can use the same function that prints out a +* specific set of stats +* VectorStandardDeviation totals +* Document Namespaces +*/ +#ifndef __BASE_STATISTICS_HH__ +#define __BASE_STATISTICS_HH__ + +#include <algorithm> +#include <cassert> +#include <cmath> +#include <functional> +#include <iosfwd> +#include <string> +#include <vector> + +#include "base/cprintf.hh" +#include "base/intmath.hh" +#include "base/refcnt.hh" +#include "base/str.hh" +#include "base/stats/bin.hh" +#include "base/stats/flags.hh" +#include "base/stats/visit.hh" +#include "base/stats/types.hh" +#include "config/stats_binning.hh" +#include "sim/host.hh" + +class Callback; + +/** The current simulated cycle. */ +extern Tick curTick; + +/* A namespace for all of the Statistics */ +namespace Stats { + +/* Contains the statistic implementation details */ +////////////////////////////////////////////////////////////////////// +// +// Statistics Framework Base classes +// +////////////////////////////////////////////////////////////////////// +struct StatData +{ + /** The name of the stat. */ + std::string name; + /** The description of the stat. */ + std::string desc; + /** The formatting flags. */ + StatFlags flags; + /** The display precision. */ + int precision; + /** A pointer to a prerequisite Stat. */ + const StatData *prereq; + /** + * A unique stat ID for each stat in the simulator. + * Can be used externally for lookups as well as for debugging. + */ + int id; + + StatData(); + virtual ~StatData(); + + /** + * @return true if the stat is binned. + */ + virtual bool binned() const = 0; + + /** + * Reset the corresponding stat to the default state. + */ + virtual void reset() = 0; + + /** + * @return true if this stat has a value and satisfies its + * requirement as a prereq + */ + virtual bool zero() const = 0; + + /** + * Check that this stat has been set up properly and is ready for + * use + * @return true for success + */ + virtual bool check() const = 0; + bool baseCheck() const; + + /** + * Visitor entry for outputing statistics data + */ + virtual void visit(Visit &visitor) = 0; + + /** + * Checks if the first stat's name is alphabetically less than the second. + * This function breaks names up at periods and considers each subname + * separately. + * @param stat1 The first stat. + * @param stat2 The second stat. + * @return stat1's name is alphabetically before stat2's + */ + static bool less(StatData *stat1, StatData *stat2); +}; + +class ScalarData : public StatData +{ + public: + virtual Counter value() const = 0; + virtual Result result() const = 0; + virtual Result total() const = 0; + virtual void visit(Visit &visitor) { visitor.visit(*this); } +}; + +template <class Stat> +class ScalarStatData : public ScalarData +{ + protected: + Stat &s; + + public: + ScalarStatData(Stat &stat) : s(stat) {} + + virtual bool binned() const { return s.binned(); } + virtual bool check() const { return s.check(); } + virtual Counter value() const { return s.value(); } + virtual Result result() const { return s.result(); } + virtual Result total() const { return s.total(); } + virtual void reset() { s.reset(); } + virtual bool zero() const { return s.zero(); } +}; + +struct VectorData : public StatData +{ + /** Names and descriptions of subfields. */ + mutable std::vector<std::string> subnames; + mutable std::vector<std::string> subdescs; + + virtual size_t size() const = 0; + virtual const VCounter &value() const = 0; + virtual const VResult &result() const = 0; + virtual Result total() const = 0; + void update() + { + if (!subnames.empty()) { + int s = size(); + if (subnames.size() < s) + subnames.resize(s); + + if (subdescs.size() < s) + subdescs.resize(s); + } + } +}; + +template <class Stat> +class VectorStatData : public VectorData +{ + protected: + Stat &s; + mutable VCounter cvec; + mutable VResult rvec; + + public: + VectorStatData(Stat &stat) : s(stat) {} + + virtual bool binned() const { return s.binned(); } + virtual bool check() const { return s.check(); } + virtual bool zero() const { return s.zero(); } + virtual void reset() { s.reset(); } + + virtual size_t size() const { return s.size(); } + virtual VCounter &value() const + { + s.value(cvec); + return cvec; + } + virtual const VResult &result() const + { + s.result(rvec); + return rvec; + } + virtual Result total() const { return s.total(); } + virtual void visit(Visit &visitor) + { + update(); + s.update(this); + visitor.visit(*this); + } +}; + +struct DistDataData +{ + Counter min_val; + Counter max_val; + Counter underflow; + Counter overflow; + VCounter cvec; + Counter sum; + Counter squares; + Counter samples; + + Counter min; + Counter max; + Counter bucket_size; + int size; + bool fancy; +}; + +struct DistData : public StatData +{ + /** Local storage for the entry values, used for printing. */ + DistDataData data; +}; + +template <class Stat> +class DistStatData : public DistData +{ + protected: + Stat &s; + + public: + DistStatData(Stat &stat) : s(stat) {} + + virtual bool binned() const { return s.binned(); } + virtual bool check() const { return s.check(); } + virtual void reset() { s.reset(); } + virtual bool zero() const { return s.zero(); } + virtual void visit(Visit &visitor) + { + s.update(this); + visitor.visit(*this); + } +}; + +struct VectorDistData : public StatData +{ + std::vector<DistDataData> data; + + /** Names and descriptions of subfields. */ + mutable std::vector<std::string> subnames; + mutable std::vector<std::string> subdescs; + + /** Local storage for the entry values, used for printing. */ + mutable VResult rvec; + + virtual size_t size() const = 0; + void update() + { + int s = size(); + if (subnames.size() < s) + subnames.resize(s); + + if (subdescs.size() < s) + subdescs.resize(s); + } +}; + +template <class Stat> +class VectorDistStatData : public VectorDistData +{ + protected: + Stat &s; + typedef typename Stat::bin_t bin_t; + + public: + VectorDistStatData(Stat &stat) : s(stat) {} + + virtual bool binned() const { return bin_t::binned; } + virtual bool check() const { return s.check(); } + virtual void reset() { s.reset(); } + virtual size_t size() const { return s.size(); } + virtual bool zero() const { return s.zero(); } + virtual void visit(Visit &visitor) + { + update(); + s.update(this); + visitor.visit(*this); + } +}; + +struct Vector2dData : public StatData +{ + /** Names and descriptions of subfields. */ + std::vector<std::string> subnames; + std::vector<std::string> subdescs; + std::vector<std::string> y_subnames; + + /** Local storage for the entry values, used for printing. */ + mutable VCounter cvec; + mutable int x; + mutable int y; + + void update() + { + if (subnames.size() < x) + subnames.resize(x); + } +}; + +template <class Stat> +class Vector2dStatData : public Vector2dData +{ + protected: + Stat &s; + typedef typename Stat::bin_t bin_t; + + public: + Vector2dStatData(Stat &stat) : s(stat) {} + + virtual bool binned() const { return bin_t::binned; } + virtual bool check() const { return s.check(); } + virtual void reset() { s.reset(); } + virtual bool zero() const { return s.zero(); } + virtual void visit(Visit &visitor) + { + update(); + s.update(this); + visitor.visit(*this); + } +}; + + +class DataAccess +{ + protected: + StatData *find() const; + void map(StatData *data); + + StatData *statData(); + const StatData *statData() const; + + void setInit(); + void setPrint(); +}; + +template <class Parent, class Child, template <class> class Data> +class Wrap : public Child +{ + protected: + Parent &self() { return *reinterpret_cast<Parent *>(this); } + + protected: + Data<Child> *statData() + { + StatData *__data = DataAccess::statData(); + Data<Child> *ptr = dynamic_cast<Data<Child> *>(__data); + assert(ptr); + return ptr; + } + + public: + const Data<Child> *statData() const + { + const StatData *__data = DataAccess::statData(); + const Data<Child> *ptr = dynamic_cast<const Data<Child> *>(__data); + assert(ptr); + return ptr; + } + + protected: + /** + * Copy constructor, copies are not allowed. + */ + Wrap(const Wrap &stat); + /** + * Can't copy stats. + */ + void operator=(const Wrap &); + + public: + Wrap() + { + map(new Data<Child>(*this)); + } + + /** + * Set the name and marks this stat to print at the end of simulation. + * @param name The new name. + * @return A reference to this stat. + */ + Parent &name(const std::string &_name) + { + Data<Child> *data = this->statData(); + data->name = _name; + this->setPrint(); + return this->self(); + } + + /** + * Set the description and marks this stat to print at the end of + * simulation. + * @param desc The new description. + * @return A reference to this stat. + */ + Parent &desc(const std::string &_desc) + { + this->statData()->desc = _desc; + return this->self(); + } + + /** + * Set the precision and marks this stat to print at the end of simulation. + * @param p The new precision + * @return A reference to this stat. + */ + Parent &precision(int _precision) + { + this->statData()->precision = _precision; + return this->self(); + } + + /** + * Set the flags and marks this stat to print at the end of simulation. + * @param f The new flags. + * @return A reference to this stat. + */ + Parent &flags(StatFlags _flags) + { + this->statData()->flags |= _flags; + return this->self(); + } + + /** + * Set the prerequisite stat and marks this stat to print at the end of + * simulation. + * @param prereq The prerequisite stat. + * @return A reference to this stat. + */ + template <class Stat> + Parent &prereq(const Stat &prereq) + { + this->statData()->prereq = prereq.statData(); + return this->self(); + } +}; + +template <class Parent, class Child, template <class Child> class Data> +class WrapVec : public Wrap<Parent, Child, Data> +{ + public: + // The following functions are specific to vectors. If you use them + // in a non vector context, you will get a nice compiler error! + + /** + * Set the subfield name for the given index, and marks this stat to print + * at the end of simulation. + * @param index The subfield index. + * @param name The new name of the subfield. + * @return A reference to this stat. + */ + Parent &subname(int index, const std::string &name) + { + std::vector<std::string> &subn = this->statData()->subnames; + if (subn.size() <= index) + subn.resize(index + 1); + subn[index] = name; + return this->self(); + } + + /** + * Set the subfield description for the given index and marks this stat to + * print at the end of simulation. + * @param index The subfield index. + * @param desc The new description of the subfield + * @return A reference to this stat. + */ + Parent &subdesc(int index, const std::string &desc) + { + std::vector<std::string> &subd = this->statData()->subdescs; + if (subd.size() <= index) + subd.resize(index + 1); + subd[index] = desc; + + return this->self(); + } + +}; + +template <class Parent, class Child, template <class Child> class Data> +class WrapVec2d : public WrapVec<Parent, Child, Data> +{ + public: + /** + * @warning This makes the assumption that if you're gonna subnames a 2d + * vector, you're subnaming across all y + */ + Parent &ysubnames(const char **names) + { + Data<Child> *data = this->statData(); + data->y_subnames.resize(this->y); + for (int i = 0; i < this->y; ++i) + data->y_subnames[i] = names[i]; + return this->self(); + } + Parent &ysubname(int index, const std::string subname) + { + Data<Child> *data = this->statData(); + assert(index < this->y); + data->y_subnames.resize(this->y); + data->y_subnames[index] = subname.c_str(); + return this->self(); + } +}; + +////////////////////////////////////////////////////////////////////// +// +// Simple Statistics +// +////////////////////////////////////////////////////////////////////// + +/** + * Templatized storage and interface for a simple scalar stat. + */ +struct StatStor +{ + public: + /** The paramaters for this storage type, none for a scalar. */ + struct Params { }; + + private: + /** The statistic value. */ + Counter data; + + public: + /** + * Builds this storage element and calls the base constructor of the + * datatype. + */ + StatStor(const Params &) : data(Counter()) {} + + /** + * The the stat to the given value. + * @param val The new value. + * @param p The paramters of this storage type. + */ + void set(Counter val, const Params &p) { data = val; } + /** + * Increment the stat by the given value. + * @param val The new value. + * @param p The paramters of this storage type. + */ + void inc(Counter val, const Params &p) { data += val; } + /** + * Decrement the stat by the given value. + * @param val The new value. + * @param p The paramters of this storage type. + */ + void dec(Counter val, const Params &p) { data -= val; } + /** + * Return the value of this stat as its base type. + * @param p The params of this storage type. + * @return The value of this stat. + */ + Counter value(const Params &p) const { return data; } + /** + * Return the value of this stat as a result type. + * @param p The parameters of this storage type. + * @return The value of this stat. + */ + Result result(const Params &p) const { return (Result)data; } + /** + * Reset stat value to default + */ + void reset() { data = Counter(); } + + /** + * @return true if zero value + */ + bool zero() const { return data == Counter(); } +}; + +/** + * Templatized storage and interface to a per-cycle average stat. This keeps + * a current count and updates a total (count * cycles) when this count + * changes. This allows the quick calculation of a per cycle count of the item + * being watched. This is good for keeping track of residencies in structures + * among other things. + * @todo add lateny to the stat and fix binning. + */ +struct AvgStor +{ + public: + /** The paramaters for this storage type */ + struct Params + { + /** + * The current count. We stash this here because the current + * value is not a binned value. + */ + Counter current; + }; + + private: + /** The total count for all cycles. */ + mutable Result total; + /** The cycle that current last changed. */ + mutable Tick last; + + public: + /** + * Build and initializes this stat storage. + */ + AvgStor(Params &p) : total(0), last(0) { p.current = Counter(); } + + /** + * Set the current count to the one provided, update the total and last + * set values. + * @param val The new count. + * @param p The parameters for this storage. + */ + void set(Counter val, Params &p) { + total += p.current * (curTick - last); + last = curTick; + p.current = val; + } + + /** + * Increment the current count by the provided value, calls set. + * @param val The amount to increment. + * @param p The parameters for this storage. + */ + void inc(Counter val, Params &p) { set(p.current + val, p); } + + /** + * Deccrement the current count by the provided value, calls set. + * @param val The amount to decrement. + * @param p The parameters for this storage. + */ + void dec(Counter val, Params &p) { set(p.current - val, p); } + + /** + * Return the current count. + * @param p The parameters for this storage. + * @return The current count. + */ + Counter value(const Params &p) const { return p.current; } + + /** + * Return the current average. + * @param p The parameters for this storage. + * @return The current average. + */ + Result result(const Params &p) const + { + total += p.current * (curTick - last); + last = curTick; + return (Result)(total + p.current) / (Result)(curTick + 1); + } + + /** + * Reset stat value to default + */ + void reset() + { + total = 0; + last = curTick; + } + + /** + * @return true if zero value + */ + bool zero() const { return total == 0.0; } +}; + +/** + * Implementation of a scalar stat. The type of stat is determined by the + * Storage template. The storage for this stat is held within the Bin class. + * This allows for breaking down statistics across multiple bins easily. + */ +template <class Storage, class Bin> +class ScalarBase : public DataAccess +{ + public: + /** Define the params of the storage class. */ + typedef typename Storage::Params params_t; + /** Define the bin type. */ + typedef typename Bin::template Bin<Storage> bin_t; + + protected: + /** The bin of this stat. */ + bin_t bin; + /** The parameters for this stat. */ + params_t params; + + protected: + /** + * Retrieve the storage from the bin. + * @return The storage object for this stat. + */ + Storage *data() { return bin.data(params); } + /** + * Retrieve a const pointer to the storage from the bin. + * @return A const pointer to the storage object for this stat. + */ + const Storage *data() const + { + bin_t *_bin = const_cast<bin_t *>(&bin); + params_t *_params = const_cast<params_t *>(¶ms); + return _bin->data(*_params); + } + + public: + /** + * Return the current value of this stat as its base type. + * @return The current value. + */ + Counter value() const { return data()->value(params); } + + public: + /** + * Create and initialize this stat, register it with the database. + */ + ScalarBase() + { + bin.init(params); + } + + public: + // Common operators for stats + /** + * Increment the stat by 1. This calls the associated storage object inc + * function. + */ + void operator++() { data()->inc(1, params); } + /** + * Decrement the stat by 1. This calls the associated storage object dec + * function. + */ + void operator--() { data()->dec(1, params); } + + /** Increment the stat by 1. */ + void operator++(int) { ++*this; } + /** Decrement the stat by 1. */ + void operator--(int) { --*this; } + + /** + * Set the data value to the given value. This calls the associated storage + * object set function. + * @param v The new value. + */ + template <typename U> + void operator=(const U &v) { data()->set(v, params); } + + /** + * Increment the stat by the given value. This calls the associated + * storage object inc function. + * @param v The value to add. + */ + template <typename U> + void operator+=(const U &v) { data()->inc(v, params); } + + /** + * Decrement the stat by the given value. This calls the associated + * storage object dec function. + * @param v The value to substract. + */ + template <typename U> + void operator-=(const U &v) { data()->dec(v, params); } + + /** + * Return the number of elements, always 1 for a scalar. + * @return 1. + */ + size_t size() const { return 1; } + /** + * Return true if stat is binned. + *@return True is stat is binned. + */ + bool binned() const { return bin_t::binned; } + + bool check() const { return bin.initialized(); } + + /** + * Reset stat value to default + */ + void reset() { bin.reset(); } + + Counter value() { return data()->value(params); } + + Result result() { return data()->result(params); } + + Result total() { return result(); } + + bool zero() { return result() == 0.0; } + +}; + +class ProxyData : public ScalarData +{ + public: + virtual void visit(Visit &visitor) { visitor.visit(*this); } + virtual bool binned() const { return false; } + virtual std::string str() const { return to_string(value()); } + virtual size_t size() const { return 1; } + virtual bool zero() const { return value() == 0; } + virtual bool check() const { return true; } + virtual void reset() { } +}; + +template <class T> +class ValueProxy : public ProxyData +{ + private: + T *scalar; + + public: + ValueProxy(T &val) : scalar(&val) {} + virtual Counter value() const { return *scalar; } + virtual Result result() const { return *scalar; } + virtual Result total() const { return *scalar; } +}; + +template <class T> +class FunctorProxy : public ProxyData +{ + private: + T *functor; + + public: + FunctorProxy(T &func) : functor(&func) {} + virtual Counter value() const { return (*functor)(); } + virtual Result result() const { return (*functor)(); } + virtual Result total() const { return (*functor)(); } +}; + +class ValueBase : public DataAccess +{ + private: + ProxyData *proxy; + + public: + ValueBase() : proxy(NULL) { } + ~ValueBase() { if (proxy) delete proxy; } + + template <class T> + void scalar(T &value) + { + proxy = new ValueProxy<T>(value); + setInit(); + } + + template <class T> + void functor(T &func) + { + proxy = new FunctorProxy<T>(func); + setInit(); + } + + Counter value() { return proxy->value(); } + Result result() const { return proxy->result(); } + Result total() const { return proxy->total(); }; + size_t size() const { return proxy->size(); } + + bool binned() const { return proxy->binned(); } + std::string str() const { return proxy->str(); } + bool zero() const { return proxy->zero(); } + bool check() const { return proxy != NULL; } + void reset() { } +}; + +////////////////////////////////////////////////////////////////////// +// +// Vector Statistics +// +////////////////////////////////////////////////////////////////////// +template <class Storage, class Bin> +class ScalarProxy; + +/** + * Implementation of a vector of stats. The type of stat is determined by the + * Storage class. @sa ScalarBase + */ +template <class Storage, class Bin> +class VectorBase : public DataAccess +{ + public: + /** Define the params of the storage class. */ + typedef typename Storage::Params params_t; + /** Define the bin type. */ + typedef typename Bin::template VectorBin<Storage> bin_t; + + protected: + /** The bin of this stat. */ + bin_t bin; + /** The parameters for this stat. */ + params_t params; + + protected: + /** + * Retrieve the storage from the bin for the given index. + * @param index The vector index to access. + * @return The storage object at the given index. + */ + Storage *data(int index) { return bin.data(index, params); } + /** + * Retrieve a const pointer to the storage from the bin + * for the given index. + * @param index The vector index to access. + * @return A const pointer to the storage object at the given index. + */ + const Storage *data(int index) const + { + bin_t *_bin = const_cast<bin_t *>(&bin); + params_t *_params = const_cast<params_t *>(¶ms); + return _bin->data(index, *_params); + } + + public: + void value(VCounter &vec) const + { + vec.resize(size()); + for (int i = 0; i < size(); ++i) + vec[i] = data(i)->value(params); + } + + /** + * Copy the values to a local vector and return a reference to it. + * @return A reference to a vector of the stat values. + */ + void result(VResult &vec) const + { + vec.resize(size()); + for (int i = 0; i < size(); ++i) + vec[i] = data(i)->result(params); + } + + /** + * @return True is stat is binned. + */ + bool binned() const { return bin_t::binned; } + + /** + * Return a total of all entries in this vector. + * @return The total of all vector entries. + */ + Result total() const { + Result total = 0.0; + for (int i = 0; i < size(); ++i) + total += data(i)->result(params); + return total; + } + + /** + * @return the number of elements in this vector. + */ + size_t size() const { return bin.size(); } + + bool zero() const + { + for (int i = 0; i < size(); ++i) + if (data(i)->zero()) + return true; + return false; + } + + bool check() const { return bin.initialized(); } + void reset() { bin.reset(); } + + public: + VectorBase() {} + + /** Friend this class with the associated scalar proxy. */ + friend class ScalarProxy<Storage, Bin>; + + /** + * Return a reference (ScalarProxy) to the stat at the given index. + * @param index The vector index to access. + * @return A reference of the stat. + */ + ScalarProxy<Storage, Bin> operator[](int index); + + void update(StatData *data) {} +}; + +const StatData * getStatData(const void *stat); + +/** + * A proxy class to access the stat at a given index in a VectorBase stat. + * Behaves like a ScalarBase. + */ +template <class Storage, class Bin> +class ScalarProxy +{ + public: + /** Define the params of the storage class. */ + typedef typename Storage::Params params_t; + /** Define the bin type. */ + typedef typename Bin::template VectorBin<Storage> bin_t; + + private: + /** Pointer to the bin in the parent VectorBase. */ + bin_t *bin; + /** Pointer to the params in the parent VectorBase. */ + params_t *params; + /** The index to access in the parent VectorBase. */ + int index; + /** Keep a pointer to the original stat so was can get data */ + void *stat; + + protected: + /** + * Retrieve the storage from the bin. + * @return The storage from the bin for this stat. + */ + Storage *data() { return bin->data(index, *params); } + /** + * Retrieve a const pointer to the storage from the bin. + * @return A const pointer to the storage for this stat. + */ + const Storage *data() const + { + bin_t *_bin = const_cast<bin_t *>(bin); + params_t *_params = const_cast<params_t *>(params); + return _bin->data(index, *_params); + } + + public: + /** + * Return the current value of this stat as its base type. + * @return The current value. + */ + Counter value() const { return data()->value(*params); } + + /** + * Return the current value of this statas a result type. + * @return The current value. + */ + Result result() const { return data()->result(*params); } + + public: + /** + * Create and initialize this proxy, do not register it with the database. + * @param b The bin to use. + * @param p The params to use. + * @param i The index to access. + */ + ScalarProxy(bin_t &b, params_t &p, int i, void *s) + : bin(&b), params(&p), index(i), stat(s) {} + /** + * Create a copy of the provided ScalarProxy. + * @param sp The proxy to copy. + */ + ScalarProxy(const ScalarProxy &sp) + : bin(sp.bin), params(sp.params), index(sp.index), stat(sp.stat) {} + /** + * Set this proxy equal to the provided one. + * @param sp The proxy to copy. + * @return A reference to this proxy. + */ + const ScalarProxy &operator=(const ScalarProxy &sp) { + bin = sp.bin; + params = sp.params; + index = sp.index; + stat = sp.stat; + return *this; + } + + public: + // Common operators for stats + /** + * Increment the stat by 1. This calls the associated storage object inc + * function. + */ + void operator++() { data()->inc(1, *params); } + /** + * Decrement the stat by 1. This calls the associated storage object dec + * function. + */ + void operator--() { data()->dec(1, *params); } + + /** Increment the stat by 1. */ + void operator++(int) { ++*this; } + /** Decrement the stat by 1. */ + void operator--(int) { --*this; } + + /** + * Set the data value to the given value. This calls the associated storage + * object set function. + * @param v The new value. + */ + template <typename U> + void operator=(const U &v) { data()->set(v, *params); } + + /** + * Increment the stat by the given value. This calls the associated + * storage object inc function. + * @param v The value to add. + */ + template <typename U> + void operator+=(const U &v) { data()->inc(v, *params); } + + /** + * Decrement the stat by the given value. This calls the associated + * storage object dec function. + * @param v The value to substract. + */ + template <typename U> + void operator-=(const U &v) { data()->dec(v, *params); } + + /** + * Return the number of elements, always 1 for a scalar. + * @return 1. + */ + size_t size() const { return 1; } + + /** + * Return true if stat is binned. + *@return false since Proxies aren't printed/binned + */ + bool binned() const { return false; } + + /** + * This stat has no state. Nothing to reset + */ + void reset() { } + + public: + const StatData *statData() const { return getStatData(stat); } + std::string str() const + { + return csprintf("%s[%d]", this->statData()->name, index); + + } +}; + +template <class Storage, class Bin> +inline ScalarProxy<Storage, Bin> +VectorBase<Storage, Bin>::operator[](int index) +{ + assert (index >= 0 && index < size()); + return ScalarProxy<Storage, Bin>(bin, params, index, this); +} + +template <class Storage, class Bin> +class VectorProxy; + +template <class Storage, class Bin> +class Vector2dBase : public DataAccess +{ + public: + typedef typename Storage::Params params_t; + typedef typename Bin::template VectorBin<Storage> bin_t; + + protected: + size_t x; + size_t y; + bin_t bin; + params_t params; + + protected: + Storage *data(int index) { return bin.data(index, params); } + const Storage *data(int index) const + { + bin_t *_bin = const_cast<bin_t *>(&bin); + params_t *_params = const_cast<params_t *>(¶ms); + return _bin->data(index, *_params); + } + + public: + Vector2dBase() {} + + void update(Vector2dData *data) + { + int size = this->size(); + data->cvec.resize(size); + for (int i = 0; i < size; ++i) + data->cvec[i] = this->data(i)->value(params); + } + + std::string ysubname(int i) const { return (*this->y_subnames)[i]; } + + friend class VectorProxy<Storage, Bin>; + VectorProxy<Storage, Bin> operator[](int index); + + size_t size() const { return bin.size(); } + bool zero() const { return data(0)->value(params) == 0.0; } + + /** + * Reset stat value to default + */ + void reset() { bin.reset(); } + + bool check() { return bin.initialized(); } +}; + +template <class Storage, class Bin> +class VectorProxy +{ + public: + typedef typename Storage::Params params_t; + typedef typename Bin::template VectorBin<Storage> bin_t; + + private: + bin_t *bin; + params_t *params; + int offset; + int len; + void *stat; + + private: + mutable VResult *vec; + + Storage *data(int index) { + assert(index < len); + return bin->data(offset + index, *params); + } + + const Storage *data(int index) const { + bin_t *_bin = const_cast<bin_t *>(bin); + params_t *_params = const_cast<params_t *>(params); + return _bin->data(offset + index, *_params); + } + + public: + const VResult &result() const { + if (vec) + vec->resize(size()); + else + vec = new VResult(size()); + + for (int i = 0; i < size(); ++i) + (*vec)[i] = data(i)->result(*params); + + return *vec; + } + + Result total() const { + Result total = 0.0; + for (int i = 0; i < size(); ++i) + total += data(i)->result(*params); + return total; + } + + public: + VectorProxy(bin_t &b, params_t &p, int o, int l, void *s) + : bin(&b), params(&p), offset(o), len(l), stat(s), vec(NULL) + { + } + + VectorProxy(const VectorProxy &sp) + : bin(sp.bin), params(sp.params), offset(sp.offset), len(sp.len), + stat(sp.stat), vec(NULL) + { + } + + ~VectorProxy() + { + if (vec) + delete vec; + } + + const VectorProxy &operator=(const VectorProxy &sp) + { + bin = sp.bin; + params = sp.params; + offset = sp.offset; + len = sp.len; + stat = sp.stat; + if (vec) + delete vec; + vec = NULL; + return *this; + } + + ScalarProxy<Storage, Bin> operator[](int index) + { + assert (index >= 0 && index < size()); + return ScalarProxy<Storage, Bin>(*bin, *params, offset + index, stat); + } + + size_t size() const { return len; } + + /** + * Return true if stat is binned. + *@return false since Proxies aren't printed/binned + */ + bool binned() const { return false; } + + /** + * This stat has no state. Nothing to reset. + */ + void reset() { } +}; + +template <class Storage, class Bin> +inline VectorProxy<Storage, Bin> +Vector2dBase<Storage, Bin>::operator[](int index) +{ + int offset = index * y; + assert (index >= 0 && offset < size()); + return VectorProxy<Storage, Bin>(bin, params, offset, y, this); +} + +////////////////////////////////////////////////////////////////////// +// +// Non formula statistics +// +////////////////////////////////////////////////////////////////////// + +/** + * Templatized storage and interface for a distrbution stat. + */ +struct DistStor +{ + public: + /** The parameters for a distribution stat. */ + struct Params + { + /** The minimum value to track. */ + Counter min; + /** The maximum value to track. */ + Counter max; + /** The number of entries in each bucket. */ + Counter bucket_size; + /** The number of buckets. Equal to (max-min)/bucket_size. */ + int size; + }; + enum { fancy = false }; + + private: + /** The smallest value sampled. */ + Counter min_val; + /** The largest value sampled. */ + Counter max_val; + /** The number of values sampled less than min. */ + Counter underflow; + /** The number of values sampled more than max. */ + Counter overflow; + /** The current sum. */ + Counter sum; + /** The sum of squares. */ + Counter squares; + /** The number of samples. */ + Counter samples; + /** Counter for each bucket. */ + VCounter cvec; + + public: + /** + * Construct this storage with the supplied params. + * @param params The parameters. + */ + DistStor(const Params ¶ms) + : min_val(INT_MAX), max_val(INT_MIN), underflow(Counter()), + overflow(Counter()), sum(Counter()), squares(Counter()), + samples(Counter()), cvec(params.size) + { + reset(); + } + + /** + * Add a value to the distribution for the given number of times. + * @param val The value to add. + * @param number The number of times to add the value. + * @param params The paramters of the distribution. + */ + void sample(Counter val, int number, const Params ¶ms) + { + if (val < params.min) + underflow += number; + else if (val > params.max) + overflow += number; + else { + int index = (int)floor((val - params.min) / params.bucket_size); + assert(index < size(params)); + cvec[index] += number; + } + + if (val < min_val) + min_val = val; + + if (val > max_val) + max_val = val; + + Counter sample = val * number; + sum += sample; + squares += sample * sample; + samples += number; + } + + /** + * Return the number of buckets in this distribution. + * @return the number of buckets. + * @todo Is it faster to return the size from the parameters? + */ + size_t size(const Params &) const { return cvec.size(); } + + /** + * Returns true if any calls to sample have been made. + * @param params The paramters of the distribution. + * @return True if any values have been sampled. + */ + bool zero(const Params ¶ms) const + { + return samples == Counter(); + } + + void update(DistDataData *data, const Params ¶ms) + { + data->min = params.min; + data->max = params.max; + data->bucket_size = params.bucket_size; + data->size = params.size; + + data->min_val = (min_val == INT_MAX) ? 0 : min_val; + data->max_val = (max_val == INT_MIN) ? 0 : max_val; + data->underflow = underflow; + data->overflow = overflow; + data->cvec.resize(params.size); + for (int i = 0; i < params.size; ++i) + data->cvec[i] = cvec[i]; + + data->sum = sum; + data->squares = squares; + data->samples = samples; + } + + /** + * Reset stat value to default + */ + void reset() + { + min_val = INT_MAX; + max_val = INT_MIN; + underflow = 0; + overflow = 0; + + int size = cvec.size(); + for (int i = 0; i < size; ++i) + cvec[i] = Counter(); + + sum = Counter(); + squares = Counter(); + samples = Counter(); + } +}; + +/** + * Templatized storage and interface for a distribution that calculates mean + * and variance. + */ +struct FancyStor +{ + public: + /** + * No paramters for this storage. + */ + struct Params {}; + enum { fancy = true }; + + private: + /** The current sum. */ + Counter sum; + /** The sum of squares. */ + Counter squares; + /** The number of samples. */ + Counter samples; + + public: + /** + * Create and initialize this storage. + */ + FancyStor(const Params &) + : sum(Counter()), squares(Counter()), samples(Counter()) + { } + + /** + * Add a value the given number of times to this running average. + * Update the running sum and sum of squares, increment the number of + * values seen by the given number. + * @param val The value to add. + * @param number The number of times to add the value. + * @param p The parameters of this stat. + */ + void sample(Counter val, int number, const Params &p) + { + Counter value = val * number; + sum += value; + squares += value * value; + samples += number; + } + + void update(DistDataData *data, const Params ¶ms) + { + data->sum = sum; + data->squares = squares; + data->samples = samples; + } + + /** + * Return the number of entries in this stat, 1 + * @return 1. + */ + size_t size(const Params &) const { return 1; } + + /** + * Return true if no samples have been added. + * @return True if no samples have been added. + */ + bool zero(const Params &) const { return samples == Counter(); } + + /** + * Reset stat value to default + */ + void reset() + { + sum = Counter(); + squares = Counter(); + samples = Counter(); + } +}; + +/** + * Templatized storage for distribution that calculates per cycle mean and + * variance. + */ +struct AvgFancy +{ + public: + /** No parameters for this storage. */ + struct Params {}; + enum { fancy = true }; + + private: + /** Current total. */ + Counter sum; + /** Current sum of squares. */ + Counter squares; + + public: + /** + * Create and initialize this storage. + */ + AvgFancy(const Params &) : sum(Counter()), squares(Counter()) {} + + /** + * Add a value to the distribution for the given number of times. + * Update the running sum and sum of squares. + * @param val The value to add. + * @param number The number of times to add the value. + * @param p The paramters of the distribution. + */ + void sample(Counter val, int number, const Params &p) + { + Counter value = val * number; + sum += value; + squares += value * value; + } + + void update(DistDataData *data, const Params ¶ms) + { + data->sum = sum; + data->squares = squares; + data->samples = curTick; + } + + /** + * Return the number of entries, in this case 1. + * @return 1. + */ + size_t size(const Params ¶ms) const { return 1; } + /** + * Return true if no samples have been added. + * @return True if the sum is zero. + */ + bool zero(const Params ¶ms) const { return sum == Counter(); } + /** + * Reset stat value to default + */ + void reset() + { + sum = Counter(); + squares = Counter(); + } +}; + +/** + * Implementation of a distribution stat. The type of distribution is + * determined by the Storage template. @sa ScalarBase + */ +template <class Storage, class Bin> +class DistBase : public DataAccess +{ + public: + /** Define the params of the storage class. */ + typedef typename Storage::Params params_t; + /** Define the bin type. */ + typedef typename Bin::template Bin<Storage> bin_t; + + protected: + /** The bin of this stat. */ + bin_t bin; + /** The parameters for this stat. */ + params_t params; + + protected: + /** + * Retrieve the storage from the bin. + * @return The storage object for this stat. + */ + Storage *data() { return bin.data(params); } + /** + * Retrieve a const pointer to the storage from the bin. + * @return A const pointer to the storage object for this stat. + */ + const Storage *data() const + { + bin_t *_bin = const_cast<bin_t *>(&bin); + params_t *_params = const_cast<params_t *>(¶ms); + return _bin->data(*_params); + } + + public: + DistBase() { } + + /** + * Add a value to the distribtion n times. Calls sample on the storage + * class. + * @param v The value to add. + * @param n The number of times to add it, defaults to 1. + */ + template <typename U> + void sample(const U &v, int n = 1) { data()->sample(v, n, params); } + + /** + * Return the number of entries in this stat. + * @return The number of entries. + */ + size_t size() const { return data()->size(params); } + /** + * Return true if no samples have been added. + * @return True if there haven't been any samples. + */ + bool zero() const { return data()->zero(params); } + + void update(DistData *base) + { + base->data.fancy = Storage::fancy; + data()->update(&(base->data), params); + } + /** + * @return True is stat is binned. + */ + bool binned() const { return bin_t::binned; } + /** + * Reset stat value to default + */ + void reset() + { + bin.reset(); + } + + bool check() { return bin.initialized(); } +}; + +template <class Storage, class Bin> +class DistProxy; + +template <class Storage, class Bin> +class VectorDistBase : public DataAccess +{ + public: + typedef typename Storage::Params params_t; + typedef typename Bin::template VectorBin<Storage> bin_t; + + protected: + bin_t bin; + params_t params; + + protected: + Storage *data(int index) { return bin.data(index, params); } + const Storage *data(int index) const + { + bin_t *_bin = const_cast<bin_t *>(&bin); + params_t *_params = const_cast<params_t *>(¶ms); + return _bin->data(index, *_params); + } + + public: + VectorDistBase() {} + + friend class DistProxy<Storage, Bin>; + DistProxy<Storage, Bin> operator[](int index); + const DistProxy<Storage, Bin> operator[](int index) const; + + size_t size() const { return bin.size(); } + bool zero() const { return false; } + /** + * Return true if stat is binned. + *@return True is stat is binned. + */ + bool binned() const { return bin_t::binned; } + /** + * Reset stat value to default + */ + void reset() { bin.reset(); } + + bool check() { return bin.initialized(); } + void update(VectorDistData *base) + { + int size = this->size(); + base->data.resize(size); + for (int i = 0; i < size; ++i) { + base->data[i].fancy = Storage::fancy; + data(i)->update(&(base->data[i]), params); + } + } +}; + +template <class Storage, class Bin> +class DistProxy +{ + public: + typedef typename Storage::Params params_t; + typedef typename Bin::template Bin<Storage> bin_t; + typedef VectorDistBase<Storage, Bin> base_t; + + private: + union { + base_t *stat; + const base_t *cstat; + }; + int index; + + protected: + Storage *data() { return stat->data(index); } + const Storage *data() const { return cstat->data(index); } + + public: + DistProxy(const VectorDistBase<Storage, Bin> &s, int i) + : cstat(&s), index(i) {} + DistProxy(const DistProxy &sp) + : cstat(sp.cstat), index(sp.index) {} + const DistProxy &operator=(const DistProxy &sp) { + cstat = sp.cstat; index = sp.index; return *this; + } + + public: + template <typename U> + void sample(const U &v, int n = 1) { data()->sample(v, n, cstat->params); } + + size_t size() const { return 1; } + bool zero() const { return data()->zero(cstat->params); } + /** + * Return true if stat is binned. + *@return false since Proxies are not binned/printed. + */ + bool binned() const { return false; } + /** + * Proxy has no state. Nothing to reset. + */ + void reset() { } +}; + +template <class Storage, class Bin> +inline DistProxy<Storage, Bin> +VectorDistBase<Storage, Bin>::operator[](int index) +{ + assert (index >= 0 && index < size()); + return DistProxy<Storage, Bin>(*this, index); +} + +template <class Storage, class Bin> +inline const DistProxy<Storage, Bin> +VectorDistBase<Storage, Bin>::operator[](int index) const +{ + assert (index >= 0 && index < size()); + return DistProxy<Storage, Bin>(*this, index); +} + +#if 0 +template <class Storage, class Bin> +Result +VectorDistBase<Storage, Bin>::total(int index) const +{ + int total = 0; + for (int i=0; i < x_size(); ++i) { + total += data(i)->result(*params); + } +} +#endif + +////////////////////////////////////////////////////////////////////// +// +// Formula Details +// +////////////////////////////////////////////////////////////////////// + +/** + * Base class for formula statistic node. These nodes are used to build a tree + * that represents the formula. + */ +class Node : public RefCounted +{ + public: + /** + * Return the number of nodes in the subtree starting at this node. + * @return the number of nodes in this subtree. + */ + virtual size_t size() const = 0; + /** + * Return the result vector of this subtree. + * @return The result vector of this subtree. + */ + virtual const VResult &result() const = 0; + /** + * Return the total of the result vector. + * @return The total of the result vector. + */ + virtual Result total() const = 0; + /** + * Return true if stat is binned. + *@return True is stat is binned. + */ + virtual bool binned() const = 0; + + /** + * + */ + virtual std::string str() const = 0; +}; + +/** Reference counting pointer to a function Node. */ +typedef RefCountingPtr<Node> NodePtr; + +class ScalarStatNode : public Node +{ + private: + const ScalarData *data; + mutable VResult vresult; + + public: + ScalarStatNode(const ScalarData *d) : data(d), vresult(1) {} + virtual const VResult &result() const + { + vresult[0] = data->result(); + return vresult; + } + virtual Result total() const { return data->result(); }; + + virtual size_t size() const { return 1; } + /** + * Return true if stat is binned. + *@return True is stat is binned. + */ + virtual bool binned() const { return data->binned(); } + + /** + * + */ + virtual std::string str() const { return data->name; } +}; + +template <class Storage, class Bin> +class ScalarProxyNode : public Node +{ + private: + const ScalarProxy<Storage, Bin> proxy; + mutable VResult vresult; + + public: + ScalarProxyNode(const ScalarProxy<Storage, Bin> &p) + : proxy(p), vresult(1) { } + virtual const VResult &result() const + { + vresult[0] = proxy.result(); + return vresult; + } + virtual Result total() const { return proxy.result(); }; + + virtual size_t size() const { return 1; } + /** + * Return true if stat is binned. + *@return True is stat is binned. + */ + virtual bool binned() const { return proxy.binned(); } + + /** + * + */ + virtual std::string str() const { return proxy.str(); } +}; + +class VectorStatNode : public Node +{ + private: + const VectorData *data; + + public: + VectorStatNode(const VectorData *d) : data(d) { } + virtual const VResult &result() const { return data->result(); } + virtual Result total() const { return data->total(); }; + + virtual size_t size() const { return data->size(); } + /** + * Return true if stat is binned. + *@return True is stat is binned. + */ + virtual bool binned() const { return data->binned(); } + + virtual std::string str() const { return data->name; } +}; + +template <class T> +class ConstNode : public Node +{ + private: + VResult vresult; + + public: + ConstNode(T s) : vresult(1, (Result)s) {} + const VResult &result() const { return vresult; } + virtual Result total() const { return vresult[0]; }; + virtual size_t size() const { return 1; } + + /** + * Return true if stat is binned. + *@return False since constants aren't binned. + */ + virtual bool binned() const { return false; } + + virtual std::string str() const { return to_string(vresult[0]); } +}; + +template <class Op> +struct OpString; + +template<> +struct OpString<std::plus<Result> > +{ + static std::string str() { return "+"; } +}; + +template<> +struct OpString<std::minus<Result> > +{ + static std::string str() { return "-"; } +}; + +template<> +struct OpString<std::multiplies<Result> > +{ + static std::string str() { return "*"; } +}; + +template<> +struct OpString<std::divides<Result> > +{ + static std::string str() { return "/"; } +}; + +template<> +struct OpString<std::modulus<Result> > +{ + static std::string str() { return "%"; } +}; + +template<> +struct OpString<std::negate<Result> > +{ + static std::string str() { return "-"; } +}; + +template <class Op> +class UnaryNode : public Node +{ + public: + NodePtr l; + mutable VResult vresult; + + public: + UnaryNode(NodePtr &p) : l(p) {} + + const VResult &result() const + { + const VResult &lvec = l->result(); + int size = lvec.size(); + + assert(size > 0); + + vresult.resize(size); + Op op; + for (int i = 0; i < size; ++i) + vresult[i] = op(lvec[i]); + + return vresult; + } + + Result total() const { + Op op; + return op(l->total()); + } + + virtual size_t size() const { return l->size(); } + /** + * Return true if child of node is binned. + *@return True if child of node is binned. + */ + virtual bool binned() const { return l->binned(); } + + virtual std::string str() const + { + return OpString<Op>::str() + l->str(); + } +}; + +template <class Op> +class BinaryNode : public Node +{ + public: + NodePtr l; + NodePtr r; + mutable VResult vresult; + + public: + BinaryNode(NodePtr &a, NodePtr &b) : l(a), r(b) {} + + const VResult &result() const + { + Op op; + const VResult &lvec = l->result(); + const VResult &rvec = r->result(); + + assert(lvec.size() > 0 && rvec.size() > 0); + + if (lvec.size() == 1 && rvec.size() == 1) { + vresult.resize(1); + vresult[0] = op(lvec[0], rvec[0]); + } else if (lvec.size() == 1) { + int size = rvec.size(); + vresult.resize(size); + for (int i = 0; i < size; ++i) + vresult[i] = op(lvec[0], rvec[i]); + } else if (rvec.size() == 1) { + int size = lvec.size(); + vresult.resize(size); + for (int i = 0; i < size; ++i) + vresult[i] = op(lvec[i], rvec[0]); + } else if (rvec.size() == lvec.size()) { + int size = rvec.size(); + vresult.resize(size); + for (int i = 0; i < size; ++i) + vresult[i] = op(lvec[i], rvec[i]); + } + + return vresult; + } + + Result total() const { + Op op; + return op(l->total(), r->total()); + } + + virtual size_t size() const { + int ls = l->size(); + int rs = r->size(); + if (ls == 1) + return rs; + else if (rs == 1) + return ls; + else { + assert(ls == rs && "Node vector sizes are not equal"); + return ls; + } + } + /** + * Return true if any children of node are binned + *@return True if either child of node is binned. + */ + virtual bool binned() const { return (l->binned() || r->binned()); } + + virtual std::string str() const + { + return csprintf("(%s %s %s)", l->str(), OpString<Op>::str(), r->str()); + } +}; + +template <class Op> +class SumNode : public Node +{ + public: + NodePtr l; + mutable VResult vresult; + + public: + SumNode(NodePtr &p) : l(p), vresult(1) {} + + const VResult &result() const + { + const VResult &lvec = l->result(); + int size = lvec.size(); + assert(size > 0); + + vresult[0] = 0.0; + + Op op; + for (int i = 0; i < size; ++i) + vresult[0] = op(vresult[0], lvec[i]); + + return vresult; + } + + Result total() const + { + const VResult &lvec = l->result(); + int size = lvec.size(); + assert(size > 0); + + Result vresult = 0.0; + + Op op; + for (int i = 0; i < size; ++i) + vresult = op(vresult, lvec[i]); + + return vresult; + } + + virtual size_t size() const { return 1; } + /** + * Return true if child of node is binned. + *@return True if child of node is binned. + */ + virtual bool binned() const { return l->binned(); } + + virtual std::string str() const + { + return csprintf("total(%s)", l->str()); + } +}; + + +////////////////////////////////////////////////////////////////////// +// +// Visible Statistics Types +// +////////////////////////////////////////////////////////////////////// +/** + * @defgroup VisibleStats "Statistic Types" + * These are the statistics that are used in the simulator. By default these + * store counters and don't use binning, but are templatized to accept any type + * and any Bin class. + * @{ + */ + +/** + * This is an easy way to assign all your stats to be binned or not + * binned. If the typedef is NoBin, nothing is binned. If it is + * MainBin, then all stats are binned under that Bin. + */ +#if STATS_BINNING +typedef MainBin DefaultBin; +#else +typedef NoBin DefaultBin; +#endif + +/** + * This is a simple scalar statistic, like a counter. + * @sa Stat, ScalarBase, StatStor + */ +template <class Bin = DefaultBin> +class Scalar + : public Wrap<Scalar<Bin>, + ScalarBase<StatStor, Bin>, + ScalarStatData> +{ + public: + /** The base implementation. */ + typedef ScalarBase<StatStor, Bin> Base; + + Scalar() + { + this->setInit(); + } + + /** + * Sets the stat equal to the given value. Calls the base implementation + * of operator= + * @param v The new value. + */ + template <typename U> + void operator=(const U &v) { Base::operator=(v); } +}; + +class Value + : public Wrap<Value, + ValueBase, + ScalarStatData> +{ + public: + /** The base implementation. */ + typedef ValueBase Base; + + template <class T> + Value &scalar(T &value) + { + Base::scalar(value); + return *this; + } + + template <class T> + Value &functor(T &func) + { + Base::functor(func); + return *this; + } +}; + +/** + * A stat that calculates the per cycle average of a value. + * @sa Stat, ScalarBase, AvgStor + */ +template <class Bin = DefaultBin> +class Average + : public Wrap<Average<Bin>, + ScalarBase<AvgStor, Bin>, + ScalarStatData> +{ + public: + /** The base implementation. */ + typedef ScalarBase<AvgStor, Bin> Base; + + Average() + { + this->setInit(); + } + + /** + * Sets the stat equal to the given value. Calls the base implementation + * of operator= + * @param v The new value. + */ + template <typename U> + void operator=(const U &v) { Base::operator=(v); } +}; + +/** + * A vector of scalar stats. + * @sa Stat, VectorBase, StatStor + */ +template <class Bin = DefaultBin> +class Vector + : public WrapVec<Vector<Bin>, + VectorBase<StatStor, Bin>, + VectorStatData> +{ + public: + /** The base implementation. */ + typedef ScalarBase<StatStor, Bin> Base; + + /** + * Set this vector to have the given size. + * @param size The new size. + * @return A reference to this stat. + */ + Vector &init(size_t size) { + this->bin.init(size, this->params); + this->setInit(); + + return *this; + } +}; + +/** + * A vector of Average stats. + * @sa Stat, VectorBase, AvgStor + */ +template <class Bin = DefaultBin> +class AverageVector + : public WrapVec<AverageVector<Bin>, + VectorBase<AvgStor, Bin>, + VectorStatData> +{ + public: + /** + * Set this vector to have the given size. + * @param size The new size. + * @return A reference to this stat. + */ + AverageVector &init(size_t size) { + this->bin.init(size, this->params); + this->setInit(); + + return *this; + } +}; + +/** + * A 2-Dimensional vecto of scalar stats. + * @sa Stat, Vector2dBase, StatStor + */ +template <class Bin = DefaultBin> +class Vector2d + : public WrapVec2d<Vector2d<Bin>, + Vector2dBase<StatStor, Bin>, + Vector2dStatData> +{ + public: + Vector2d &init(size_t _x, size_t _y) { + this->statData()->x = this->x = _x; + this->statData()->y = this->y = _y; + this->bin.init(this->x * this->y, this->params); + this->setInit(); + + return *this; + } +}; + +/** + * A simple distribution stat. + * @sa Stat, DistBase, DistStor + */ +template <class Bin = DefaultBin> +class Distribution + : public Wrap<Distribution<Bin>, + DistBase<DistStor, Bin>, + DistStatData> +{ + public: + /** Base implementation. */ + typedef DistBase<DistStor, Bin> Base; + /** The Parameter type. */ + typedef typename DistStor::Params Params; + + public: + /** + * Set the parameters of this distribution. @sa DistStor::Params + * @param min The minimum value of the distribution. + * @param max The maximum value of the distribution. + * @param bkt The number of values in each bucket. + * @return A reference to this distribution. + */ + Distribution &init(Counter min, Counter max, Counter bkt) { + this->params.min = min; + this->params.max = max; + this->params.bucket_size = bkt; + this->params.size = (int)rint((max - min) / bkt + 1.0); + this->bin.init(this->params); + this->setInit(); + + return *this; + } +}; + +/** + * Calculates the mean and variance of all the samples. + * @sa Stat, DistBase, FancyStor + */ +template <class Bin = DefaultBin> +class StandardDeviation + : public Wrap<StandardDeviation<Bin>, + DistBase<FancyStor, Bin>, + DistStatData> +{ + public: + /** The base implementation */ + typedef DistBase<DistStor, Bin> Base; + /** The parameter type. */ + typedef typename DistStor::Params Params; + + public: + /** + * Construct and initialize this distribution. + */ + StandardDeviation() { + this->bin.init(this->params); + this->setInit(); + } +}; + +/** + * Calculates the per cycle mean and variance of the samples. + * @sa Stat, DistBase, AvgFancy + */ +template <class Bin = DefaultBin> +class AverageDeviation + : public Wrap<AverageDeviation<Bin>, + DistBase<AvgFancy, Bin>, + DistStatData> +{ + public: + /** The base implementation */ + typedef DistBase<DistStor, Bin> Base; + /** The parameter type. */ + typedef typename DistStor::Params Params; + + public: + /** + * Construct and initialize this distribution. + */ + AverageDeviation() + { + this->bin.init(this->params); + this->setInit(); + } +}; + +/** + * A vector of distributions. + * @sa Stat, VectorDistBase, DistStor + */ +template <class Bin = DefaultBin> +class VectorDistribution + : public WrapVec<VectorDistribution<Bin>, + VectorDistBase<DistStor, Bin>, + VectorDistStatData> +{ + public: + /** The base implementation */ + typedef VectorDistBase<DistStor, Bin> Base; + /** The parameter type. */ + typedef typename DistStor::Params Params; + + public: + /** + * Initialize storage and parameters for this distribution. + * @param size The size of the vector (the number of distributions). + * @param min The minimum value of the distribution. + * @param max The maximum value of the distribution. + * @param bkt The number of values in each bucket. + * @return A reference to this distribution. + */ + VectorDistribution &init(int size, Counter min, Counter max, Counter bkt) { + this->params.min = min; + this->params.max = max; + this->params.bucket_size = bkt; + this->params.size = (int)rint((max - min) / bkt + 1.0); + this->bin.init(size, this->params); + this->setInit(); + + return *this; + } +}; + +/** + * This is a vector of StandardDeviation stats. + * @sa Stat, VectorDistBase, FancyStor + */ +template <class Bin = DefaultBin> +class VectorStandardDeviation + : public WrapVec<VectorStandardDeviation<Bin>, + VectorDistBase<FancyStor, Bin>, + VectorDistStatData> +{ + public: + /** The base implementation */ + typedef VectorDistBase<FancyStor, Bin> Base; + /** The parameter type. */ + typedef typename DistStor::Params Params; + + public: + /** + * Initialize storage for this distribution. + * @param size The size of the vector. + * @return A reference to this distribution. + */ + VectorStandardDeviation &init(int size) { + this->bin.init(size, this->params); + this->setInit(); + + return *this; + } +}; + +/** + * This is a vector of AverageDeviation stats. + * @sa Stat, VectorDistBase, AvgFancy + */ +template <class Bin = DefaultBin> +class VectorAverageDeviation + : public WrapVec<VectorAverageDeviation<Bin>, + VectorDistBase<AvgFancy, Bin>, + VectorDistStatData> +{ + public: + /** The base implementation */ + typedef VectorDistBase<AvgFancy, Bin> Base; + /** The parameter type. */ + typedef typename DistStor::Params Params; + + public: + /** + * Initialize storage for this distribution. + * @param size The size of the vector. + * @return A reference to this distribution. + */ + VectorAverageDeviation &init(int size) { + this->bin.init(size, this->params); + this->setInit(); + + return *this; + } +}; + +/** + * A formula for statistics that is calculated when printed. A formula is + * stored as a tree of Nodes that represent the equation to calculate. + * @sa Stat, ScalarStat, VectorStat, Node, Temp + */ +class FormulaBase : public DataAccess +{ + protected: + /** The root of the tree which represents the Formula */ + NodePtr root; + friend class Temp; + + public: + /** + * Return the result of the Fomula in a vector. If there were no Vector + * components to the Formula, then the vector is size 1. If there were, + * like x/y with x being a vector of size 3, then the result returned will + * be x[0]/y, x[1]/y, x[2]/y, respectively. + * @return The result vector. + */ + void result(VResult &vec) const; + + /** + * Return the total Formula result. If there is a Vector + * component to this Formula, then this is the result of the + * Formula if the formula is applied after summing all the + * components of the Vector. For example, if Formula is x/y where + * x is size 3, then total() will return (x[1]+x[2]+x[3])/y. If + * there is no Vector component, total() returns the same value as + * the first entry in the VResult val() returns. + * @return The total of the result vector. + */ + Result total() const; + + /** + * Return the number of elements in the tree. + */ + size_t size() const; + + /** + * Return true if Formula is binned. i.e. any of its children + * nodes are binned + * @return True if Formula is binned. + */ + bool binned() const; + + bool check() const { return true; } + + /** + * Formulas don't need to be reset + */ + void reset(); + + /** + * + */ + bool zero() const; + + /** + * + */ + void update(StatData *); + + std::string str() const; +}; + +class FormulaData : public VectorData +{ + public: + virtual std::string str() const = 0; + virtual bool check() const { return true; } +}; + +template <class Stat> +class FormulaStatData : public FormulaData +{ + protected: + Stat &s; + mutable VResult vec; + mutable VCounter cvec; + + public: + FormulaStatData(Stat &stat) : s(stat) {} + + virtual bool binned() const { return s.binned(); } + virtual bool zero() const { return s.zero(); } + virtual void reset() { s.reset(); } + + virtual size_t size() const { return s.size(); } + virtual const VResult &result() const + { + s.result(vec); + return vec; + } + virtual Result total() const { return s.total(); } + virtual VCounter &value() const { return cvec; } + virtual void visit(Visit &visitor) + { + update(); + s.update(this); + visitor.visit(*this); + } + virtual std::string str() const { return s.str(); } +}; + +class Temp; +class Formula + : public WrapVec<Formula, + FormulaBase, + FormulaStatData> +{ + public: + /** + * Create and initialize thie formula, and register it with the database. + */ + Formula(); + + /** + * Create a formula with the given root node, register it with the + * database. + * @param r The root of the expression tree. + */ + Formula(Temp r); + + /** + * Set an unitialized Formula to the given root. + * @param r The root of the expression tree. + * @return a reference to this formula. + */ + const Formula &operator=(Temp r); + + /** + * Add the given tree to the existing one. + * @param r The root of the expression tree. + * @return a reference to this formula. + */ + const Formula &operator+=(Temp r); +}; + +class FormulaNode : public Node +{ + private: + const Formula &formula; + mutable VResult vec; + + public: + FormulaNode(const Formula &f) : formula(f) {} + + virtual size_t size() const { return formula.size(); } + virtual const VResult &result() const { formula.result(vec); return vec; } + virtual Result total() const { return formula.total(); } + virtual bool binned() const { return formula.binned(); } + + virtual std::string str() const { return formula.str(); } +}; + +/** + * Helper class to construct formula node trees. + */ +class Temp +{ + protected: + /** + * Pointer to a Node object. + */ + NodePtr node; + + public: + /** + * Copy the given pointer to this class. + * @param n A pointer to a Node object to copy. + */ + Temp(NodePtr n) : node(n) { } + + /** + * Return the node pointer. + * @return the node pointer. + */ + operator NodePtr&() { return node;} + + public: + /** + * Create a new ScalarStatNode. + * @param s The ScalarStat to place in a node. + */ + template <class Bin> + Temp(const Scalar<Bin> &s) + : node(new ScalarStatNode(s.statData())) { } + + /** + * Create a new ScalarStatNode. + * @param s The ScalarStat to place in a node. + */ + Temp(const Value &s) + : node(new ScalarStatNode(s.statData())) { } + + /** + * Create a new ScalarStatNode. + * @param s The ScalarStat to place in a node. + */ + template <class Bin> + Temp(const Average<Bin> &s) + : node(new ScalarStatNode(s.statData())) { } + + /** + * Create a new VectorStatNode. + * @param s The VectorStat to place in a node. + */ + template <class Bin> + Temp(const Vector<Bin> &s) + : node(new VectorStatNode(s.statData())) { } + + /** + * + */ + Temp(const Formula &f) + : node(new FormulaNode(f)) { } + + /** + * Create a new ScalarProxyNode. + * @param p The ScalarProxy to place in a node. + */ + template <class Storage, class Bin> + Temp(const ScalarProxy<Storage, Bin> &p) + : node(new ScalarProxyNode<Storage, Bin>(p)) { } + + /** + * Create a ConstNode + * @param value The value of the const node. + */ + Temp(signed char value) + : node(new ConstNode<signed char>(value)) {} + + /** + * Create a ConstNode + * @param value The value of the const node. + */ + Temp(unsigned char value) + : node(new ConstNode<unsigned char>(value)) {} + + /** + * Create a ConstNode + * @param value The value of the const node. + */ + Temp(signed short value) + : node(new ConstNode<signed short>(value)) {} + + /** + * Create a ConstNode + * @param value The value of the const node. + */ + Temp(unsigned short value) + : node(new ConstNode<unsigned short>(value)) {} + + /** + * Create a ConstNode + * @param value The value of the const node. + */ + Temp(signed int value) + : node(new ConstNode<signed int>(value)) {} + + /** + * Create a ConstNode + * @param value The value of the const node. + */ + Temp(unsigned int value) + : node(new ConstNode<unsigned int>(value)) {} + + /** + * Create a ConstNode + * @param value The value of the const node. + */ + Temp(signed long value) + : node(new ConstNode<signed long>(value)) {} + + /** + * Create a ConstNode + * @param value The value of the const node. + */ + Temp(unsigned long value) + : node(new ConstNode<unsigned long>(value)) {} + + /** + * Create a ConstNode + * @param value The value of the const node. + */ + Temp(signed long long value) + : node(new ConstNode<signed long long>(value)) {} + + /** + * Create a ConstNode + * @param value The value of the const node. + */ + Temp(unsigned long long value) + : node(new ConstNode<unsigned long long>(value)) {} + + /** + * Create a ConstNode + * @param value The value of the const node. + */ + Temp(float value) + : node(new ConstNode<float>(value)) {} + + /** + * Create a ConstNode + * @param value The value of the const node. + */ + Temp(double value) + : node(new ConstNode<double>(value)) {} +}; + + +/** + * @} + */ + +void check(); +void reset(); +void registerResetCallback(Callback *cb); + +inline Temp +operator+(Temp l, Temp r) +{ + return NodePtr(new BinaryNode<std::plus<Result> >(l, r)); +} + +inline Temp +operator-(Temp l, Temp r) +{ + return NodePtr(new BinaryNode<std::minus<Result> >(l, r)); +} + +inline Temp +operator*(Temp l, Temp r) +{ + return NodePtr(new BinaryNode<std::multiplies<Result> >(l, r)); +} + +inline Temp +operator/(Temp l, Temp r) +{ + return NodePtr(new BinaryNode<std::divides<Result> >(l, r)); +} + +inline Temp +operator-(Temp l) +{ + return NodePtr(new UnaryNode<std::negate<Result> >(l)); +} + +template <typename T> +inline Temp +constant(T val) +{ + return NodePtr(new ConstNode<T>(val)); +} + +inline Temp +sum(Temp val) +{ + return NodePtr(new SumNode<std::plus<Result> >(val)); +} + +/* namespace Stats */ } + +#endif // __BASE_STATISTICS_HH__ diff --git a/base/stats/events.cc b/src/base/stats/events.cc index 3191aec13..3191aec13 100644 --- a/base/stats/events.cc +++ b/src/base/stats/events.cc diff --git a/base/stats/events.hh b/src/base/stats/events.hh index 2a23240b4..2a23240b4 100644 --- a/base/stats/events.hh +++ b/src/base/stats/events.hh diff --git a/base/stats/flags.hh b/src/base/stats/flags.hh index 00db95bc1..00db95bc1 100644 --- a/base/stats/flags.hh +++ b/src/base/stats/flags.hh diff --git a/base/stats/mysql.cc b/src/base/stats/mysql.cc index 6d12b4fc1..6d12b4fc1 100644 --- a/base/stats/mysql.cc +++ b/src/base/stats/mysql.cc diff --git a/base/stats/mysql.hh b/src/base/stats/mysql.hh index 25ea22b97..25ea22b97 100644 --- a/base/stats/mysql.hh +++ b/src/base/stats/mysql.hh diff --git a/base/stats/mysql_run.hh b/src/base/stats/mysql_run.hh index d8dcb7594..d8dcb7594 100644 --- a/base/stats/mysql_run.hh +++ b/src/base/stats/mysql_run.hh diff --git a/base/stats/output.hh b/src/base/stats/output.hh index ee6b38d63..ee6b38d63 100644 --- a/base/stats/output.hh +++ b/src/base/stats/output.hh diff --git a/base/stats/statdb.cc b/src/base/stats/statdb.cc index a6b00ab8a..a6b00ab8a 100644 --- a/base/stats/statdb.cc +++ b/src/base/stats/statdb.cc diff --git a/base/stats/statdb.hh b/src/base/stats/statdb.hh index eb56d8fac..eb56d8fac 100644 --- a/base/stats/statdb.hh +++ b/src/base/stats/statdb.hh diff --git a/src/base/stats/text.cc b/src/base/stats/text.cc new file mode 100644 index 000000000..300737c60 --- /dev/null +++ b/src/base/stats/text.cc @@ -0,0 +1,736 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(__APPLE__) +#define _GLIBCPP_USE_C99 1 +#endif + +#include <iostream> +#include <sstream> +#include <fstream> +#include <string> + +#include "base/misc.hh" +#include "base/statistics.hh" +#include "base/stats/statdb.hh" +#include "base/stats/text.hh" +#include "base/stats/visit.hh" + +using namespace std; + +#ifndef NAN +float __nan(); +/** Define Not a number. */ +#define NAN (__nan()) +/** Need to define __nan() */ +#define __M5_NAN +#endif + +#ifdef __M5_NAN +float +__nan() +{ + union { + uint32_t ui; + float f; + } nan; + + nan.ui = 0x7fc00000; + return nan.f; +} +#endif + +namespace Stats { + +Text::Text() + : mystream(false), stream(NULL), compat(false), descriptions(false) +{ +} + +Text::Text(std::ostream &stream) + : mystream(false), stream(NULL), compat(false), descriptions(false) +{ + open(stream); +} + +Text::Text(const std::string &file) + : mystream(false), stream(NULL), compat(false), descriptions(false) +{ + open(file); +} + + +Text::~Text() +{ + if (mystream) { + assert(stream); + delete stream; + } +} + +void +Text::open(std::ostream &_stream) +{ + if (stream) + panic("stream already set!"); + + mystream = false; + stream = &_stream; + assert(valid()); +} + +void +Text::open(const std::string &file) +{ + if (stream) + panic("stream already set!"); + + mystream = true; + stream = new ofstream(file.c_str(), ios::trunc); + assert(valid()); +} + +bool +Text::valid() const +{ + return stream != NULL; +} + +void +Text::output() +{ + using namespace Database; + + ccprintf(*stream, "\n---------- Begin Simulation Statistics ----------\n"); + if (bins().empty() || bins().size() == 1) { + stat_list_t::const_iterator i, end = stats().end(); + for (i = stats().begin(); i != end; ++i) + (*i)->visit(*this); + } else { + ccprintf(*stream, "PRINTING BINNED STATS\n"); + bin_list_t::iterator i, end = bins().end(); + for (i = bins().begin(); i != end; ++i) { + MainBin *bin = *i; + bin->activate(); + ccprintf(*stream,"---%s Bin------------\n", bin->name()); + stat_list_t::const_iterator i, end = stats().end(); + for (i = stats().begin(); i != end; ++i) + (*i)->visit(*this); + ccprintf(*stream, "---------------------------------\n"); + } + } + ccprintf(*stream, "\n---------- End Simulation Statistics ----------\n"); + stream->flush(); +} + +bool +Text::noOutput(const StatData &data) +{ + if (!(data.flags & print)) + return true; + + if (data.prereq && data.prereq->zero()) + return true; + + return false; +} + +string +ValueToString(Result value, int precision, bool compat) +{ + stringstream val; + + if (!isnan(value)) { + if (precision != -1) + val.precision(precision); + else if (value == rint(value)) + val.precision(0); + + val.unsetf(ios::showpoint); + val.setf(ios::fixed); + val << value; + } else { + val << (compat ? "<err: div-0>" : "no value"); + } + + return val.str(); +} + +struct ScalarPrint +{ + Result value; + string name; + string desc; + StatFlags flags; + bool compat; + bool descriptions; + int precision; + Result pdf; + Result cdf; + + void operator()(ostream &stream) const; +}; + +void +ScalarPrint::operator()(ostream &stream) const +{ + if (flags & nozero && value == 0.0 || + flags & nonan && isnan(value)) + return; + + stringstream pdfstr, cdfstr; + + if (!isnan(pdf)) + ccprintf(pdfstr, "%.2f%%", pdf * 100.0); + + if (!isnan(cdf)) + ccprintf(cdfstr, "%.2f%%", cdf * 100.0); + + if (compat && flags & __substat) { + ccprintf(stream, "%32s %12s %10s %10s", name, + ValueToString(value, precision, compat), pdfstr, cdfstr); + } else { + ccprintf(stream, "%-40s %12s %10s %10s", name, + ValueToString(value, precision, compat), pdfstr, cdfstr); + } + + if (descriptions) { + if (!desc.empty()) + ccprintf(stream, " # %s", desc); + } + stream << endl; +} + +struct VectorPrint +{ + string name; + string desc; + vector<string> subnames; + vector<string> subdescs; + StatFlags flags; + bool compat; + bool descriptions; + int precision; + VResult vec; + Result total; + + void operator()(ostream &stream) const; +}; + +void +VectorPrint::operator()(std::ostream &stream) const +{ + int _size = vec.size(); + Result _total = 0.0; + + if (flags & (pdf | cdf)) { + for (int i = 0; i < _size; ++i) { + _total += vec[i]; + } + } + + string base = name + (compat ? "_" : "::"); + + ScalarPrint print; + print.name = name; + print.desc = desc; + print.precision = precision; + print.descriptions = descriptions; + print.flags = flags; + print.pdf = NAN; + print.cdf = NAN; + + bool havesub = !subnames.empty(); + + if (_size == 1) { + print.value = vec[0]; + print(stream); + } else if (!compat) { + for (int i = 0; i < _size; ++i) { + if (havesub && (i >= subnames.size() || subnames[i].empty())) + continue; + + print.name = base + (havesub ? subnames[i] : to_string(i)); + print.desc = subdescs.empty() ? desc : subdescs[i]; + print.value = vec[i]; + + if (_total && (flags & pdf)) { + print.pdf = vec[i] / _total; + print.cdf += print.pdf; + } + + print(stream); + } + + if (flags & ::Stats::total) { + print.name = base + "total"; + print.desc = desc; + print.value = total; + print(stream); + } + } else { + if (flags & ::Stats::total) { + print.value = total; + print(stream); + } + + Result _pdf = 0.0; + Result _cdf = 0.0; + if (flags & dist) { + ccprintf(stream, "%s.start_dist\n", name); + for (int i = 0; i < _size; ++i) { + print.name = havesub ? subnames[i] : to_string(i); + print.desc = subdescs.empty() ? desc : subdescs[i]; + print.flags |= __substat; + print.value = vec[i]; + + if (_total) { + _pdf = vec[i] / _total; + _cdf += _pdf; + } + + if (flags & pdf) + print.pdf = _pdf; + if (flags & cdf) + print.cdf = _cdf; + + print(stream); + } + ccprintf(stream, "%s.end_dist\n", name); + } else { + for (int i = 0; i < _size; ++i) { + if (havesub && subnames[i].empty()) + continue; + + print.name = base; + print.name += havesub ? subnames[i] : to_string(i); + print.desc = subdescs.empty() ? desc : subdescs[i]; + print.value = vec[i]; + + if (_total) { + _pdf = vec[i] / _total; + _cdf += _pdf; + } else { + _pdf = _cdf = NAN; + } + + if (flags & pdf) { + print.pdf = _pdf; + print.cdf = _cdf; + } + + print(stream); + } + } + } +} + +struct DistPrint +{ + string name; + string desc; + StatFlags flags; + bool compat; + bool descriptions; + int precision; + + Result min_val; + Result max_val; + Result underflow; + Result overflow; + VResult vec; + Result sum; + Result squares; + Result samples; + + Counter min; + Counter max; + Counter bucket_size; + int size; + bool fancy; + + void operator()(ostream &stream) const; +}; + +void +DistPrint::operator()(ostream &stream) const +{ + if (fancy) { + ScalarPrint print; + string base = name + (compat ? "_" : "::"); + + print.precision = precision; + print.flags = flags; + print.compat = compat; + print.descriptions = descriptions; + print.desc = desc; + print.pdf = NAN; + print.cdf = NAN; + + print.name = base + "mean"; + print.value = samples ? sum / samples : NAN; + print(stream); + + print.name = base + "stdev"; + print.value = samples ? sqrt((samples * squares - sum * sum) / + (samples * (samples - 1.0))) : NAN; + print(stream); + + print.name = "**Ignore: " + base + "TOT"; + print.value = samples; + print(stream); + return; + } + + assert(size == vec.size()); + + Result total = 0.0; + + total += underflow; + for (int i = 0; i < size; ++i) + total += vec[i]; + total += overflow; + + string base = name + (compat ? "." : "::"); + + ScalarPrint print; + print.desc = compat ? "" : desc; + print.flags = flags; + print.compat = compat; + print.descriptions = descriptions; + print.precision = precision; + print.pdf = NAN; + print.cdf = NAN; + + if (compat) { + ccprintf(stream, "%-42s", base + "start_dist"); + if (descriptions && !desc.empty()) + ccprintf(stream, " # %s", desc); + stream << endl; + } + + print.name = base + "samples"; + print.value = samples; + print(stream); + + print.name = base + "min_value"; + print.value = min_val; + print(stream); + + if (!compat || underflow > 0.0) { + print.name = base + "underflows"; + print.value = underflow; + if (!compat && total) { + print.pdf = underflow / total; + print.cdf += print.pdf; + } + print(stream); + } + + + if (!compat) { + for (int i = 0; i < size; ++i) { + stringstream namestr; + namestr << name; + + Counter low = i * bucket_size + min; + Counter high = ::min(low + bucket_size, max); + namestr << low; + if (low < high) + namestr << "-" << high; + + print.name = namestr.str(); + print.value = vec[i]; + if (total) { + print.pdf = vec[i] / total; + print.cdf += print.pdf; + } + print(stream); + } + + } else { + Counter _min; + Result _pdf; + Result _cdf = 0.0; + + print.flags = flags | __substat; + + for (int i = 0; i < size; ++i) { + if (flags & nozero && vec[i] == 0.0 || + flags & nonan && isnan(vec[i])) + continue; + + _min = i * bucket_size + min; + _pdf = vec[i] / total * 100.0; + _cdf += _pdf; + + + print.name = ValueToString(_min, 0, compat); + print.value = vec[i]; + print.pdf = (flags & pdf) ? _pdf : NAN; + print.cdf = (flags & cdf) ? _cdf : NAN; + print(stream); + } + + print.flags = flags; + } + + if (!compat || overflow > 0.0) { + print.name = base + "overflows"; + print.value = overflow; + if (!compat && total) { + print.pdf = overflow / total; + print.cdf += print.pdf; + } else { + print.pdf = NAN; + print.cdf = NAN; + } + print(stream); + } + + print.pdf = NAN; + print.cdf = NAN; + + if (!compat) { + print.name = base + "total"; + print.value = total; + print(stream); + } + + print.name = base + "max_value"; + print.value = max_val; + print(stream); + + if (!compat && samples != 0) { + print.name = base + "mean"; + print.value = sum / samples; + print(stream); + + print.name = base + "stdev"; + print.value = sqrt((samples * squares - sum * sum) / + (samples * (samples - 1.0))); + print(stream); + } + + if (compat) + ccprintf(stream, "%send_dist\n\n", base); +} + +void +Text::visit(const ScalarData &data) +{ + if (noOutput(data)) + return; + + ScalarPrint print; + print.value = data.result(); + print.name = data.name; + print.desc = data.desc; + print.flags = data.flags; + print.compat = compat; + print.descriptions = descriptions; + print.precision = data.precision; + print.pdf = NAN; + print.cdf = NAN; + + print(*stream); +} + +void +Text::visit(const VectorData &data) +{ + if (noOutput(data)) + return; + + int size = data.size(); + VectorPrint print; + + print.name = data.name; + print.desc = data.desc; + print.flags = data.flags; + print.compat = compat; + print.descriptions = descriptions; + print.precision = data.precision; + print.vec = data.result(); + print.total = data.total(); + + if (!data.subnames.empty()) { + for (int i = 0; i < size; ++i) { + if (!data.subnames[i].empty()) { + print.subnames = data.subnames; + print.subnames.resize(size); + for (int i = 0; i < size; ++i) { + if (!data.subnames[i].empty() && + !data.subdescs[i].empty()) { + print.subdescs = data.subdescs; + print.subdescs.resize(size); + break; + } + } + break; + } + } + } + + print(*stream); +} + +void +Text::visit(const Vector2dData &data) +{ + if (noOutput(data)) + return; + + bool havesub = false; + VectorPrint print; + + print.subnames = data.y_subnames; + print.flags = data.flags; + print.compat = compat; + print.descriptions = descriptions; + print.precision = data.precision; + + if (!data.subnames.empty()) { + for (int i = 0; i < data.x; ++i) + if (!data.subnames[i].empty()) + havesub = true; + } + + VResult tot_vec(data.y); + Result super_total = 0.0; + for (int i = 0; i < data.x; ++i) { + if (havesub && (i >= data.subnames.size() || data.subnames[i].empty())) + continue; + + int iy = i * data.y; + VResult yvec(data.y); + + Result total = 0.0; + for (int j = 0; j < data.y; ++j) { + yvec[j] = data.cvec[iy + j]; + tot_vec[j] += yvec[j]; + total += yvec[j]; + super_total += yvec[j]; + } + + print.name = data.name + "_" + (havesub ? data.subnames[i] : to_string(i)); + print.desc = data.desc; + print.vec = yvec; + print.total = total; + print(*stream); + } + + if ((data.flags & ::Stats::total) && (data.x > 1)) { + print.name = data.name; + print.desc = data.desc; + print.vec = tot_vec; + print.total = super_total; + print(*stream); + } +} + +void +Text::visit(const DistData &data) +{ + if (noOutput(data)) + return; + + DistPrint print; + + print.name = data.name; + print.desc = data.desc; + print.flags = data.flags; + print.compat = compat; + print.descriptions = descriptions; + print.precision = data.precision; + + print.min_val = data.data.min_val; + print.max_val = data.data.max_val; + print.underflow = data.data.underflow; + print.overflow = data.data.overflow; + print.vec.resize(data.data.cvec.size()); + for (int i = 0; i < print.vec.size(); ++i) + print.vec[i] = (Result)data.data.cvec[i]; + print.sum = data.data.sum; + print.squares = data.data.squares; + print.samples = data.data.samples; + + print.min = data.data.min; + print.max = data.data.max; + print.bucket_size = data.data.bucket_size; + print.size = data.data.size; + print.fancy = data.data.fancy; + + print(*stream); +} + +void +Text::visit(const VectorDistData &data) +{ + if (noOutput(data)) + return; + + for (int i = 0; i < data.size(); ++i) { + DistPrint print; + + print.name = data.name + + (data.subnames[i].empty() ? ("_" + to_string(i)) : data.subnames[i]); + print.desc = data.subdescs[i].empty() ? data.desc : data.subdescs[i]; + print.flags = data.flags; + print.compat = compat; + print.descriptions = descriptions; + print.precision = data.precision; + + print.min_val = data.data[i].min_val; + print.max_val = data.data[i].max_val; + print.underflow = data.data[i].underflow; + print.overflow = data.data[i].overflow; + print.vec.resize(data.data[i].cvec.size()); + for (int j = 0; j < print.vec.size(); ++j) + print.vec[j] = (Result)data.data[i].cvec[j]; + print.sum = data.data[i].sum; + print.squares = data.data[i].squares; + print.samples = data.data[i].samples; + + print.min = data.data[i].min; + print.max = data.data[i].max; + print.bucket_size = data.data[i].bucket_size; + print.size = data.data[i].size; + print.fancy = data.data[i].fancy; + + print(*stream); + } +} + +void +Text::visit(const FormulaData &data) +{ + visit((const VectorData &)data); +} + +/* namespace Stats */ } diff --git a/base/stats/text.hh b/src/base/stats/text.hh index 125cb79fa..125cb79fa 100644 --- a/base/stats/text.hh +++ b/src/base/stats/text.hh diff --git a/base/stats/types.hh b/src/base/stats/types.hh index 57f1564a5..57f1564a5 100644 --- a/base/stats/types.hh +++ b/src/base/stats/types.hh diff --git a/base/stats/visit.cc b/src/base/stats/visit.cc index dd4d49502..dd4d49502 100644 --- a/base/stats/visit.cc +++ b/src/base/stats/visit.cc diff --git a/base/stats/visit.hh b/src/base/stats/visit.hh index c0593c670..c0593c670 100644 --- a/base/stats/visit.hh +++ b/src/base/stats/visit.hh diff --git a/base/str.cc b/src/base/str.cc index 5f7f50286..5f7f50286 100644 --- a/base/str.cc +++ b/src/base/str.cc diff --git a/base/str.hh b/src/base/str.hh index 79e33a1be..79e33a1be 100644 --- a/base/str.hh +++ b/src/base/str.hh diff --git a/base/time.cc b/src/base/time.cc index 5827c9a85..5827c9a85 100644 --- a/base/time.cc +++ b/src/base/time.cc diff --git a/base/time.hh b/src/base/time.hh index 5731e3029..5731e3029 100644 --- a/base/time.hh +++ b/src/base/time.hh diff --git a/base/timebuf.hh b/src/base/timebuf.hh index f6b5b2781..f6b5b2781 100644 --- a/base/timebuf.hh +++ b/src/base/timebuf.hh diff --git a/base/trace.cc b/src/base/trace.cc index 90db7f045..90db7f045 100644 --- a/base/trace.cc +++ b/src/base/trace.cc diff --git a/base/trace.hh b/src/base/trace.hh index 5e14f1bff..5e14f1bff 100644 --- a/base/trace.hh +++ b/src/base/trace.hh diff --git a/src/base/traceflags.py b/src/base/traceflags.py new file mode 100644 index 000000000..9797e4cb7 --- /dev/null +++ b/src/base/traceflags.py @@ -0,0 +1,289 @@ +#!/usr/bin/env python + +# Copyright (c) 2004-2005 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# +# This file generates the header and source files for the flags +# that control the tracing facility. +# + +import sys + +if len(sys.argv) != 2: + print "%s: Need argument (basename of cc/hh files)" % sys.argv[0] + sys.exit(1) + +hhfilename = sys.argv[1] + '.hh' +ccfilename = sys.argv[1] + '.cc' + +# +# The list of trace flags that can be used to condition DPRINTFs etc. +# To define a new flag, simply add it to this list. +# +baseFlags = [ + 'AlphaConsole', + 'BADADDR', + 'BPredRAS', + 'Bus', + 'BusAddrRanges', + 'BusBridge', + 'Cache', + 'Chains', + 'Clock', + 'Commit', + 'CommitRate', + 'Config', + 'Console', + 'ConsolePoll', + 'ConsoleVerbose', + 'Context', + 'Cycle', + 'DMA', + 'DMAReadVerbose', + 'DMAWriteVerbose', + 'DebugPrintf', + 'Decode', + 'DiskImage', + 'DiskImageRead', + 'DiskImageWrite', + 'DynInst', + 'Ethernet', + 'EthernetCksum', + 'EthernetDMA', + 'EthernetData', + 'EthernetDesc', + 'EthernetIntr', + 'EthernetPIO', + 'EthernetSM', + 'Event', + 'Fault', + 'Fetch', + 'Flow', + 'FreeList', + 'FullCPU', + 'GDBAcc', + 'GDBExtra', + 'GDBMisc', + 'GDBRead', + 'GDBRecv', + 'GDBSend', + 'GDBWrite', + 'HWPrefetch', + 'IEW', + 'IIC', + 'IICMore', + 'IPI', + 'IQ', + 'ISP', + 'IdeCtrl', + 'IdeDisk', + 'InstExec', + 'Interrupt', + 'LSQ', + 'LSQUnit', + 'Loader', + 'MC146818', + 'MMU', + 'MSHR', + 'Mbox', + 'MemDepUnit', + 'OzoneCPU', + 'FE', + 'IBE', + 'BE', + 'OzoneLSQ', + ] + +# +# "Compound" flags correspond to a set of base flags. These exist +# solely for convenience in setting them via the command line: if a +# compound flag is specified, all of the corresponding base flags are +# set. Compound flags cannot be used directly in DPRINTFs etc. +# To define a new compound flag, add a new entry to this hash +# following the existing examples. +# +compoundFlagMap = { + 'GDBAll' : [ 'GDBMisc', 'GDBAcc', 'GDBRead', 'GDBWrite', 'GDBSend', 'GDBRecv', 'GDBExtra' ], + 'ScsiAll' : [ 'ScsiDisk', 'ScsiCtrl', 'ScsiNone' ], + 'DiskImageAll' : [ 'DiskImage', 'DiskImageRead', 'DiskImageWrite' ], + 'EthernetAll' : [ 'Ethernet', 'EthernetPIO', 'EthernetDMA', 'EthernetData' , 'EthernetDesc', 'EthernetIntr', 'EthernetSM', 'EthernetCksum' ], + 'EthernetNoData' : [ 'Ethernet', 'EthernetPIO', 'EthernetDesc', 'EthernetIntr', 'EthernetSM', 'EthernetCksum' ], + 'IdeAll' : [ 'IdeCtrl', 'IdeDisk' ], + 'FullCPUAll' : [ 'Fetch', 'Decode', 'Rename', 'IEW', 'Commit', 'IQ', 'ROB', 'FreeList', 'RenameMap', 'LSQ', 'LSQUnit', 'StoreSet', 'MemDepUnit', 'DynInst', 'FullCPU', 'Activity','Scoreboard','Writeback'], + 'OzoneCPUAll' : [ 'BE', 'FE', 'IBE', 'OzoneLSQ', 'OzoneCPU'] +} + +############################################################# +# +# Everything below this point generates the appropriate C++ +# declarations and definitions for the trace flags. If you are simply +# adding or modifying flag definitions, you should not have to change +# anything below. +# + +import sys + +# extract just the compound flag names into a list +compoundFlags = [] +compoundFlags.extend(compoundFlagMap.keys()) +compoundFlags.sort() + +# +# First generate the header file. This defines the Flag enum +# and some extern declarations for the .cc file. +# +try: + hhfile = file(hhfilename, 'w') +except IOError, e: + sys.exit("can't open %s: %s" % (hhfilename, e)) + +# file header boilerplate +print >>hhfile, ''' +/* + * DO NOT EDIT THIS FILE! + * + * Automatically generated from traceflags.py + */ + +#ifndef __BASE_TRACE_FLAGS_HH__ +#define __BASE_TRACE_FLAGS_HH__ + +namespace Trace { + +enum Flags { +''', + +# Generate the enum. Base flags come first, then compound flags. +idx = 0 +for flag in baseFlags: + print >>hhfile, ' %s = %d,' % (flag, idx) + idx += 1 + +numBaseFlags = idx +print >>hhfile, ' NumFlags = %d,' % idx + +# put a comment in here to separate base from compound flags +print >>hhfile, ''' + // The remaining enum values are *not* valid indices for Trace::flags. + // They are "compound" flags, which correspond to sets of base + // flags, and are used only by TraceParamContext::setFlags(). +''', + +for flag in compoundFlags: + print >>hhfile, ' %s = %d,' % (flag, idx) + idx += 1 + +numCompoundFlags = idx - numBaseFlags +print >>hhfile, ' NumCompoundFlags = %d' % numCompoundFlags + +# trailer boilerplate +print >>hhfile, '''\ +}; // enum Flags + +// Array of strings for SimpleEnumParam +extern const char *flagStrings[]; +extern const int numFlagStrings; + +// Array of arraay pointers: for each compound flag, gives the list of +// base flags to set. Inidividual flag arrays are terminated by -1. +extern const Flags *compoundFlags[]; + +/* namespace Trace */ } + +#endif // __BASE_TRACE_FLAGS_HH__ +''', + +hhfile.close() + +# +# +# Print out .cc file with array definitions. +# +# +try: + ccfile = file(ccfilename, 'w') +except OSError, e: + sys.exit("can't open %s: %s" % (ccfilename, e)) + +# file header +print >>ccfile, ''' +/* + * DO NOT EDIT THIS FILE! + * + * Automatically generated from traceflags.pl. + */ + +#include "base/traceflags.hh" + +using namespace Trace; + +const char *Trace::flagStrings[] = +{ +''', + +# The string array is used by SimpleEnumParam to map the strings +# provided by the user to enum values. +for flag in baseFlags: + print >>ccfile, ' "%s",' % flag + +for flag in compoundFlags: + print >>ccfile, ' "%s",' % flag + +print >>ccfile, '};\n' + +numFlagStrings = len(baseFlags) + len(compoundFlags); + +print >>ccfile, 'const int Trace::numFlagStrings = %d;' % numFlagStrings +print >>ccfile + +# +# Now define the individual compound flag arrays. There is an array +# for each compound flag listing the component base flags. +# + +for flag in compoundFlags: + flags = compoundFlagMap[flag] + flags.append('(Flags)-1') + print >>ccfile, 'static const Flags %sMap[] =' % flag + print >>ccfile, '{ %s };' % (', '.join(flags)) + print >>ccfile + +# +# Finally the compoundFlags[] array maps the compound flags +# to their individual arrays/ +# +print >>ccfile, 'const Flags *Trace::compoundFlags[] =' +print >>ccfile, '{' + +for flag in compoundFlags: + print >>ccfile, ' %sMap,' % flag + +# file trailer +print >>ccfile, '};' + +ccfile.close() + diff --git a/base/userinfo.cc b/src/base/userinfo.cc index 15bd72224..15bd72224 100644 --- a/base/userinfo.cc +++ b/src/base/userinfo.cc diff --git a/base/userinfo.hh b/src/base/userinfo.hh index d8ebd443c..d8ebd443c 100644 --- a/base/userinfo.hh +++ b/src/base/userinfo.hh diff --git a/src/cpu/SConscript b/src/cpu/SConscript new file mode 100644 index 000000000..a4cbe2aa6 --- /dev/null +++ b/src/cpu/SConscript @@ -0,0 +1,179 @@ +# -*- mode:python -*- + +# Copyright (c) 2006 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +import os +import os.path + +# Import build environment variable from SConstruct. +Import('env') + +################################################################# +# +# Generate StaticInst execute() method signatures. +# +# There must be one signature for each CPU model compiled in. +# Since the set of compiled-in models is flexible, we generate a +# header containing the appropriate set of signatures on the fly. +# +################################################################# + +# CPU model-specific data is contained in cpu_models.py +# Convert to SCons File node to get path handling +models_db = File('cpu_models.py') +# slurp in contents of file +execfile(models_db.srcnode().abspath) + +# Template for execute() signature. +exec_sig_template = ''' +virtual Fault execute(%s *xc, Trace::InstRecord *traceData) const = 0; +virtual Fault initiateAcc(%s *xc, Trace::InstRecord *traceData) const +{ panic("initiateAcc not defined!"); }; +virtual Fault completeAcc(Packet *pkt, %s *xc, + Trace::InstRecord *traceData) const +{ panic("completeAcc not defined!"); }; +''' + +mem_ini_sig_template = ''' +virtual Fault initiateAcc(%s *xc, Trace::InstRecord *traceData) const { panic("Not defined!"); }; +''' + +mem_comp_sig_template = ''' +virtual Fault completeAcc(uint8_t *data, %s *xc, Trace::InstRecord *traceData) const { panic("Not defined!"); return NoFault; }; +''' + +# Generate header. +def gen_cpu_exec_signatures(target, source, env): + f = open(str(target[0]), 'w') + print >> f, ''' +#ifndef __CPU_STATIC_INST_EXEC_SIGS_HH__ +#define __CPU_STATIC_INST_EXEC_SIGS_HH__ +''' + for cpu in env['CPU_MODELS']: + xc_type = CpuModel.dict[cpu].strings['CPU_exec_context'] + print >> f, exec_sig_template % (xc_type, xc_type, xc_type) + print >> f, ''' +#endif // __CPU_STATIC_INST_EXEC_SIGS_HH__ +''' + +# Generate string that gets printed when header is rebuilt +def gen_sigs_string(target, source, env): + return "Generating static_inst_exec_sigs.hh: " \ + + ', '.join(env['CPU_MODELS']) + +# Add command to generate header to environment. +env.Command('static_inst_exec_sigs.hh', models_db, + Action(gen_cpu_exec_signatures, gen_sigs_string, + varlist = ['CPU_MODELS'])) + +################################################################# +# +# Include CPU-model-specific files based on set of models +# specified in CPU_MODELS build option. +# +################################################################# + +sources = [] + +need_simple_base = False +if 'AtomicSimpleCPU' in env['CPU_MODELS']: + need_simple_base = True + sources += Split('simple/atomic.cc') + +if 'TimingSimpleCPU' in env['CPU_MODELS']: + need_simple_base = True + sources += Split('simple/timing.cc') + +if need_simple_base: + sources += Split('simple/base.cc') + +if 'FastCPU' in env['CPU_MODELS']: + sources += Split('fast/cpu.cc') + +if 'AlphaFullCPU' in env['CPU_MODELS']: + sources += Split(''' + o3/2bit_local_pred.cc + o3/alpha_dyn_inst.cc + o3/alpha_cpu.cc + o3/alpha_cpu_builder.cc + o3/bpred_unit.cc + o3/btb.cc + o3/commit.cc + o3/decode.cc + o3/fetch.cc + o3/free_list.cc + o3/fu_pool.cc + o3/cpu.cc + o3/iew.cc + o3/inst_queue.cc + o3/lsq_unit.cc + o3/lsq.cc + o3/mem_dep_unit.cc + o3/ras.cc + o3/rename.cc + o3/rename_map.cc + o3/rob.cc + o3/scoreboard.cc + o3/store_set.cc + o3/tournament_pred.cc + ''') + +if 'OzoneSimpleCPU' in env['CPU_MODELS']: + sources += Split(''' + ozone/cpu.cc + ozone/cpu_builder.cc + ozone/dyn_inst.cc + ozone/front_end.cc + ozone/inorder_back_end.cc + ozone/inst_queue.cc + ozone/rename_table.cc + ''') + +if 'OzoneCPU' in env['CPU_MODELS']: + sources += Split(''' + ozone/back_end.cc + ozone/lsq_unit.cc + ozone/lw_back_end.cc + ozone/lw_lsq.cc + ''') + +if 'CheckerCPU' in env['CPU_MODELS']: + sources += Split(''' + checker/cpu.cc + checker/cpu_builder.cc + checker/o3_cpu_builder.cc + ''') + +# FullCPU sources are included from m5/SConscript since they're not +# below this point in the file hierarchy. + +# Convert file names to SCons File objects. This takes care of the +# path relative to the top of the directory tree. +sources = [File(s) for s in sources] + +Return('sources') + diff --git a/src/cpu/base.cc b/src/cpu/base.cc new file mode 100644 index 000000000..8641d987d --- /dev/null +++ b/src/cpu/base.cc @@ -0,0 +1,381 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <iostream> +#include <string> +#include <sstream> + +#include "base/cprintf.hh" +#include "base/loader/symtab.hh" +#include "base/misc.hh" +#include "base/output.hh" +#include "cpu/base.hh" +#include "cpu/cpuevent.hh" +#include "cpu/exec_context.hh" +#include "cpu/profile.hh" +#include "cpu/sampler/sampler.hh" +#include "sim/param.hh" +#include "sim/process.hh" +#include "sim/sim_events.hh" +#include "sim/system.hh" + +#include "base/trace.hh" + +using namespace std; + +vector<BaseCPU *> BaseCPU::cpuList; + +// This variable reflects the max number of threads in any CPU. Be +// careful to only use it once all the CPUs that you care about have +// been initialized +int maxThreadsPerCPU = 1; + +#if FULL_SYSTEM +BaseCPU::BaseCPU(Params *p) + : SimObject(p->name), clock(p->clock), checkInterrupts(true), + params(p), number_of_threads(p->numberOfThreads), system(p->system) +#else +BaseCPU::BaseCPU(Params *p) + : SimObject(p->name), clock(p->clock), params(p), + number_of_threads(p->numberOfThreads), system(p->system) +#endif +{ + DPRINTF(FullCPU, "BaseCPU: Creating object, mem address %#x.\n", this); + + // add self to global list of CPUs + cpuList.push_back(this); + + DPRINTF(FullCPU, "BaseCPU: CPU added to cpuList, mem address %#x.\n", + this); + + if (number_of_threads > maxThreadsPerCPU) + maxThreadsPerCPU = number_of_threads; + + // allocate per-thread instruction-based event queues + comInstEventQueue = new EventQueue *[number_of_threads]; + for (int i = 0; i < number_of_threads; ++i) + comInstEventQueue[i] = new EventQueue("instruction-based event queue"); + + // + // set up instruction-count-based termination events, if any + // + if (p->max_insts_any_thread != 0) + for (int i = 0; i < number_of_threads; ++i) + new SimExitEvent(comInstEventQueue[i], p->max_insts_any_thread, + "a thread reached the max instruction count"); + + if (p->max_insts_all_threads != 0) { + // allocate & initialize shared downcounter: each event will + // decrement this when triggered; simulation will terminate + // when counter reaches 0 + int *counter = new int; + *counter = number_of_threads; + for (int i = 0; i < number_of_threads; ++i) + new CountedExitEvent(comInstEventQueue[i], + "all threads reached the max instruction count", + p->max_insts_all_threads, *counter); + } + + // allocate per-thread load-based event queues + comLoadEventQueue = new EventQueue *[number_of_threads]; + for (int i = 0; i < number_of_threads; ++i) + comLoadEventQueue[i] = new EventQueue("load-based event queue"); + + // + // set up instruction-count-based termination events, if any + // + if (p->max_loads_any_thread != 0) + for (int i = 0; i < number_of_threads; ++i) + new SimExitEvent(comLoadEventQueue[i], p->max_loads_any_thread, + "a thread reached the max load count"); + + if (p->max_loads_all_threads != 0) { + // allocate & initialize shared downcounter: each event will + // decrement this when triggered; simulation will terminate + // when counter reaches 0 + int *counter = new int; + *counter = number_of_threads; + for (int i = 0; i < number_of_threads; ++i) + new CountedExitEvent(comLoadEventQueue[i], + "all threads reached the max load count", + p->max_loads_all_threads, *counter); + } + +#if FULL_SYSTEM + memset(interrupts, 0, sizeof(interrupts)); + intstatus = 0; +#endif + + functionTracingEnabled = false; + if (p->functionTrace) { + functionTraceStream = simout.find(csprintf("ftrace.%s", name())); + currentFunctionStart = currentFunctionEnd = 0; + functionEntryTick = p->functionTraceStart; + + if (p->functionTraceStart == 0) { + functionTracingEnabled = true; + } else { + Event *e = + new EventWrapper<BaseCPU, &BaseCPU::enableFunctionTrace>(this, + true); + e->schedule(p->functionTraceStart); + } + } +#if FULL_SYSTEM + profileEvent = NULL; + if (params->profile) + profileEvent = new ProfileEvent(this, params->profile); +#endif + +} + +BaseCPU::Params::Params() +{ +#if FULL_SYSTEM + profile = false; +#endif + checker = NULL; +} + +void +BaseCPU::enableFunctionTrace() +{ + functionTracingEnabled = true; +} + +BaseCPU::~BaseCPU() +{ +} + +void +BaseCPU::init() +{ + if (!params->deferRegistration) + registerExecContexts(); +} + +void +BaseCPU::startup() +{ +#if FULL_SYSTEM + if (!params->deferRegistration && profileEvent) + profileEvent->schedule(curTick); +#endif +} + + +void +BaseCPU::regStats() +{ + using namespace Stats; + + numCycles + .name(name() + ".numCycles") + .desc("number of cpu cycles simulated") + ; + + int size = execContexts.size(); + if (size > 1) { + for (int i = 0; i < size; ++i) { + stringstream namestr; + ccprintf(namestr, "%s.ctx%d", name(), i); + execContexts[i]->regStats(namestr.str()); + } + } else if (size == 1) + execContexts[0]->regStats(name()); + +#if FULL_SYSTEM +#endif +} + + +void +BaseCPU::registerExecContexts() +{ + for (int i = 0; i < execContexts.size(); ++i) { + ExecContext *xc = execContexts[i]; + +#if FULL_SYSTEM + int id = params->cpu_id; + if (id != -1) + id += i; + + xc->setCpuId(system->registerExecContext(xc, id)); +#else + xc->setCpuId(xc->getProcessPtr()->registerExecContext(xc)); +#endif + } + } +} + + +void +BaseCPU::switchOut(Sampler *sampler) +{ + panic("This CPU doesn't support sampling!"); +} + +void +BaseCPU::takeOverFrom(BaseCPU *oldCPU) +{ + assert(execContexts.size() == oldCPU->execContexts.size()); + + for (int i = 0; i < execContexts.size(); ++i) { + ExecContext *newXC = execContexts[i]; + ExecContext *oldXC = oldCPU->execContexts[i]; + + newXC->takeOverFrom(oldXC); + + CpuEvent::replaceExecContext(oldXC, newXC); + + assert(newXC->readCpuId() == oldXC->readCpuId()); +#if FULL_SYSTEM + system->replaceExecContext(newXC, newXC->readCpuId()); +#else + assert(newXC->getProcessPtr() == oldXC->getProcessPtr()); + newXC->getProcessPtr()->replaceExecContext(newXC, newXC->readCpuId()); +#endif + } + +#if FULL_SYSTEM + for (int i = 0; i < TheISA::NumInterruptLevels; ++i) + interrupts[i] = oldCPU->interrupts[i]; + intstatus = oldCPU->intstatus; + + for (int i = 0; i < execContexts.size(); ++i) + execContexts[i]->profileClear(); + + if (profileEvent) + profileEvent->schedule(curTick); +#endif +} + + +#if FULL_SYSTEM +BaseCPU::ProfileEvent::ProfileEvent(BaseCPU *_cpu, int _interval) + : Event(&mainEventQueue), cpu(_cpu), interval(_interval) +{ } + +void +BaseCPU::ProfileEvent::process() +{ + for (int i = 0, size = cpu->execContexts.size(); i < size; ++i) { + ExecContext *xc = cpu->execContexts[i]; + xc->profileSample(); + } + + schedule(curTick + interval); +} + +void +BaseCPU::post_interrupt(int int_num, int index) +{ + DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index); + + if (int_num < 0 || int_num >= TheISA::NumInterruptLevels) + panic("int_num out of bounds\n"); + + if (index < 0 || index >= sizeof(uint64_t) * 8) + panic("int_num out of bounds\n"); + + checkInterrupts = true; + interrupts[int_num] |= 1 << index; + intstatus |= (ULL(1) << int_num); +} + +void +BaseCPU::clear_interrupt(int int_num, int index) +{ + DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index); + + if (int_num < 0 || int_num >= TheISA::NumInterruptLevels) + panic("int_num out of bounds\n"); + + if (index < 0 || index >= sizeof(uint64_t) * 8) + panic("int_num out of bounds\n"); + + interrupts[int_num] &= ~(1 << index); + if (interrupts[int_num] == 0) + intstatus &= ~(ULL(1) << int_num); +} + +void +BaseCPU::clear_interrupts() +{ + DPRINTF(Interrupt, "Interrupts all cleared\n"); + + memset(interrupts, 0, sizeof(interrupts)); + intstatus = 0; +} + + +void +BaseCPU::serialize(std::ostream &os) +{ + SERIALIZE_ARRAY(interrupts, TheISA::NumInterruptLevels); + SERIALIZE_SCALAR(intstatus); +} + +void +BaseCPU::unserialize(Checkpoint *cp, const std::string §ion) +{ + UNSERIALIZE_ARRAY(interrupts, TheISA::NumInterruptLevels); + UNSERIALIZE_SCALAR(intstatus); +} + +#endif // FULL_SYSTEM + +void +BaseCPU::traceFunctionsInternal(Addr pc) +{ + if (!debugSymbolTable) + return; + + // if pc enters different function, print new function symbol and + // update saved range. Otherwise do nothing. + if (pc < currentFunctionStart || pc >= currentFunctionEnd) { + string sym_str; + bool found = debugSymbolTable->findNearestSymbol(pc, sym_str, + currentFunctionStart, + currentFunctionEnd); + + if (!found) { + // no symbol found: use addr as label + sym_str = csprintf("0x%x", pc); + currentFunctionStart = pc; + currentFunctionEnd = pc + 1; + } + + ccprintf(*functionTraceStream, " (%d)\n%d: %s", + curTick - functionEntryTick, curTick, sym_str); + functionEntryTick = curTick; + } +} + + +DEFINE_SIM_OBJECT_CLASS_NAME("BaseCPU", BaseCPU) diff --git a/src/cpu/base.hh b/src/cpu/base.hh new file mode 100644 index 000000000..f14ace750 --- /dev/null +++ b/src/cpu/base.hh @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __CPU_BASE_HH__ +#define __CPU_BASE_HH__ + +#include <vector> + +#include "base/statistics.hh" +#include "config/full_system.hh" +#include "cpu/sampler/sampler.hh" +#include "sim/eventq.hh" +#include "sim/sim_object.hh" +#include "arch/isa_traits.hh" + +class BranchPred; +class CheckerCPU; +class ExecContext; +class System; + +class BaseCPU : public SimObject +{ + protected: + // CPU's clock period in terms of the number of ticks of curTime. + Tick clock; + + public: + inline Tick frequency() const { return Clock::Frequency / clock; } + inline Tick cycles(int numCycles) const { return clock * numCycles; } + inline Tick curCycle() const { return curTick / clock; } + +#if FULL_SYSTEM + protected: + uint64_t interrupts[TheISA::NumInterruptLevels]; + uint64_t intstatus; + + public: + virtual void post_interrupt(int int_num, int index); + virtual void clear_interrupt(int int_num, int index); + virtual void clear_interrupts(); + bool checkInterrupts; + + bool check_interrupt(int int_num) const { + if (int_num > TheISA::NumInterruptLevels) + panic("int_num out of bounds\n"); + + return interrupts[int_num] != 0; + } + + bool check_interrupts() const { return intstatus != 0; } + uint64_t intr_status() const { return intstatus; } + + class ProfileEvent : public Event + { + private: + BaseCPU *cpu; + int interval; + + public: + ProfileEvent(BaseCPU *cpu, int interval); + void process(); + }; + ProfileEvent *profileEvent; +#endif + + protected: + std::vector<ExecContext *> execContexts; + + public: + + /// Notify the CPU that the indicated context is now active. The + /// delay parameter indicates the number of ticks to wait before + /// executing (typically 0 or 1). + virtual void activateContext(int thread_num, int delay) {} + + /// Notify the CPU that the indicated context is now suspended. + virtual void suspendContext(int thread_num) {} + + /// Notify the CPU that the indicated context is now deallocated. + virtual void deallocateContext(int thread_num) {} + + /// Notify the CPU that the indicated context is now halted. + virtual void haltContext(int thread_num) {} + + public: + struct Params + { + std::string name; + int numberOfThreads; + bool deferRegistration; + Counter max_insts_any_thread; + Counter max_insts_all_threads; + Counter max_loads_any_thread; + Counter max_loads_all_threads; + Tick clock; + bool functionTrace; + Tick functionTraceStart; + System *system; +#if FULL_SYSTEM + int cpu_id; + Tick profile; +#endif + BaseCPU *checker; + + Params(); + }; + + const Params *params; + + BaseCPU(Params *params); + virtual ~BaseCPU(); + + virtual void init(); + virtual void startup(); + virtual void regStats(); + + virtual void activateWhenReady(int tid) {}; + + void registerExecContexts(); + + /// Prepare for another CPU to take over execution. When it is + /// is ready (drained pipe) it signals the sampler. + virtual void switchOut(Sampler *); + + /// Take over execution from the given CPU. Used for warm-up and + /// sampling. + virtual void takeOverFrom(BaseCPU *); + + /** + * Number of threads we're actually simulating (<= SMT_MAX_THREADS). + * This is a constant for the duration of the simulation. + */ + int number_of_threads; + + /** + * Vector of per-thread instruction-based event queues. Used for + * scheduling events based on number of instructions committed by + * a particular thread. + */ + EventQueue **comInstEventQueue; + + /** + * Vector of per-thread load-based event queues. Used for + * scheduling events based on number of loads committed by + *a particular thread. + */ + EventQueue **comLoadEventQueue; + + System *system; + +#if FULL_SYSTEM + /** + * Serialize this object to the given output stream. + * @param os The stream to serialize to. + */ + virtual void serialize(std::ostream &os); + + /** + * Reconstruct the state of this object from a checkpoint. + * @param cp The checkpoint use. + * @param section The section name of this object + */ + virtual void unserialize(Checkpoint *cp, const std::string §ion); + +#endif + + /** + * Return pointer to CPU's branch predictor (NULL if none). + * @return Branch predictor pointer. + */ + virtual BranchPred *getBranchPred() { return NULL; }; + + virtual Counter totalInstructions() const { return 0; } + + // Function tracing + private: + bool functionTracingEnabled; + std::ostream *functionTraceStream; + Addr currentFunctionStart; + Addr currentFunctionEnd; + Tick functionEntryTick; + void enableFunctionTrace(); + void traceFunctionsInternal(Addr pc); + + protected: + void traceFunctions(Addr pc) + { + if (functionTracingEnabled) + traceFunctionsInternal(pc); + } + + private: + static std::vector<BaseCPU *> cpuList; //!< Static global cpu list + + public: + static int numSimulatedCPUs() { return cpuList.size(); } + static Counter numSimulatedInstructions() + { + Counter total = 0; + + int size = cpuList.size(); + for (int i = 0; i < size; ++i) + total += cpuList[i]->totalInstructions(); + + return total; + } + + public: + // Number of CPU cycles simulated + Stats::Scalar<> numCycles; +}; + +#endif // __CPU_BASE_HH__ diff --git a/cpu/base_dyn_inst.cc b/src/cpu/base_dyn_inst.cc index 7ab760ae3..7ab760ae3 100644 --- a/cpu/base_dyn_inst.cc +++ b/src/cpu/base_dyn_inst.cc diff --git a/cpu/base_dyn_inst.hh b/src/cpu/base_dyn_inst.hh index 388ea4a8d..388ea4a8d 100644 --- a/cpu/base_dyn_inst.hh +++ b/src/cpu/base_dyn_inst.hh diff --git a/src/cpu/cpu_exec_context.cc b/src/cpu/cpu_exec_context.cc new file mode 100644 index 000000000..7c2b32a93 --- /dev/null +++ b/src/cpu/cpu_exec_context.cc @@ -0,0 +1,340 @@ +/* + * Copyright (c) 2001-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <string> + +#include "arch/isa_traits.hh" +#include "cpu/base.hh" +#include "cpu/cpu_exec_context.hh" +#include "cpu/exec_context.hh" + +#if FULL_SYSTEM +#include "base/callback.hh" +#include "base/cprintf.hh" +#include "base/output.hh" +#include "base/trace.hh" +#include "cpu/profile.hh" +#include "cpu/quiesce_event.hh" +#include "kern/kernel_stats.hh" +#include "sim/serialize.hh" +#include "sim/sim_exit.hh" +#include "arch/stacktrace.hh" +#else +#include "sim/process.hh" +#include "sim/system.hh" +#include "mem/translating_port.hh" +#endif + +using namespace std; + +// constructor +#if FULL_SYSTEM +CPUExecContext::CPUExecContext(BaseCPU *_cpu, int _thread_num, System *_sys, + AlphaITB *_itb, AlphaDTB *_dtb, + bool use_kernel_stats) + : _status(ExecContext::Unallocated), cpu(_cpu), thread_num(_thread_num), + cpu_id(-1), lastActivate(0), lastSuspend(0), system(_sys), itb(_itb), + dtb(_dtb), profile(NULL), func_exe_inst(0), storeCondFailures(0) + +{ + proxy = new ProxyExecContext<CPUExecContext>(this); + + quiesceEvent = new EndQuiesceEvent(proxy); + + regs.clear(); + + if (cpu->params->profile) { + profile = new FunctionProfile(system->kernelSymtab); + Callback *cb = + new MakeCallback<CPUExecContext, + &CPUExecContext::dumpFuncProfile>(this); + registerExitCallback(cb); + } + + // let's fill with a dummy node for now so we don't get a segfault + // on the first cycle when there's no node available. + static ProfileNode dummyNode; + profileNode = &dummyNode; + profilePC = 3; + + + if (use_kernel_stats) { + kernelStats = new Kernel::Statistics(system); + } else { + kernelStats = NULL; + } + Port *mem_port; + physPort = new FunctionalPort(csprintf("%s-%d-funcport", + cpu->name(), thread_num)); + mem_port = system->physmem->getPort("functional"); + mem_port->setPeer(physPort); + physPort->setPeer(mem_port); + + virtPort = new VirtualPort(csprintf("%s-%d-vport", + cpu->name(), thread_num)); + mem_port = system->physmem->getPort("functional"); + mem_port->setPeer(virtPort); + virtPort->setPeer(mem_port); +} +#else +CPUExecContext::CPUExecContext(BaseCPU *_cpu, int _thread_num, + Process *_process, int _asid, MemObject* memobj) + : _status(ExecContext::Unallocated), + cpu(_cpu), thread_num(_thread_num), cpu_id(-1), lastActivate(0), + lastSuspend(0), process(_process), asid(_asid), + func_exe_inst(0), storeCondFailures(0) +{ + /* Use this port to for syscall emulation writes to memory. */ + Port *mem_port; + port = new TranslatingPort(csprintf("%s-%d-funcport", + cpu->name(), thread_num), + process->pTable, false); + mem_port = memobj->getPort("functional"); + mem_port->setPeer(port); + port->setPeer(mem_port); + + regs.clear(); + proxy = new ProxyExecContext<CPUExecContext>(this); +} + +CPUExecContext::CPUExecContext(RegFile *regFile) + : cpu(NULL), thread_num(-1), process(NULL), asid(-1), + func_exe_inst(0), storeCondFailures(0) +{ + regs = *regFile; + proxy = new ProxyExecContext<CPUExecContext>(this); +} + +#endif + +CPUExecContext::~CPUExecContext() +{ + delete proxy; +} + +#if FULL_SYSTEM +void +CPUExecContext::dumpFuncProfile() +{ + std::ostream *os = simout.create(csprintf("profile.%s.dat", cpu->name())); + profile->dump(proxy, *os); +} + +void +CPUExecContext::profileClear() +{ + if (profile) + profile->clear(); +} + +void +CPUExecContext::profileSample() +{ + if (profile) + profile->sample(profileNode, profilePC); +} + +#endif + +void +CPUExecContext::takeOverFrom(ExecContext *oldContext) +{ + // some things should already be set up +#if FULL_SYSTEM + assert(system == oldContext->getSystemPtr()); +#else + assert(process == oldContext->getProcessPtr()); +#endif + + // copy over functional state + _status = oldContext->status(); + copyArchRegs(oldContext); + cpu_id = oldContext->readCpuId(); +#if !FULL_SYSTEM + func_exe_inst = oldContext->readFuncExeInst(); +#else + EndQuiesceEvent *quiesce = oldContext->getQuiesceEvent(); + if (quiesce) { + // Point the quiesce event's XC at this XC so that it wakes up + // the proper CPU. + quiesce->xc = proxy; + } + if (quiesceEvent) { + quiesceEvent->xc = proxy; + } +#endif + + storeCondFailures = 0; + + oldContext->setStatus(ExecContext::Unallocated); +} + +void +CPUExecContext::serialize(ostream &os) +{ + SERIALIZE_ENUM(_status); + regs.serialize(os); + // thread_num and cpu_id are deterministic from the config + SERIALIZE_SCALAR(func_exe_inst); + SERIALIZE_SCALAR(inst); + +#if FULL_SYSTEM + Tick quiesceEndTick = 0; + if (quiesceEvent->scheduled()) + quiesceEndTick = quiesceEvent->when(); + SERIALIZE_SCALAR(quiesceEndTick); + if (kernelStats) + kernelStats->serialize(os); +#endif +} + + +void +CPUExecContext::unserialize(Checkpoint *cp, const std::string §ion) +{ + UNSERIALIZE_ENUM(_status); + regs.unserialize(cp, section); + // thread_num and cpu_id are deterministic from the config + UNSERIALIZE_SCALAR(func_exe_inst); + UNSERIALIZE_SCALAR(inst); + +#if FULL_SYSTEM + Tick quiesceEndTick; + UNSERIALIZE_SCALAR(quiesceEndTick); + if (quiesceEndTick) + quiesceEvent->schedule(quiesceEndTick); + if (kernelStats) + kernelStats->unserialize(cp, section); +#endif +} + + +void +CPUExecContext::activate(int delay) +{ + if (status() == ExecContext::Active) + return; + + lastActivate = curTick; + + if (status() == ExecContext::Unallocated) { + cpu->activateWhenReady(thread_num); + return; + } + + _status = ExecContext::Active; + + // status() == Suspended + cpu->activateContext(thread_num, delay); +} + +void +CPUExecContext::suspend() +{ + if (status() == ExecContext::Suspended) + return; + + lastActivate = curTick; + lastSuspend = curTick; +/* +#if FULL_SYSTEM + // Don't change the status from active if there are pending interrupts + if (cpu->check_interrupts()) { + assert(status() == ExecContext::Active); + return; + } +#endif +*/ + _status = ExecContext::Suspended; + cpu->suspendContext(thread_num); +} + +void +CPUExecContext::deallocate() +{ + if (status() == ExecContext::Unallocated) + return; + + _status = ExecContext::Unallocated; + cpu->deallocateContext(thread_num); +} + +void +CPUExecContext::halt() +{ + if (status() == ExecContext::Halted) + return; + + _status = ExecContext::Halted; + cpu->haltContext(thread_num); +} + + +void +CPUExecContext::regStats(const string &name) +{ +#if FULL_SYSTEM + if (kernelStats) + kernelStats->regStats(name + ".kern"); +#endif +} + +void +CPUExecContext::copyArchRegs(ExecContext *xc) +{ + TheISA::copyRegs(xc, proxy); +} + +#if FULL_SYSTEM +VirtualPort* +CPUExecContext::getVirtPort(ExecContext *xc) +{ + if (!xc) + return virtPort; + + VirtualPort *vp; + Port *mem_port; + + vp = new VirtualPort("xc-vport", xc); + mem_port = system->physmem->getPort("functional"); + mem_port->setPeer(vp); + vp->setPeer(mem_port); + return vp; +} + +void +CPUExecContext::delVirtPort(VirtualPort *vp) +{ +// assert(!vp->nullExecContext()); + delete vp->getPeer(); + delete vp; +} + + +#endif + diff --git a/src/cpu/cpu_exec_context.hh b/src/cpu/cpu_exec_context.hh new file mode 100644 index 000000000..61e6550af --- /dev/null +++ b/src/cpu/cpu_exec_context.hh @@ -0,0 +1,540 @@ +/* + * Copyright (c) 2001-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __CPU_CPU_EXEC_CONTEXT_HH__ +#define __CPU_CPU_EXEC_CONTEXT_HH__ + +#include "arch/isa_traits.hh" +#include "config/full_system.hh" +#include "cpu/exec_context.hh" +#include "mem/physical.hh" +#include "mem/request.hh" +#include "sim/byteswap.hh" +#include "sim/eventq.hh" +#include "sim/host.hh" +#include "sim/serialize.hh" + +class BaseCPU; + +#if FULL_SYSTEM + +#include "sim/system.hh" +#include "arch/tlb.hh" + +class FunctionProfile; +class ProfileNode; +class FunctionalPort; +class PhysicalPort; + + +namespace Kernel { + class Statistics; +}; + +#else // !FULL_SYSTEM + +#include "sim/process.hh" +#include "mem/page_table.hh" +class TranslatingPort; + + +#endif // FULL_SYSTEM + +// +// The CPUExecContext object represents a functional context for +// instruction execution. It incorporates everything required for +// architecture-level functional simulation of a single thread. +// + +class CPUExecContext +{ + protected: + typedef TheISA::RegFile RegFile; + typedef TheISA::MachInst MachInst; + typedef TheISA::MiscRegFile MiscRegFile; + typedef TheISA::MiscReg MiscReg; + typedef TheISA::FloatReg FloatReg; + typedef TheISA::FloatRegBits FloatRegBits; + public: + typedef ExecContext::Status Status; + + private: + Status _status; + + public: + Status status() const { return _status; } + + void setStatus(Status newStatus) { _status = newStatus; } + + /// Set the status to Active. Optional delay indicates number of + /// cycles to wait before beginning execution. + void activate(int delay = 1); + + /// Set the status to Suspended. + void suspend(); + + /// Set the status to Unallocated. + void deallocate(); + + /// Set the status to Halted. + void halt(); + + protected: + RegFile regs; // correct-path register context + + public: + // pointer to CPU associated with this context + BaseCPU *cpu; + + ProxyExecContext<CPUExecContext> *proxy; + + // Current instruction + MachInst inst; + + // Index of hardware thread context on the CPU that this represents. + int thread_num; + + // ID of this context w.r.t. the System or Process object to which + // it belongs. For full-system mode, this is the system CPU ID. + int cpu_id; + + Tick lastActivate; + Tick lastSuspend; + + System *system; + + +#if FULL_SYSTEM + AlphaITB *itb; + AlphaDTB *dtb; + + /** A functional port outgoing only for functional accesses to physical + * addresses.*/ + FunctionalPort *physPort; + + /** A functional port, outgoing only, for functional accesse to virtual + * addresses. That doen't require execution context information */ + VirtualPort *virtPort; + + FunctionProfile *profile; + ProfileNode *profileNode; + Addr profilePC; + void dumpFuncProfile(); + + EndQuiesceEvent *quiesceEvent; + + EndQuiesceEvent *getQuiesceEvent() { return quiesceEvent; } + + Tick readLastActivate() { return lastActivate; } + + Tick readLastSuspend() { return lastSuspend; } + + void profileClear(); + + void profileSample(); + + Kernel::Statistics *getKernelStats() { return kernelStats; } + + Kernel::Statistics *kernelStats; +#else + /// Port that syscalls can use to access memory (provides translation step). + TranslatingPort *port; + + Process *process; + + // Address space ID. Note that this is used for TIMING cache + // simulation only; all functional memory accesses should use + // one of the FunctionalMemory pointers above. + short asid; + +#endif + + /** + * Temporary storage to pass the source address from copy_load to + * copy_store. + * @todo Remove this temporary when we have a better way to do it. + */ + Addr copySrcAddr; + /** + * Temp storage for the physical source address of a copy. + * @todo Remove this temporary when we have a better way to do it. + */ + Addr copySrcPhysAddr; + + + /* + * number of executed instructions, for matching with syscall trace + * points in EIO files. + */ + Counter func_exe_inst; + + // + // Count failed store conditionals so we can warn of apparent + // application deadlock situations. + unsigned storeCondFailures; + + // constructor: initialize context from given process structure +#if FULL_SYSTEM + CPUExecContext(BaseCPU *_cpu, int _thread_num, System *_system, + AlphaITB *_itb, AlphaDTB *_dtb, + bool use_kernel_stats = true); +#else + CPUExecContext(BaseCPU *_cpu, int _thread_num, Process *_process, int _asid, + MemObject *memobj); + // Constructor to use XC to pass reg file around. Not used for anything + // else. + CPUExecContext(RegFile *regFile); +#endif + virtual ~CPUExecContext(); + + virtual void takeOverFrom(ExecContext *oldContext); + + void regStats(const std::string &name); + + void serialize(std::ostream &os); + void unserialize(Checkpoint *cp, const std::string §ion); + + BaseCPU *getCpuPtr() { return cpu; } + + ExecContext *getProxy() { return proxy; } + + int getThreadNum() { return thread_num; } + +#if FULL_SYSTEM + System *getSystemPtr() { return system; } + + AlphaITB *getITBPtr() { return itb; } + + AlphaDTB *getDTBPtr() { return dtb; } + + int getInstAsid() { return regs.instAsid(); } + int getDataAsid() { return regs.dataAsid(); } + + Fault translateInstReq(RequestPtr &req) + { + return itb->translate(req, proxy); + } + + Fault translateDataReadReq(RequestPtr &req) + { + return dtb->translate(req, proxy, false); + } + + Fault translateDataWriteReq(RequestPtr &req) + { + return dtb->translate(req, proxy, true); + } + + FunctionalPort *getPhysPort() { return physPort; } + + /** Return a virtual port. If no exec context is specified then a static + * port is returned. Otherwise a port is created and returned. It must be + * deleted by deleteVirtPort(). */ + VirtualPort *getVirtPort(ExecContext *xc); + + void delVirtPort(VirtualPort *vp); + +#else + TranslatingPort *getMemPort() { return port; } + + Process *getProcessPtr() { return process; } + + int getInstAsid() { return asid; } + int getDataAsid() { return asid; } + + Fault translateInstReq(RequestPtr &req) + { + return process->pTable->translate(req); + } + + Fault translateDataReadReq(RequestPtr &req) + { + return process->pTable->translate(req); + } + + Fault translateDataWriteReq(RequestPtr &req) + { + return process->pTable->translate(req); + } + +#endif + +/* + template <class T> + Fault read(RequestPtr &req, T &data) + { +#if FULL_SYSTEM && THE_ISA == ALPHA_ISA + if (req->flags & LOCKED) { + req->xc->setMiscReg(TheISA::Lock_Addr_DepTag, req->paddr); + req->xc->setMiscReg(TheISA::Lock_Flag_DepTag, true); + } +#endif + + Fault error; + error = mem->prot_read(req->paddr, data, req->size); + data = LittleEndianGuest::gtoh(data); + return error; + } + + template <class T> + Fault write(RequestPtr &req, T &data) + { +#if FULL_SYSTEM && THE_ISA == ALPHA_ISA + ExecContext *xc; + + // If this is a store conditional, act appropriately + if (req->flags & LOCKED) { + xc = req->xc; + + if (req->flags & UNCACHEABLE) { + // Don't update result register (see stq_c in isa_desc) + req->result = 2; + xc->setStCondFailures(0);//Needed? [RGD] + } else { + bool lock_flag = xc->readMiscReg(TheISA::Lock_Flag_DepTag); + Addr lock_addr = xc->readMiscReg(TheISA::Lock_Addr_DepTag); + req->result = lock_flag; + if (!lock_flag || + ((lock_addr & ~0xf) != (req->paddr & ~0xf))) { + xc->setMiscReg(TheISA::Lock_Flag_DepTag, false); + xc->setStCondFailures(xc->readStCondFailures() + 1); + if (((xc->readStCondFailures()) % 100000) == 0) { + std::cerr << "Warning: " + << xc->readStCondFailures() + << " consecutive store conditional failures " + << "on cpu " << req->xc->readCpuId() + << std::endl; + } + return NoFault; + } + else xc->setStCondFailures(0); + } + } + + // Need to clear any locked flags on other proccessors for + // this address. Only do this for succsful Store Conditionals + // and all other stores (WH64?). Unsuccessful Store + // Conditionals would have returned above, and wouldn't fall + // through. + for (int i = 0; i < system->execContexts.size(); i++){ + xc = system->execContexts[i]; + if ((xc->readMiscReg(TheISA::Lock_Addr_DepTag) & ~0xf) == + (req->paddr & ~0xf)) { + xc->setMiscReg(TheISA::Lock_Flag_DepTag, false); + } + } + +#endif + return mem->prot_write(req->paddr, (T)htog(data), req->size); + } +*/ + virtual bool misspeculating(); + + + MachInst getInst() { return inst; } + + void setInst(MachInst new_inst) + { + inst = new_inst; + } + + Fault instRead(RequestPtr &req) + { + panic("instRead not implemented"); + // return funcPhysMem->read(req, inst); + return NoFault; + } + + void setCpuId(int id) { cpu_id = id; } + + int readCpuId() { return cpu_id; } + + void copyArchRegs(ExecContext *xc); + + // + // New accessors for new decoder. + // + uint64_t readIntReg(int reg_idx) + { + return regs.readIntReg(reg_idx); + } + + FloatReg readFloatReg(int reg_idx, int width) + { + return regs.readFloatReg(reg_idx, width); + } + + FloatReg readFloatReg(int reg_idx) + { + return regs.readFloatReg(reg_idx); + } + + FloatRegBits readFloatRegBits(int reg_idx, int width) + { + return regs.readFloatRegBits(reg_idx, width); + } + + FloatRegBits readFloatRegBits(int reg_idx) + { + return regs.readFloatRegBits(reg_idx); + } + + void setIntReg(int reg_idx, uint64_t val) + { + regs.setIntReg(reg_idx, val); + } + + void setFloatReg(int reg_idx, FloatReg val, int width) + { + regs.setFloatReg(reg_idx, val, width); + } + + void setFloatReg(int reg_idx, FloatReg val) + { + regs.setFloatReg(reg_idx, val); + } + + void setFloatRegBits(int reg_idx, FloatRegBits val, int width) + { + regs.setFloatRegBits(reg_idx, val, width); + } + + void setFloatRegBits(int reg_idx, FloatRegBits val) + { + regs.setFloatRegBits(reg_idx, val); + } + + uint64_t readPC() + { + return regs.readPC(); + } + + void setPC(uint64_t val) + { + regs.setPC(val); + } + + uint64_t readNextPC() + { + return regs.readNextPC(); + } + + void setNextPC(uint64_t val) + { + regs.setNextPC(val); + } + + uint64_t readNextNPC() + { + return regs.readNextNPC(); + } + + void setNextNPC(uint64_t val) + { + regs.setNextNPC(val); + } + + + MiscReg readMiscReg(int misc_reg) + { + return regs.readMiscReg(misc_reg); + } + + MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault) + { + return regs.readMiscRegWithEffect(misc_reg, fault, proxy); + } + + Fault setMiscReg(int misc_reg, const MiscReg &val) + { + return regs.setMiscReg(misc_reg, val); + } + + Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val) + { + return regs.setMiscRegWithEffect(misc_reg, val, proxy); + } + + unsigned readStCondFailures() { return storeCondFailures; } + + void setStCondFailures(unsigned sc_failures) + { storeCondFailures = sc_failures; } + + void clearArchRegs() { regs.clear(); } + +#if FULL_SYSTEM + int readIntrFlag() { return regs.intrflag; } + void setIntrFlag(int val) { regs.intrflag = val; } + Fault hwrei(); + bool inPalMode() { return AlphaISA::PcPAL(regs.readPC()); } + bool simPalCheck(int palFunc); +#endif + +#if !FULL_SYSTEM + TheISA::IntReg getSyscallArg(int i) + { + return regs.readIntReg(TheISA::ArgumentReg0 + i); + } + + // used to shift args for indirect syscall + void setSyscallArg(int i, TheISA::IntReg val) + { + regs.setIntReg(TheISA::ArgumentReg0 + i, val); + } + + void setSyscallReturn(SyscallReturn return_value) + { + TheISA::setSyscallReturn(return_value, ®s); + } + + void syscall(int64_t callnum) + { + process->syscall(callnum, proxy); + } + + Counter readFuncExeInst() { return func_exe_inst; } + + void setFuncExeInst(Counter new_val) { func_exe_inst = new_val; } +#endif + + void changeRegFileContext(RegFile::ContextParam param, + RegFile::ContextVal val) + { + regs.changeContext(param, val); + } +}; + + +// for non-speculative execution context, spec_mode is always false +inline bool +CPUExecContext::misspeculating() +{ + return false; +} + +#endif // __CPU_CPU_EXEC_CONTEXT_HH__ diff --git a/src/cpu/cpu_models.py b/src/cpu/cpu_models.py new file mode 100644 index 000000000..c3de03948 --- /dev/null +++ b/src/cpu/cpu_models.py @@ -0,0 +1,80 @@ +# Copyright (c) 2003-2006 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +################ +# CpuModel class +# +# The CpuModel class encapsulates everything the ISA parser needs to +# know about a particular CPU model. + +class CpuModel: + # Dict of available CPU model objects. Accessible as CpuModel.dict. + dict = {} + + # Constructor. Automatically adds models to CpuModel.dict. + def __init__(self, name, filename, includes, strings): + self.name = name + self.filename = filename # filename for output exec code + self.includes = includes # include files needed in exec file + # The 'strings' dict holds all the per-CPU symbols we can + # substitute into templates etc. + self.strings = strings + # Add self to dict + CpuModel.dict[name] = self + + +# +# Define CPU models. +# +# Parameters are: +# - name of model +# - filename for generated ISA execution file +# - includes needed for generated ISA execution file +# - substitution strings for ISA description templates +# + +CpuModel('AtomicSimpleCPU', 'atomic_simple_cpu_exec.cc', + '#include "cpu/simple/atomic.hh"', + { 'CPU_exec_context': 'AtomicSimpleCPU' }) +CpuModel('TimingSimpleCPU', 'timing_simple_cpu_exec.cc', + '#include "cpu/simple/timing.hh"', + { 'CPU_exec_context': 'TimingSimpleCPU' }) +CpuModel('FullCPU', 'full_cpu_exec.cc', + '#include "encumbered/cpu/full/dyn_inst.hh"', + { 'CPU_exec_context': 'DynInst' }) +CpuModel('AlphaFullCPU', 'alpha_o3_exec.cc', + '#include "cpu/o3/alpha_dyn_inst.hh"', + { 'CPU_exec_context': 'AlphaDynInst<AlphaSimpleImpl>' }) +CpuModel('OzoneSimpleCPU', 'ozone_simple_exec.cc', + '#include "cpu/ozone/dyn_inst.hh"', + { 'CPU_exec_context': 'OzoneDynInst<SimpleImpl>' }) +CpuModel('OzoneCPU', 'ozone_exec.cc', + '#include "cpu/ozone/dyn_inst.hh"', + { 'CPU_exec_context': 'OzoneDynInst<OzoneImpl>' }) +CpuModel('CheckerCPU', 'checker_cpu_exec.cc', + '#include "cpu/checker/cpu.hh"', + { 'CPU_exec_context': 'CheckerCPU' }) + diff --git a/src/cpu/cpuevent.cc b/src/cpu/cpuevent.cc new file mode 100644 index 000000000..ae1dd7fa3 --- /dev/null +++ b/src/cpu/cpuevent.cc @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Ali Saidi + */ + +#include "cpu/cpuevent.hh" + +/** Static list of all CpuEvent objects so we can modify their execution + * contexts as needed. */ +CpuEvent::CpuEventList CpuEvent::cpuEventList; + +CpuEvent::~CpuEvent() +{ + CpuEventList::iterator i; + + // delete the event from the global list + for (i = cpuEventList.begin(); i != cpuEventList.end(); ) { + if (*i == this) + i = cpuEventList.erase(i); + else + i++; + } +} + +void +CpuEvent::replaceExecContext(ExecContext *oldXc, ExecContext *newXc) +{ + CpuEventList::iterator i; + + // Update any events that have the old execution context with the new exec + // context + for (i = cpuEventList.begin(); i != cpuEventList.end(); i++) { + if ((*i)->xc == oldXc) + (*i)->xc = newXc; + } +} diff --git a/src/cpu/cpuevent.hh b/src/cpu/cpuevent.hh new file mode 100644 index 000000000..10359b121 --- /dev/null +++ b/src/cpu/cpuevent.hh @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Ali Saidi + */ + +#ifndef __CPU_CPUEVENT_HH__ +#define __CPU_CPUEVENT_HH__ + +#include <vector> +#include "sim/eventq.hh" + +class ExecContext; + +/** This class creates a global list of events than need a pointer to an + * execution context. When a switchover takes place the events can be migrated + * to the new execution context, otherwise you could have a wake timer interrupt + * go off on a switched out cpu or other unfortunate events. This object MUST be + * dynamically allocated to avoid it being deleted after a cpu switch happens. + * */ +class CpuEvent : public Event +{ + private: + /** type of global list of cpu events. */ + typedef std::vector<CpuEvent *> CpuEventList; + + /** Static list of cpu events that is searched every time a cpu switch + * happens. */ + static CpuEventList cpuEventList; + + /** The execution context that is switched to the new cpus. */ + ExecContext *xc; + + public: + CpuEvent(EventQueue *q, ExecContext *_xc, Priority p = Default_Pri) + : Event(q, p), xc(_xc) + { cpuEventList.push_back(this); } + + /** delete the cpu event from the global list. */ + ~CpuEvent(); + + /** Update all events switching old xc to new xc. + * @param oldXc the old exeuction context we are switching from + * @param newXc the new execution context we are switching to. + */ + static void replaceExecContext(ExecContext *oldXc, ExecContext *newXc); +}; + +template <class T, void (T::* F)(ExecContext *xc)> +class CpuEventWrapper : public CpuEvent +{ + private: + T *object; + + public: + CpuEventWrapper(T *obj, ExecContext *_xc, EventQueue *q = &mainEventQueue, + Priority p = Default_Pri) + : CpuEvent(q, _xc, p), object(obj) + { } + void process() { (object->*F)(xc); } +}; + +#endif // __CPU_CPUEVENT_HH__ + diff --git a/src/cpu/exec_context.hh b/src/cpu/exec_context.hh new file mode 100644 index 000000000..5b601bb30 --- /dev/null +++ b/src/cpu/exec_context.hh @@ -0,0 +1,417 @@ +/* + * Copyright (c) 2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __CPU_EXEC_CONTEXT_HH__ +#define __CPU_EXEC_CONTEXT_HH__ + +#include "config/full_system.hh" +#include "mem/request.hh" +#include "sim/faults.hh" +#include "sim/host.hh" +#include "sim/serialize.hh" +#include "sim/byteswap.hh" + +// @todo: Figure out a more architecture independent way to obtain the ITB and +// DTB pointers. +class AlphaDTB; +class AlphaITB; +class BaseCPU; +class EndQuiesceEvent; +class Event; +class TranslatingPort; +class FunctionalPort; +class VirtualPort; +class Process; +class System; +namespace Kernel { + class Statistics; +}; + +class ExecContext +{ + protected: + typedef TheISA::RegFile RegFile; + typedef TheISA::MachInst MachInst; + typedef TheISA::IntReg IntReg; + typedef TheISA::FloatReg FloatReg; + typedef TheISA::FloatRegBits FloatRegBits; + typedef TheISA::MiscRegFile MiscRegFile; + typedef TheISA::MiscReg MiscReg; + public: + enum Status + { + /// Initialized but not running yet. All CPUs start in + /// this state, but most transition to Active on cycle 1. + /// In MP or SMT systems, non-primary contexts will stay + /// in this state until a thread is assigned to them. + Unallocated, + + /// Running. Instructions should be executed only when + /// the context is in this state. + Active, + + /// Temporarily inactive. Entered while waiting for + /// synchronization, etc. + Suspended, + + /// Permanently shut down. Entered when target executes + /// m5exit pseudo-instruction. When all contexts enter + /// this state, the simulation will terminate. + Halted + }; + + virtual ~ExecContext() { }; + + virtual BaseCPU *getCpuPtr() = 0; + + virtual void setCpuId(int id) = 0; + + virtual int readCpuId() = 0; + +#if FULL_SYSTEM + virtual System *getSystemPtr() = 0; + + virtual AlphaITB *getITBPtr() = 0; + + virtual AlphaDTB * getDTBPtr() = 0; + + virtual Kernel::Statistics *getKernelStats() = 0; + + virtual FunctionalPort *getPhysPort() = 0; + + virtual VirtualPort *getVirtPort(ExecContext *xc = NULL) = 0; + + virtual void delVirtPort(VirtualPort *vp) = 0; +#else + virtual TranslatingPort *getMemPort() = 0; + + virtual Process *getProcessPtr() = 0; +#endif + + virtual Status status() const = 0; + + virtual void setStatus(Status new_status) = 0; + + /// Set the status to Active. Optional delay indicates number of + /// cycles to wait before beginning execution. + virtual void activate(int delay = 1) = 0; + + /// Set the status to Suspended. + virtual void suspend() = 0; + + /// Set the status to Unallocated. + virtual void deallocate() = 0; + + /// Set the status to Halted. + virtual void halt() = 0; + +#if FULL_SYSTEM + virtual void dumpFuncProfile() = 0; +#endif + + virtual void takeOverFrom(ExecContext *old_context) = 0; + + virtual void regStats(const std::string &name) = 0; + + virtual void serialize(std::ostream &os) = 0; + virtual void unserialize(Checkpoint *cp, const std::string §ion) = 0; + +#if FULL_SYSTEM + virtual EndQuiesceEvent *getQuiesceEvent() = 0; + + // Not necessarily the best location for these... + // Having an extra function just to read these is obnoxious + virtual Tick readLastActivate() = 0; + virtual Tick readLastSuspend() = 0; + + virtual void profileClear() = 0; + virtual void profileSample() = 0; +#endif + + virtual int getThreadNum() = 0; + + // Also somewhat obnoxious. Really only used for the TLB fault. + // However, may be quite useful in SPARC. + virtual TheISA::MachInst getInst() = 0; + + virtual void copyArchRegs(ExecContext *xc) = 0; + + virtual void clearArchRegs() = 0; + + // + // New accessors for new decoder. + // + virtual uint64_t readIntReg(int reg_idx) = 0; + + virtual FloatReg readFloatReg(int reg_idx, int width) = 0; + + virtual FloatReg readFloatReg(int reg_idx) = 0; + + virtual FloatRegBits readFloatRegBits(int reg_idx, int width) = 0; + + virtual FloatRegBits readFloatRegBits(int reg_idx) = 0; + + virtual void setIntReg(int reg_idx, uint64_t val) = 0; + + virtual void setFloatReg(int reg_idx, FloatReg val, int width) = 0; + + virtual void setFloatReg(int reg_idx, FloatReg val) = 0; + + virtual void setFloatRegBits(int reg_idx, FloatRegBits val) = 0; + + virtual void setFloatRegBits(int reg_idx, FloatRegBits val, int width) = 0; + + virtual uint64_t readPC() = 0; + + virtual void setPC(uint64_t val) = 0; + + virtual uint64_t readNextPC() = 0; + + virtual void setNextPC(uint64_t val) = 0; + + virtual uint64_t readNextNPC() = 0; + + virtual void setNextNPC(uint64_t val) = 0; + + virtual MiscReg readMiscReg(int misc_reg) = 0; + + virtual MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault) = 0; + + virtual Fault setMiscReg(int misc_reg, const MiscReg &val) = 0; + + virtual Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val) = 0; + + // Also not necessarily the best location for these two. Hopefully will go + // away once we decide upon where st cond failures goes. + virtual unsigned readStCondFailures() = 0; + + virtual void setStCondFailures(unsigned sc_failures) = 0; + +#if FULL_SYSTEM + virtual bool inPalMode() = 0; +#endif + + // Only really makes sense for old CPU model. Still could be useful though. + virtual bool misspeculating() = 0; + +#if !FULL_SYSTEM + virtual IntReg getSyscallArg(int i) = 0; + + // used to shift args for indirect syscall + virtual void setSyscallArg(int i, IntReg val) = 0; + + virtual void setSyscallReturn(SyscallReturn return_value) = 0; + + + // Same with st cond failures. + virtual Counter readFuncExeInst() = 0; +#endif + + virtual void changeRegFileContext(RegFile::ContextParam param, + RegFile::ContextVal val) = 0; +}; + +template <class XC> +class ProxyExecContext : public ExecContext +{ + public: + ProxyExecContext(XC *actual_xc) + { actualXC = actual_xc; } + + private: + XC *actualXC; + + public: + + BaseCPU *getCpuPtr() { return actualXC->getCpuPtr(); } + + void setCpuId(int id) { actualXC->setCpuId(id); } + + int readCpuId() { return actualXC->readCpuId(); } + +#if FULL_SYSTEM + System *getSystemPtr() { return actualXC->getSystemPtr(); } + + AlphaITB *getITBPtr() { return actualXC->getITBPtr(); } + + AlphaDTB *getDTBPtr() { return actualXC->getDTBPtr(); } + + Kernel::Statistics *getKernelStats() { return actualXC->getKernelStats(); } + + FunctionalPort *getPhysPort() { return actualXC->getPhysPort(); } + + VirtualPort *getVirtPort(ExecContext *xc = NULL) { return actualXC->getVirtPort(xc); } + + void delVirtPort(VirtualPort *vp) { return actualXC->delVirtPort(vp); } +#else + TranslatingPort *getMemPort() { return actualXC->getMemPort(); } + + Process *getProcessPtr() { return actualXC->getProcessPtr(); } +#endif + + Status status() const { return actualXC->status(); } + + void setStatus(Status new_status) { actualXC->setStatus(new_status); } + + /// Set the status to Active. Optional delay indicates number of + /// cycles to wait before beginning execution. + void activate(int delay = 1) { actualXC->activate(delay); } + + /// Set the status to Suspended. + void suspend() { actualXC->suspend(); } + + /// Set the status to Unallocated. + void deallocate() { actualXC->deallocate(); } + + /// Set the status to Halted. + void halt() { actualXC->halt(); } + +#if FULL_SYSTEM + void dumpFuncProfile() { actualXC->dumpFuncProfile(); } +#endif + + void takeOverFrom(ExecContext *oldContext) + { actualXC->takeOverFrom(oldContext); } + + void regStats(const std::string &name) { actualXC->regStats(name); } + + void serialize(std::ostream &os) { actualXC->serialize(os); } + void unserialize(Checkpoint *cp, const std::string §ion) + { actualXC->unserialize(cp, section); } + +#if FULL_SYSTEM + EndQuiesceEvent *getQuiesceEvent() { return actualXC->getQuiesceEvent(); } + + Tick readLastActivate() { return actualXC->readLastActivate(); } + Tick readLastSuspend() { return actualXC->readLastSuspend(); } + + void profileClear() { return actualXC->profileClear(); } + void profileSample() { return actualXC->profileSample(); } +#endif + + int getThreadNum() { return actualXC->getThreadNum(); } + + // @todo: Do I need this? + MachInst getInst() { return actualXC->getInst(); } + + // @todo: Do I need this? + void copyArchRegs(ExecContext *xc) { actualXC->copyArchRegs(xc); } + + void clearArchRegs() { actualXC->clearArchRegs(); } + + // + // New accessors for new decoder. + // + uint64_t readIntReg(int reg_idx) + { return actualXC->readIntReg(reg_idx); } + + FloatReg readFloatReg(int reg_idx, int width) + { return actualXC->readFloatReg(reg_idx, width); } + + FloatReg readFloatReg(int reg_idx) + { return actualXC->readFloatReg(reg_idx); } + + FloatRegBits readFloatRegBits(int reg_idx, int width) + { return actualXC->readFloatRegBits(reg_idx, width); } + + FloatRegBits readFloatRegBits(int reg_idx) + { return actualXC->readFloatRegBits(reg_idx); } + + void setIntReg(int reg_idx, uint64_t val) + { actualXC->setIntReg(reg_idx, val); } + + void setFloatReg(int reg_idx, FloatReg val, int width) + { actualXC->setFloatReg(reg_idx, val, width); } + + void setFloatReg(int reg_idx, FloatReg val) + { actualXC->setFloatReg(reg_idx, val); } + + void setFloatRegBits(int reg_idx, FloatRegBits val, int width) + { actualXC->setFloatRegBits(reg_idx, val, width); } + + void setFloatRegBits(int reg_idx, FloatRegBits val) + { actualXC->setFloatRegBits(reg_idx, val); } + + uint64_t readPC() { return actualXC->readPC(); } + + void setPC(uint64_t val) { actualXC->setPC(val); } + + uint64_t readNextPC() { return actualXC->readNextPC(); } + + void setNextPC(uint64_t val) { actualXC->setNextPC(val); } + + uint64_t readNextNPC() { return actualXC->readNextNPC(); } + + void setNextNPC(uint64_t val) { actualXC->setNextNPC(val); } + + MiscReg readMiscReg(int misc_reg) + { return actualXC->readMiscReg(misc_reg); } + + MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault) + { return actualXC->readMiscRegWithEffect(misc_reg, fault); } + + Fault setMiscReg(int misc_reg, const MiscReg &val) + { return actualXC->setMiscReg(misc_reg, val); } + + Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val) + { return actualXC->setMiscRegWithEffect(misc_reg, val); } + + unsigned readStCondFailures() + { return actualXC->readStCondFailures(); } + + void setStCondFailures(unsigned sc_failures) + { actualXC->setStCondFailures(sc_failures); } +#if FULL_SYSTEM + bool inPalMode() { return actualXC->inPalMode(); } +#endif + + // @todo: Fix this! + bool misspeculating() { return actualXC->misspeculating(); } + +#if !FULL_SYSTEM + IntReg getSyscallArg(int i) { return actualXC->getSyscallArg(i); } + + // used to shift args for indirect syscall + void setSyscallArg(int i, IntReg val) + { actualXC->setSyscallArg(i, val); } + + void setSyscallReturn(SyscallReturn return_value) + { actualXC->setSyscallReturn(return_value); } + + + Counter readFuncExeInst() { return actualXC->readFuncExeInst(); } +#endif + + void changeRegFileContext(RegFile::ContextParam param, + RegFile::ContextVal val) + { + actualXC->changeRegFileContext(param, val); + } +}; + +#endif diff --git a/src/cpu/exetrace.cc b/src/cpu/exetrace.cc new file mode 100644 index 000000000..5ec05ea72 --- /dev/null +++ b/src/cpu/exetrace.cc @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <fstream> +#include <iomanip> + +#include "base/loader/symtab.hh" +#include "cpu/base.hh" +#include "cpu/exetrace.hh" +#include "cpu/static_inst.hh" +#include "sim/param.hh" +#include "sim/system.hh" + +using namespace std; + + +//////////////////////////////////////////////////////////////////////// +// +// Methods for the InstRecord object +// + + +void +Trace::InstRecord::dump(ostream &outs) +{ + if (flags[INTEL_FORMAT]) { +#if FULL_SYSTEM + bool is_trace_system = (cpu->system->name() == trace_system); +#else + bool is_trace_system = true; +#endif + if (is_trace_system) { + ccprintf(outs, "%7d ) ", cycle); + outs << "0x" << hex << PC << ":\t"; + if (staticInst->isLoad()) { + outs << "<RD 0x" << hex << addr; + outs << ">"; + } else if (staticInst->isStore()) { + outs << "<WR 0x" << hex << addr; + outs << ">"; + } + outs << endl; + } + } else { + if (flags[PRINT_CYCLE]) + ccprintf(outs, "%7d: ", cycle); + + outs << cpu->name() << " "; + + if (flags[TRACE_MISSPEC]) + outs << (misspeculating ? "-" : "+") << " "; + + if (flags[PRINT_THREAD_NUM]) + outs << "T" << thread << " : "; + + + std::string sym_str; + Addr sym_addr; + if (debugSymbolTable + && debugSymbolTable->findNearestSymbol(PC, sym_str, sym_addr) + && flags[PC_SYMBOL]) { + if (PC != sym_addr) + sym_str += csprintf("+%d", PC - sym_addr); + outs << "@" << sym_str << " : "; + } + else { + outs << "0x" << hex << PC << " : "; + } + + // + // Print decoded instruction + // + +#if defined(__GNUC__) && (__GNUC__ < 3) + // There's a bug in gcc 2.x library that prevents setw() + // from working properly on strings + string mc(staticInst->disassemble(PC, debugSymbolTable)); + while (mc.length() < 26) + mc += " "; + outs << mc; +#else + outs << setw(26) << left << staticInst->disassemble(PC, debugSymbolTable); +#endif + + outs << " : "; + + if (flags[PRINT_OP_CLASS]) { + outs << opClassStrings[staticInst->opClass()] << " : "; + } + + if (flags[PRINT_RESULT_DATA] && data_status != DataInvalid) { + outs << " D="; +#if 0 + if (data_status == DataDouble) + ccprintf(outs, "%f", data.as_double); + else + ccprintf(outs, "%#018x", data.as_int); +#else + ccprintf(outs, "%#018x", data.as_int); +#endif + } + + if (flags[PRINT_EFF_ADDR] && addr_valid) + outs << " A=0x" << hex << addr; + + if (flags[PRINT_INT_REGS] && regs_valid) { + for (int i = 0; i < TheISA::NumIntRegs;) + for (int j = i + 1; i <= j; i++) + ccprintf(outs, "r%02d = %#018x%s", i, + iregs->regs.readReg(i), + ((i == j) ? "\n" : " ")); + outs << "\n"; + } + + if (flags[PRINT_FETCH_SEQ] && fetch_seq_valid) + outs << " FetchSeq=" << dec << fetch_seq; + + if (flags[PRINT_CP_SEQ] && cp_seq_valid) + outs << " CPSeq=" << dec << cp_seq; + + // + // End of line... + // + outs << endl; + } +} + + +vector<bool> Trace::InstRecord::flags(NUM_BITS); +string Trace::InstRecord::trace_system; + +//////////////////////////////////////////////////////////////////////// +// +// Parameter space for per-cycle execution address tracing options. +// Derive from ParamContext so we can override checkParams() function. +// +class ExecutionTraceParamContext : public ParamContext +{ + public: + ExecutionTraceParamContext(const string &_iniSection) + : ParamContext(_iniSection) + { + } + + void checkParams(); // defined at bottom of file +}; + +ExecutionTraceParamContext exeTraceParams("exetrace"); + +Param<bool> exe_trace_spec(&exeTraceParams, "speculative", + "capture speculative instructions", true); + +Param<bool> exe_trace_print_cycle(&exeTraceParams, "print_cycle", + "print cycle number", true); +Param<bool> exe_trace_print_opclass(&exeTraceParams, "print_opclass", + "print op class", true); +Param<bool> exe_trace_print_thread(&exeTraceParams, "print_thread", + "print thread number", true); +Param<bool> exe_trace_print_effaddr(&exeTraceParams, "print_effaddr", + "print effective address", true); +Param<bool> exe_trace_print_data(&exeTraceParams, "print_data", + "print result data", true); +Param<bool> exe_trace_print_iregs(&exeTraceParams, "print_iregs", + "print all integer regs", false); +Param<bool> exe_trace_print_fetchseq(&exeTraceParams, "print_fetchseq", + "print fetch sequence number", false); +Param<bool> exe_trace_print_cp_seq(&exeTraceParams, "print_cpseq", + "print correct-path sequence number", false); +Param<bool> exe_trace_pc_symbol(&exeTraceParams, "pc_symbol", + "Use symbols for the PC if available", true); +Param<bool> exe_trace_intel_format(&exeTraceParams, "intel_format", + "print trace in intel compatible format", false); +Param<string> exe_trace_system(&exeTraceParams, "trace_system", + "print trace of which system (client or server)", + "client"); + + +// +// Helper function for ExecutionTraceParamContext::checkParams() just +// to get us into the InstRecord namespace +// +void +Trace::InstRecord::setParams() +{ + flags[TRACE_MISSPEC] = exe_trace_spec; + + flags[PRINT_CYCLE] = exe_trace_print_cycle; + flags[PRINT_OP_CLASS] = exe_trace_print_opclass; + flags[PRINT_THREAD_NUM] = exe_trace_print_thread; + flags[PRINT_RESULT_DATA] = exe_trace_print_effaddr; + flags[PRINT_EFF_ADDR] = exe_trace_print_data; + flags[PRINT_INT_REGS] = exe_trace_print_iregs; + flags[PRINT_FETCH_SEQ] = exe_trace_print_fetchseq; + flags[PRINT_CP_SEQ] = exe_trace_print_cp_seq; + flags[PC_SYMBOL] = exe_trace_pc_symbol; + flags[INTEL_FORMAT] = exe_trace_intel_format; + trace_system = exe_trace_system; +} + +void +ExecutionTraceParamContext::checkParams() +{ + Trace::InstRecord::setParams(); +} + diff --git a/src/cpu/exetrace.hh b/src/cpu/exetrace.hh new file mode 100644 index 000000000..7b86a9344 --- /dev/null +++ b/src/cpu/exetrace.hh @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __EXETRACE_HH__ +#define __EXETRACE_HH__ + +#include <fstream> +#include <vector> + +#include "sim/host.hh" +#include "cpu/inst_seq.hh" // for InstSeqNum +#include "base/trace.hh" +#include "cpu/exec_context.hh" +#include "cpu/static_inst.hh" + +class BaseCPU; + + +namespace Trace { + +class InstRecord : public Record +{ + protected: + typedef TheISA::IntRegFile IntRegFile; + + // The following fields are initialized by the constructor and + // thus guaranteed to be valid. + BaseCPU *cpu; + // need to make this ref-counted so it doesn't go away before we + // dump the record + StaticInstPtr staticInst; + Addr PC; + bool misspeculating; + unsigned thread; + + // The remaining fields are only valid for particular instruction + // types (e.g, addresses for memory ops) or when particular + // options are enabled (e.g., tracing full register contents). + // Each data field has an associated valid flag to indicate + // whether the data field is valid. + Addr addr; + bool addr_valid; + + union { + uint64_t as_int; + double as_double; + } data; + enum { + DataInvalid = 0, + DataInt8 = 1, // set to equal number of bytes + DataInt16 = 2, + DataInt32 = 4, + DataInt64 = 8, + DataDouble = 3 + } data_status; + + InstSeqNum fetch_seq; + bool fetch_seq_valid; + + InstSeqNum cp_seq; + bool cp_seq_valid; + + struct iRegFile { + IntRegFile regs; + }; + iRegFile *iregs; + bool regs_valid; + + public: + InstRecord(Tick _cycle, BaseCPU *_cpu, + const StaticInstPtr &_staticInst, + Addr _pc, bool spec, int _thread) + : Record(_cycle), cpu(_cpu), staticInst(_staticInst), PC(_pc), + misspeculating(spec), thread(_thread) + { + data_status = DataInvalid; + addr_valid = false; + regs_valid = false; + + fetch_seq_valid = false; + cp_seq_valid = false; + } + + virtual ~InstRecord() { } + + virtual void dump(std::ostream &outs); + + void setAddr(Addr a) { addr = a; addr_valid = true; } + + void setData(uint64_t d) { data.as_int = d; data_status = DataInt64; } + void setData(uint32_t d) { data.as_int = d; data_status = DataInt32; } + void setData(uint16_t d) { data.as_int = d; data_status = DataInt16; } + void setData(uint8_t d) { data.as_int = d; data_status = DataInt8; } + + void setData(int64_t d) { setData((uint64_t)d); } + void setData(int32_t d) { setData((uint32_t)d); } + void setData(int16_t d) { setData((uint16_t)d); } + void setData(int8_t d) { setData((uint8_t)d); } + + void setData(double d) { data.as_double = d; data_status = DataDouble; } + + void setFetchSeq(InstSeqNum seq) + { fetch_seq = seq; fetch_seq_valid = true; } + + void setCPSeq(InstSeqNum seq) + { cp_seq = seq; cp_seq_valid = true; } + + void setRegs(const IntRegFile ®s); + + void finalize() { theLog.append(this); } + + enum InstExecFlagBits { + TRACE_MISSPEC = 0, + PRINT_CYCLE, + PRINT_OP_CLASS, + PRINT_THREAD_NUM, + PRINT_RESULT_DATA, + PRINT_EFF_ADDR, + PRINT_INT_REGS, + PRINT_FETCH_SEQ, + PRINT_CP_SEQ, + PC_SYMBOL, + INTEL_FORMAT, + NUM_BITS + }; + + static std::vector<bool> flags; + static std::string trace_system; + + static void setParams(); + + static bool traceMisspec() { return flags[TRACE_MISSPEC]; } +}; + + +inline void +InstRecord::setRegs(const IntRegFile ®s) +{ + if (!iregs) + iregs = new iRegFile; + + memcpy(&iregs->regs, ®s, sizeof(IntRegFile)); + regs_valid = true; +} + +inline +InstRecord * +getInstRecord(Tick cycle, ExecContext *xc, BaseCPU *cpu, + const StaticInstPtr staticInst, + Addr pc, int thread = 0) +{ + if (DTRACE(InstExec) && + (InstRecord::traceMisspec() || !xc->misspeculating())) { + return new InstRecord(cycle, cpu, staticInst, pc, + xc->misspeculating(), thread); + } + + return NULL; +} + + +} + +#endif // __EXETRACE_HH__ diff --git a/cpu/inst_seq.hh b/src/cpu/inst_seq.hh index 356d19df0..356d19df0 100644 --- a/cpu/inst_seq.hh +++ b/src/cpu/inst_seq.hh diff --git a/cpu/intr_control.cc b/src/cpu/intr_control.cc index 43e7f654c..43e7f654c 100644 --- a/cpu/intr_control.cc +++ b/src/cpu/intr_control.cc diff --git a/cpu/intr_control.hh b/src/cpu/intr_control.hh index 5ec4e14cb..5ec4e14cb 100644 --- a/cpu/intr_control.hh +++ b/src/cpu/intr_control.hh diff --git a/src/cpu/memtest/memtest.cc b/src/cpu/memtest/memtest.cc new file mode 100644 index 000000000..54def1012 --- /dev/null +++ b/src/cpu/memtest/memtest.cc @@ -0,0 +1,440 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// FIX ME: make trackBlkAddr use blocksize from actual cache, not hard coded + +#include <iomanip> +#include <set> +#include <string> +#include <vector> + +#include "base/misc.hh" +#include "base/statistics.hh" +#include "cpu/cpu_exec_context.hh" +#include "cpu/memtest/memtest.hh" +#include "mem/cache/base_cache.hh" +#include "sim/builder.hh" +#include "sim/sim_events.hh" +#include "sim/stats.hh" + +using namespace std; +using namespace TheISA; + +int TESTER_ALLOCATOR=0; + +MemTest::MemTest(const string &name, + MemInterface *_cache_interface, + FunctionalMemory *main_mem, + FunctionalMemory *check_mem, + unsigned _memorySize, + unsigned _percentReads, + unsigned _percentCopies, + unsigned _percentUncacheable, + unsigned _progressInterval, + unsigned _percentSourceUnaligned, + unsigned _percentDestUnaligned, + Addr _traceAddr, + Counter _max_loads) + : SimObject(name), + tickEvent(this), + cacheInterface(_cache_interface), + mainMem(main_mem), + checkMem(check_mem), + size(_memorySize), + percentReads(_percentReads), + percentCopies(_percentCopies), + percentUncacheable(_percentUncacheable), + progressInterval(_progressInterval), + nextProgressMessage(_progressInterval), + percentSourceUnaligned(_percentSourceUnaligned), + percentDestUnaligned(percentDestUnaligned), + maxLoads(_max_loads) +{ + vector<string> cmd; + cmd.push_back("/bin/ls"); + vector<string> null_vec; + cpuXC = new CPUExecContext(NULL, 0, mainMem, 0); + + blockSize = cacheInterface->getBlockSize(); + blockAddrMask = blockSize - 1; + traceBlockAddr = blockAddr(_traceAddr); + + //setup data storage with interesting values + uint8_t *data1 = new uint8_t[size]; + uint8_t *data2 = new uint8_t[size]; + uint8_t *data3 = new uint8_t[size]; + memset(data1, 1, size); + memset(data2, 2, size); + memset(data3, 3, size); + curTick = 0; + + baseAddr1 = 0x100000; + baseAddr2 = 0x400000; + uncacheAddr = 0x800000; + + // set up intial memory contents here + mainMem->prot_write(baseAddr1, data1, size); + checkMem->prot_write(baseAddr1, data1, size); + mainMem->prot_write(baseAddr2, data2, size); + checkMem->prot_write(baseAddr2, data2, size); + mainMem->prot_write(uncacheAddr, data3, size); + checkMem->prot_write(uncacheAddr, data3, size); + + delete [] data1; + delete [] data2; + delete [] data3; + + // set up counters + noResponseCycles = 0; + numReads = 0; + tickEvent.schedule(0); + + id = TESTER_ALLOCATOR++; +} + +static void +printData(ostream &os, uint8_t *data, int nbytes) +{ + os << hex << setfill('0'); + // assume little-endian: print bytes from highest address to lowest + for (uint8_t *dp = data + nbytes - 1; dp >= data; --dp) { + os << setw(2) << (unsigned)*dp; + } + os << dec; +} + +void +MemTest::completeRequest(MemReqPtr &req, uint8_t *data) +{ + //Remove the address from the list of outstanding + std::set<unsigned>::iterator removeAddr = outstandingAddrs.find(req->paddr); + assert(removeAddr != outstandingAddrs.end()); + outstandingAddrs.erase(removeAddr); + + switch (req->cmd) { + case Read: + if (memcmp(req->data, data, req->size) != 0) { + cerr << name() << ": on read of 0x" << hex << req->paddr + << " (0x" << hex << blockAddr(req->paddr) << ")" + << "@ cycle " << dec << curTick + << ", cache returns 0x"; + printData(cerr, req->data, req->size); + cerr << ", expected 0x"; + printData(cerr, data, req->size); + cerr << endl; + fatal(""); + } + + numReads++; + numReadsStat++; + + if (numReads == nextProgressMessage) { + ccprintf(cerr, "%s: completed %d read accesses @%d\n", + name(), numReads, curTick); + nextProgressMessage += progressInterval; + } + + if (numReads >= maxLoads) + SimExit(curTick, "Maximum number of loads reached!"); + break; + + case Write: + numWritesStat++; + break; + + case Copy: + //Also remove dest from outstanding list + removeAddr = outstandingAddrs.find(req->dest); + assert(removeAddr != outstandingAddrs.end()); + outstandingAddrs.erase(removeAddr); + numCopiesStat++; + break; + + default: + panic("invalid command"); + } + + if (blockAddr(req->paddr) == traceBlockAddr) { + cerr << name() << ": completed " + << (req->cmd.isWrite() ? "write" : "read") + << " access of " + << dec << req->size << " bytes at address 0x" + << hex << req->paddr + << " (0x" << hex << blockAddr(req->paddr) << ")" + << ", value = 0x"; + printData(cerr, req->data, req->size); + cerr << " @ cycle " << dec << curTick; + + cerr << endl; + } + + noResponseCycles = 0; + delete [] data; +} + + +void +MemTest::regStats() +{ + using namespace Stats; + + + numReadsStat + .name(name() + ".num_reads") + .desc("number of read accesses completed") + ; + + numWritesStat + .name(name() + ".num_writes") + .desc("number of write accesses completed") + ; + + numCopiesStat + .name(name() + ".num_copies") + .desc("number of copy accesses completed") + ; +} + +void +MemTest::tick() +{ + if (!tickEvent.scheduled()) + tickEvent.schedule(curTick + cycles(1)); + + if (++noResponseCycles >= 500000) { + cerr << name() << ": deadlocked at cycle " << curTick << endl; + fatal(""); + } + + if (cacheInterface->isBlocked()) { + return; + } + + //make new request + unsigned cmd = random() % 100; + unsigned offset = random() % size; + unsigned base = random() % 2; + uint64_t data = random(); + unsigned access_size = random() % 4; + unsigned cacheable = random() % 100; + + //If we aren't doing copies, use id as offset, and do a false sharing + //mem tester + if (percentCopies == 0) { + //We can eliminate the lower bits of the offset, and then use the id + //to offset within the blks + offset &= ~63; //Not the low order bits + offset += id; + access_size = 0; + } + + MemReqPtr req = new MemReq(); + + if (cacheable < percentUncacheable) { + req->flags |= UNCACHEABLE; + req->paddr = uncacheAddr + offset; + } else { + req->paddr = ((base) ? baseAddr1 : baseAddr2) + offset; + } + // bool probe = (random() % 2 == 1) && !req->isUncacheable(); + bool probe = false; + + req->size = 1 << access_size; + req->data = new uint8_t[req->size]; + req->paddr &= ~(req->size - 1); + req->time = curTick; + req->xc = cpuXC->getProxy(); + + if (cmd < percentReads) { + // read + + //For now we only allow one outstanding request per addreess per tester + //This means we assume CPU does write forwarding to reads that alias something + //in the cpu store buffer. + if (outstandingAddrs.find(req->paddr) != outstandingAddrs.end()) return; + else outstandingAddrs.insert(req->paddr); + + req->cmd = Read; + uint8_t *result = new uint8_t[8]; + checkMem->access(Read, req->paddr, result, req->size); + if (blockAddr(req->paddr) == traceBlockAddr) { + cerr << name() + << ": initiating read " + << ((probe) ? "probe of " : "access of ") + << dec << req->size << " bytes from addr 0x" + << hex << req->paddr + << " (0x" << hex << blockAddr(req->paddr) << ")" + << " at cycle " + << dec << curTick << endl; + } + if (probe) { + cacheInterface->probeAndUpdate(req); + completeRequest(req, result); + } else { + req->completionEvent = new MemCompleteEvent(req, result, this); + cacheInterface->access(req); + } + } else if (cmd < (100 - percentCopies)){ + // write + + //For now we only allow one outstanding request per addreess per tester + //This means we assume CPU does write forwarding to reads that alias something + //in the cpu store buffer. + if (outstandingAddrs.find(req->paddr) != outstandingAddrs.end()) return; + else outstandingAddrs.insert(req->paddr); + + req->cmd = Write; + memcpy(req->data, &data, req->size); + checkMem->access(Write, req->paddr, req->data, req->size); + if (blockAddr(req->paddr) == traceBlockAddr) { + cerr << name() << ": initiating write " + << ((probe)?"probe of ":"access of ") + << dec << req->size << " bytes (value = 0x"; + printData(cerr, req->data, req->size); + cerr << ") to addr 0x" + << hex << req->paddr + << " (0x" << hex << blockAddr(req->paddr) << ")" + << " at cycle " + << dec << curTick << endl; + } + if (probe) { + cacheInterface->probeAndUpdate(req); + completeRequest(req, NULL); + } else { + req->completionEvent = new MemCompleteEvent(req, NULL, this); + cacheInterface->access(req); + } + } else { + // copy + unsigned source_align = random() % 100; + unsigned dest_align = random() % 100; + unsigned offset2 = random() % size; + + Addr source = ((base) ? baseAddr1 : baseAddr2) + offset; + Addr dest = ((base) ? baseAddr2 : baseAddr1) + offset2; + if (outstandingAddrs.find(source) != outstandingAddrs.end()) return; + else outstandingAddrs.insert(source); + if (outstandingAddrs.find(dest) != outstandingAddrs.end()) return; + else outstandingAddrs.insert(dest); + + if (source_align >= percentSourceUnaligned) { + source = blockAddr(source); + } + if (dest_align >= percentDestUnaligned) { + dest = blockAddr(dest); + } + req->cmd = Copy; + req->flags &= ~UNCACHEABLE; + req->paddr = source; + req->dest = dest; + delete [] req->data; + req->data = new uint8_t[blockSize]; + req->size = blockSize; + if (source == traceBlockAddr || dest == traceBlockAddr) { + cerr << name() + << ": initiating copy of " + << dec << req->size << " bytes from addr 0x" + << hex << source + << " (0x" << hex << blockAddr(source) << ")" + << " to addr 0x" + << hex << dest + << " (0x" << hex << blockAddr(dest) << ")" + << " at cycle " + << dec << curTick << endl; + } + cacheInterface->access(req); + uint8_t result[blockSize]; + checkMem->access(Read, source, &result, blockSize); + checkMem->access(Write, dest, &result, blockSize); + } +} + + +void +MemCompleteEvent::process() +{ + tester->completeRequest(req, data); + delete this; +} + + +const char * +MemCompleteEvent::description() +{ + return "memory access completion"; +} + + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(MemTest) + + SimObjectParam<BaseCache *> cache; + SimObjectParam<FunctionalMemory *> main_mem; + SimObjectParam<FunctionalMemory *> check_mem; + Param<unsigned> memory_size; + Param<unsigned> percent_reads; + Param<unsigned> percent_copies; + Param<unsigned> percent_uncacheable; + Param<unsigned> progress_interval; + Param<unsigned> percent_source_unaligned; + Param<unsigned> percent_dest_unaligned; + Param<Addr> trace_addr; + Param<Counter> max_loads; + +END_DECLARE_SIM_OBJECT_PARAMS(MemTest) + + +BEGIN_INIT_SIM_OBJECT_PARAMS(MemTest) + + INIT_PARAM(cache, "L1 cache"), + INIT_PARAM(main_mem, "hierarchical memory"), + INIT_PARAM(check_mem, "check memory"), + INIT_PARAM(memory_size, "memory size"), + INIT_PARAM(percent_reads, "target read percentage"), + INIT_PARAM(percent_copies, "target copy percentage"), + INIT_PARAM(percent_uncacheable, "target uncacheable percentage"), + INIT_PARAM(progress_interval, "progress report interval (in accesses)"), + INIT_PARAM(percent_source_unaligned, + "percent of copy source address that are unaligned"), + INIT_PARAM(percent_dest_unaligned, + "percent of copy dest address that are unaligned"), + INIT_PARAM(trace_addr, "address to trace"), + INIT_PARAM(max_loads, "terminate when we have reached this load count") + +END_INIT_SIM_OBJECT_PARAMS(MemTest) + + +CREATE_SIM_OBJECT(MemTest) +{ + return new MemTest(getInstanceName(), cache->getInterface(), main_mem, + check_mem, memory_size, percent_reads, percent_copies, + percent_uncacheable, progress_interval, + percent_source_unaligned, percent_dest_unaligned, + trace_addr, max_loads); +} + +REGISTER_SIM_OBJECT("MemTest", MemTest) diff --git a/cpu/memtest/memtest.hh b/src/cpu/memtest/memtest.hh index cdb40a26a..cdb40a26a 100644 --- a/cpu/memtest/memtest.hh +++ b/src/cpu/memtest/memtest.hh diff --git a/cpu/o3/2bit_local_pred.cc b/src/cpu/o3/2bit_local_pred.cc index c3fb2fdb8..c3fb2fdb8 100644 --- a/cpu/o3/2bit_local_pred.cc +++ b/src/cpu/o3/2bit_local_pred.cc diff --git a/cpu/o3/2bit_local_pred.hh b/src/cpu/o3/2bit_local_pred.hh index cd65978ca..cd65978ca 100644 --- a/cpu/o3/2bit_local_pred.hh +++ b/src/cpu/o3/2bit_local_pred.hh diff --git a/cpu/o3/alpha_cpu.cc b/src/cpu/o3/alpha_cpu.cc index 7bc90dae6..7bc90dae6 100644 --- a/cpu/o3/alpha_cpu.cc +++ b/src/cpu/o3/alpha_cpu.cc diff --git a/src/cpu/o3/alpha_cpu.hh b/src/cpu/o3/alpha_cpu.hh new file mode 100644 index 000000000..1bab0703e --- /dev/null +++ b/src/cpu/o3/alpha_cpu.hh @@ -0,0 +1,430 @@ +/* + * Copyright (c) 2004-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __CPU_O3_ALPHA_FULL_CPU_HH__ +#define __CPU_O3_ALPHA_FULL_CPU_HH__ + +#include "arch/isa_traits.hh" +#include "cpu/exec_context.hh" +#include "cpu/o3/cpu.hh" +#include "sim/byteswap.hh" + +class EndQuiesceEvent; +namespace Kernel { + class Statistics; +}; + +template <class Impl> +class AlphaFullCPU : public FullO3CPU<Impl> +{ + protected: + typedef TheISA::IntReg IntReg; + typedef TheISA::MiscReg MiscReg; + typedef TheISA::RegFile RegFile; + typedef TheISA::MiscRegFile MiscRegFile; + + public: + typedef O3ThreadState<Impl> ImplState; + typedef O3ThreadState<Impl> Thread; + typedef typename Impl::Params Params; + + /** Constructs an AlphaFullCPU with the given parameters. */ + AlphaFullCPU(Params *params); + + class AlphaXC : public ExecContext + { + public: + AlphaFullCPU<Impl> *cpu; + + O3ThreadState<Impl> *thread; + + virtual BaseCPU *getCpuPtr() { return cpu; } + + virtual void setCpuId(int id) { cpu->cpu_id = id; } + + virtual int readCpuId() { return cpu->cpu_id; } + + virtual FunctionalMemory *getMemPtr() { return thread->mem; } + +#if FULL_SYSTEM + virtual System *getSystemPtr() { return cpu->system; } + + virtual PhysicalMemory *getPhysMemPtr() { return cpu->physmem; } + + virtual AlphaITB *getITBPtr() { return cpu->itb; } + + virtual AlphaDTB * getDTBPtr() { return cpu->dtb; } + + virtual Kernel::Statistics *getKernelStats() + { return thread->kernelStats; } +#else + virtual Process *getProcessPtr() { return thread->process; } +#endif + + virtual Status status() const { return thread->status(); } + + virtual void setStatus(Status new_status) + { thread->setStatus(new_status); } + + /// Set the status to Active. Optional delay indicates number of + /// cycles to wait before beginning execution. + virtual void activate(int delay = 1); + + /// Set the status to Suspended. + virtual void suspend(); + + /// Set the status to Unallocated. + virtual void deallocate(); + + /// Set the status to Halted. + virtual void halt(); + +#if FULL_SYSTEM + virtual void dumpFuncProfile(); +#endif + + virtual void takeOverFrom(ExecContext *old_context); + + virtual void regStats(const std::string &name); + + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); + +#if FULL_SYSTEM + virtual EndQuiesceEvent *getQuiesceEvent(); + + virtual Tick readLastActivate(); + virtual Tick readLastSuspend(); + + virtual void profileClear(); + virtual void profileSample(); +#endif + + virtual int getThreadNum() { return thread->tid; } + + virtual TheISA::MachInst getInst(); + + virtual void copyArchRegs(ExecContext *xc); + + virtual void clearArchRegs(); + + virtual uint64_t readIntReg(int reg_idx); + + virtual float readFloatRegSingle(int reg_idx); + + virtual double readFloatRegDouble(int reg_idx); + + virtual uint64_t readFloatRegInt(int reg_idx); + + virtual void setIntReg(int reg_idx, uint64_t val); + + virtual void setFloatRegSingle(int reg_idx, float val); + + virtual void setFloatRegDouble(int reg_idx, double val); + + virtual void setFloatRegInt(int reg_idx, uint64_t val); + + virtual uint64_t readPC() + { return cpu->readPC(thread->tid); } + + virtual void setPC(uint64_t val); + + virtual uint64_t readNextPC() + { return cpu->readNextPC(thread->tid); } + + virtual void setNextPC(uint64_t val); + + virtual MiscReg readMiscReg(int misc_reg) + { return cpu->readMiscReg(misc_reg, thread->tid); } + + virtual MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault) + { return cpu->readMiscRegWithEffect(misc_reg, fault, thread->tid); } + + virtual Fault setMiscReg(int misc_reg, const MiscReg &val); + + virtual Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val); + + // @todo: Figure out where these store cond failures should go. + virtual unsigned readStCondFailures() + { return thread->storeCondFailures; } + + virtual void setStCondFailures(unsigned sc_failures) + { thread->storeCondFailures = sc_failures; } + +#if FULL_SYSTEM + virtual bool inPalMode() + { return TheISA::PcPAL(cpu->readPC(thread->tid)); } +#endif + + // Only really makes sense for old CPU model. Lots of code + // outside the CPU still checks this function, so it will + // always return false to keep everything working. + virtual bool misspeculating() { return false; } + +#if !FULL_SYSTEM + virtual IntReg getSyscallArg(int i); + + virtual void setSyscallArg(int i, IntReg val); + + virtual void setSyscallReturn(SyscallReturn return_value); + + virtual void syscall() { return cpu->syscall(thread->tid); } + + virtual Counter readFuncExeInst() { return thread->funcExeInst; } +#endif + }; + +#if FULL_SYSTEM + /** ITB pointer. */ + AlphaITB *itb; + /** DTB pointer. */ + AlphaDTB *dtb; +#endif + + /** Registers statistics. */ + void regStats(); + +#if FULL_SYSTEM + /** Translates instruction requestion. */ + Fault translateInstReq(MemReqPtr &req) + { + return itb->translate(req); + } + + /** Translates data read request. */ + Fault translateDataReadReq(MemReqPtr &req) + { + return dtb->translate(req, false); + } + + /** Translates data write request. */ + Fault translateDataWriteReq(MemReqPtr &req) + { + return dtb->translate(req, true); + } + +#else + Fault dummyTranslation(MemReqPtr &req) + { +#if 0 + assert((req->vaddr >> 48 & 0xffff) == 0); +#endif + + // put the asid in the upper 16 bits of the paddr + req->paddr = req->vaddr & ~((Addr)0xffff << sizeof(Addr) * 8 - 16); + req->paddr = req->paddr | (Addr)req->asid << sizeof(Addr) * 8 - 16; + return NoFault; + } + + /** Translates instruction requestion in syscall emulation mode. */ + Fault translateInstReq(MemReqPtr &req) + { + return dummyTranslation(req); + } + + /** Translates data read request in syscall emulation mode. */ + Fault translateDataReadReq(MemReqPtr &req) + { + return dummyTranslation(req); + } + + /** Translates data write request in syscall emulation mode. */ + Fault translateDataWriteReq(MemReqPtr &req) + { + return dummyTranslation(req); + } + +#endif + MiscReg readMiscReg(int misc_reg, unsigned tid); + + MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault, unsigned tid); + + Fault setMiscReg(int misc_reg, const MiscReg &val, unsigned tid); + + Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val, unsigned tid); + + void squashFromXC(unsigned tid); + +#if FULL_SYSTEM + void post_interrupt(int int_num, int index); + + int readIntrFlag(); + /** Sets the interrupt flags. */ + void setIntrFlag(int val); + /** HW return from error interrupt. */ + Fault hwrei(unsigned tid); + /** Returns if a specific PC is a PAL mode PC. */ + bool inPalMode(uint64_t PC) + { return AlphaISA::PcPAL(PC); } + + /** Traps to handle given fault. */ + void trap(Fault fault, unsigned tid); + bool simPalCheck(int palFunc, unsigned tid); + + /** Processes any interrupts. */ + void processInterrupts(); + + /** Halts the CPU. */ + void halt() { panic("Halt not implemented!\n"); } +#endif + + +#if !FULL_SYSTEM + /** Executes a syscall. + * @todo: Determine if this needs to be virtual. + */ + void syscall(int thread_num); + /** Gets a syscall argument. */ + IntReg getSyscallArg(int i, int tid); + + /** Used to shift args for indirect syscall. */ + void setSyscallArg(int i, IntReg val, int tid); + + /** Sets the return value of a syscall. */ + void setSyscallReturn(SyscallReturn return_value, int tid); +#endif + + /** Read from memory function. */ + template <class T> + Fault read(MemReqPtr &req, T &data) + { +#if 0 +#if FULL_SYSTEM && THE_ISA == ALPHA_ISA + if (req->flags & LOCKED) { + req->xc->setMiscReg(TheISA::Lock_Addr_DepTag, req->paddr); + req->xc->setMiscReg(TheISA::Lock_Flag_DepTag, true); + } +#endif +#endif + Fault error; + +#if FULL_SYSTEM + // @todo: Fix this LL/SC hack. + if (req->flags & LOCKED) { + lockAddr = req->paddr; + lockFlag = true; + } +#endif + + error = this->mem->read(req, data); + data = gtoh(data); + return error; + } + + /** CPU read function, forwards read to LSQ. */ + template <class T> + Fault read(MemReqPtr &req, T &data, int load_idx) + { + return this->iew.ldstQueue.read(req, data, load_idx); + } + + /** Write to memory function. */ + template <class T> + Fault write(MemReqPtr &req, T &data) + { +#if 0 +#if FULL_SYSTEM && THE_ISA == ALPHA_ISA + ExecContext *xc; + + // If this is a store conditional, act appropriately + if (req->flags & LOCKED) { + xc = req->xc; + + if (req->flags & UNCACHEABLE) { + // Don't update result register (see stq_c in isa_desc) + req->result = 2; + xc->setStCondFailures(0);//Needed? [RGD] + } else { + bool lock_flag = xc->readMiscReg(TheISA::Lock_Flag_DepTag); + Addr lock_addr = xc->readMiscReg(TheISA::Lock_Addr_DepTag); + req->result = lock_flag; + if (!lock_flag || + ((lock_addr & ~0xf) != (req->paddr & ~0xf))) { + xc->setMiscReg(TheISA::Lock_Flag_DepTag, false); + xc->setStCondFailures(xc->readStCondFailures() + 1); + if (((xc->readStCondFailures()) % 100000) == 0) { + std::cerr << "Warning: " + << xc->readStCondFailures() + << " consecutive store conditional failures " + << "on cpu " << req->xc->readCpuId() + << std::endl; + } + return NoFault; + } + else xc->setStCondFailures(0); + } + } + + // Need to clear any locked flags on other proccessors for + // this address. Only do this for succsful Store Conditionals + // and all other stores (WH64?). Unsuccessful Store + // Conditionals would have returned above, and wouldn't fall + // through. + for (int i = 0; i < this->system->execContexts.size(); i++){ + xc = this->system->execContexts[i]; + if ((xc->readMiscReg(TheISA::Lock_Addr_DepTag) & ~0xf) == + (req->paddr & ~0xf)) { + xc->setMiscReg(TheISA::Lock_Flag_DepTag, false); + } + } + +#endif +#endif + +#if FULL_SYSTEM + // @todo: Fix this LL/SC hack. + if (req->flags & LOCKED) { + if (req->flags & UNCACHEABLE) { + req->result = 2; + } else { + if (this->lockFlag) { + req->result = 1; + } else { + req->result = 0; + return NoFault; + } + } + } +#endif + + return this->mem->write(req, (T)htog(data)); + } + + /** CPU write function, forwards write to LSQ. */ + template <class T> + Fault write(MemReqPtr &req, T &data, int store_idx) + { + return this->iew.ldstQueue.write(req, data, store_idx); + } + + Addr lockAddr; + + bool lockFlag; +}; + +#endif // __CPU_O3_ALPHA_FULL_CPU_HH__ diff --git a/cpu/o3/alpha_cpu_builder.cc b/src/cpu/o3/alpha_cpu_builder.cc index b0d812edc..b0d812edc 100644 --- a/cpu/o3/alpha_cpu_builder.cc +++ b/src/cpu/o3/alpha_cpu_builder.cc diff --git a/src/cpu/o3/alpha_cpu_impl.hh b/src/cpu/o3/alpha_cpu_impl.hh new file mode 100644 index 000000000..f7f0a3842 --- /dev/null +++ b/src/cpu/o3/alpha_cpu_impl.hh @@ -0,0 +1,775 @@ +/* + * Copyright (c) 2004-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "arch/alpha/faults.hh" +#include "base/cprintf.hh" +#include "base/statistics.hh" +#include "base/timebuf.hh" +#include "cpu/checker/exec_context.hh" +#include "mem/mem_interface.hh" +#include "sim/sim_events.hh" +#include "sim/stats.hh" + +#include "cpu/o3/alpha_cpu.hh" +#include "cpu/o3/alpha_params.hh" +#include "cpu/o3/comm.hh" +#include "cpu/o3/thread_state.hh" + +#if FULL_SYSTEM +#include "arch/alpha/osfpal.hh" +#include "arch/isa_traits.hh" +#include "cpu/quiesce_event.hh" +#include "kern/kernel_stats.hh" +#endif + +using namespace TheISA; + +template <class Impl> +AlphaFullCPU<Impl>::AlphaFullCPU(Params *params) +#if FULL_SYSTEM + : FullO3CPU<Impl>(params), itb(params->itb), dtb(params->dtb) +#else + : FullO3CPU<Impl>(params) +#endif +{ + DPRINTF(FullCPU, "AlphaFullCPU: Creating AlphaFullCPU object.\n"); + + this->thread.resize(this->numThreads); + + for (int i = 0; i < this->numThreads; ++i) { +#if FULL_SYSTEM + assert(this->numThreads == 1); + this->thread[i] = new Thread(this, 0, params->mem); + this->thread[i]->setStatus(ExecContext::Suspended); +#else + if (i < params->workload.size()) { + DPRINTF(FullCPU, "FullCPU: Workload[%i]'s starting PC is %#x, " + "process is %#x", + i, params->workload[i]->prog_entry, this->thread[i]); + this->thread[i] = new Thread(this, i, params->workload[i], i); + assert(params->workload[i]->getMemory() != NULL); + + this->thread[i]->setStatus(ExecContext::Suspended); + //usedTids[i] = true; + //threadMap[i] = i; + } else { + //Allocate Empty execution context so M5 can use later + //when scheduling threads to CPU + Process* dummy_proc = NULL; + + this->thread[i] = new Thread(this, i, dummy_proc, i); + //usedTids[i] = false; + } +#endif // !FULL_SYSTEM + + this->thread[i]->numInst = 0; + + ExecContext *xc_proxy; + + AlphaXC *alpha_xc_proxy = new AlphaXC; + + if (params->checker) { + xc_proxy = new CheckerExecContext<AlphaXC>(alpha_xc_proxy, this->checker); + } else { + xc_proxy = alpha_xc_proxy; + } + + alpha_xc_proxy->cpu = this; + alpha_xc_proxy->thread = this->thread[i]; + +#if FULL_SYSTEM + this->thread[i]->quiesceEvent = + new EndQuiesceEvent(xc_proxy); + this->thread[i]->lastActivate = 0; + this->thread[i]->lastSuspend = 0; +#endif + this->thread[i]->xcProxy = xc_proxy; + + this->execContexts.push_back(xc_proxy); + } + + + for (int i=0; i < this->numThreads; i++) { + this->thread[i]->funcExeInst = 0; + } + + // Sets CPU pointers. These must be set at this level because the CPU + // pointers are defined to be the highest level of CPU class. + this->fetch.setCPU(this); + this->decode.setCPU(this); + this->rename.setCPU(this); + this->iew.setCPU(this); + this->commit.setCPU(this); + + this->rob.setCPU(this); + this->regFile.setCPU(this); + + lockAddr = 0; + lockFlag = false; +} + +template <class Impl> +void +AlphaFullCPU<Impl>::regStats() +{ + // Register stats for everything that has stats. + this->fullCPURegStats(); + this->fetch.regStats(); + this->decode.regStats(); + this->rename.regStats(); + this->iew.regStats(); + this->commit.regStats(); +} + +#if FULL_SYSTEM +template <class Impl> +void +AlphaFullCPU<Impl>::AlphaXC::dumpFuncProfile() +{ + // Currently not supported +} +#endif + +template <class Impl> +void +AlphaFullCPU<Impl>::AlphaXC::takeOverFrom(ExecContext *old_context) +{ + // some things should already be set up + assert(getMemPtr() == old_context->getMemPtr()); +#if FULL_SYSTEM + assert(getSystemPtr() == old_context->getSystemPtr()); +#else + assert(getProcessPtr() == old_context->getProcessPtr()); +#endif + + // copy over functional state + setStatus(old_context->status()); + copyArchRegs(old_context); + setCpuId(old_context->readCpuId()); +#if !FULL_SYSTEM + thread->funcExeInst = old_context->readFuncExeInst(); +#else + EndQuiesceEvent *other_quiesce = old_context->getQuiesceEvent(); + if (other_quiesce) { + // Point the quiesce event's XC at this XC so that it wakes up + // the proper CPU. + other_quiesce->xc = this; + } + if (thread->quiesceEvent) { + thread->quiesceEvent->xc = this; + } + + // Transfer kernel stats from one CPU to the other. + thread->kernelStats = old_context->getKernelStats(); +// storeCondFailures = 0; + cpu->lockFlag = false; +#endif + + old_context->setStatus(ExecContext::Unallocated); + + thread->inSyscall = false; + thread->trapPending = false; +} + +template <class Impl> +void +AlphaFullCPU<Impl>::AlphaXC::activate(int delay) +{ + DPRINTF(FullCPU, "Calling activate on AlphaXC\n"); + + if (thread->status() == ExecContext::Active) + return; + +#if FULL_SYSTEM + thread->lastActivate = curTick; +#endif + + if (thread->status() == ExecContext::Unallocated) { + cpu->activateWhenReady(thread->tid); + return; + } + + thread->setStatus(ExecContext::Active); + + // status() == Suspended + cpu->activateContext(thread->tid, delay); +} + +template <class Impl> +void +AlphaFullCPU<Impl>::AlphaXC::suspend() +{ + DPRINTF(FullCPU, "Calling suspend on AlphaXC\n"); + + if (thread->status() == ExecContext::Suspended) + return; + +#if FULL_SYSTEM + thread->lastActivate = curTick; + thread->lastSuspend = curTick; +#endif +/* +#if FULL_SYSTEM + // Don't change the status from active if there are pending interrupts + if (cpu->check_interrupts()) { + assert(status() == ExecContext::Active); + return; + } +#endif +*/ + thread->setStatus(ExecContext::Suspended); + cpu->suspendContext(thread->tid); +} + +template <class Impl> +void +AlphaFullCPU<Impl>::AlphaXC::deallocate() +{ + DPRINTF(FullCPU, "Calling deallocate on AlphaXC\n"); + + if (thread->status() == ExecContext::Unallocated) + return; + + thread->setStatus(ExecContext::Unallocated); + cpu->deallocateContext(thread->tid); +} + +template <class Impl> +void +AlphaFullCPU<Impl>::AlphaXC::halt() +{ + DPRINTF(FullCPU, "Calling halt on AlphaXC\n"); + + if (thread->status() == ExecContext::Halted) + return; + + thread->setStatus(ExecContext::Halted); + cpu->haltContext(thread->tid); +} + +template <class Impl> +void +AlphaFullCPU<Impl>::AlphaXC::regStats(const std::string &name) +{ +#if FULL_SYSTEM + thread->kernelStats = new Kernel::Statistics(cpu->system); + thread->kernelStats->regStats(name + ".kern"); +#endif +} + +template <class Impl> +void +AlphaFullCPU<Impl>::AlphaXC::serialize(std::ostream &os) +{ +#if FULL_SYSTEM + if (thread->kernelStats) + thread->kernelStats->serialize(os); +#endif + +} + +template <class Impl> +void +AlphaFullCPU<Impl>::AlphaXC::unserialize(Checkpoint *cp, const std::string §ion) +{ +#if FULL_SYSTEM + if (thread->kernelStats) + thread->kernelStats->unserialize(cp, section); +#endif + +} + +#if FULL_SYSTEM +template <class Impl> +EndQuiesceEvent * +AlphaFullCPU<Impl>::AlphaXC::getQuiesceEvent() +{ + return thread->quiesceEvent; +} + +template <class Impl> +Tick +AlphaFullCPU<Impl>::AlphaXC::readLastActivate() +{ + return thread->lastActivate; +} + +template <class Impl> +Tick +AlphaFullCPU<Impl>::AlphaXC::readLastSuspend() +{ + return thread->lastSuspend; +} + +template <class Impl> +void +AlphaFullCPU<Impl>::AlphaXC::profileClear() +{} + +template <class Impl> +void +AlphaFullCPU<Impl>::AlphaXC::profileSample() +{} +#endif + +template <class Impl> +TheISA::MachInst +AlphaFullCPU<Impl>::AlphaXC:: getInst() +{ + return thread->inst; +} + +template <class Impl> +void +AlphaFullCPU<Impl>::AlphaXC::copyArchRegs(ExecContext *xc) +{ + // This function will mess things up unless the ROB is empty and + // there are no instructions in the pipeline. + unsigned tid = thread->tid; + PhysRegIndex renamed_reg; + + // First loop through the integer registers. + for (int i = 0; i < AlphaISA::NumIntRegs; ++i) { + renamed_reg = cpu->renameMap[tid].lookup(i); + + DPRINTF(FullCPU, "FullCPU: Copying over register %i, had data %lli, " + "now has data %lli.\n", + renamed_reg, cpu->readIntReg(renamed_reg), + xc->readIntReg(i)); + + cpu->setIntReg(renamed_reg, xc->readIntReg(i)); + } + + // Then loop through the floating point registers. + for (int i = 0; i < AlphaISA::NumFloatRegs; ++i) + { + renamed_reg = this->renameMap.lookup(i + AlphaISA::FP_Base_DepTag); + this->cpuXC->setFloatRegBits(i, + this->regFile.readFloatRegBits(renamed_reg)); + } + + // Copy the misc regs. + cpu->regFile.miscRegs[tid].copyMiscRegs(xc); + + // Then finally set the PC and the next PC. + cpu->setPC(xc->readPC(), tid); + cpu->setNextPC(xc->readNextPC(), tid); +#if !FULL_SYSTEM + this->thread->funcExeInst = xc->readFuncExeInst(); +#endif +} + +template <class Impl> +void +AlphaFullCPU<Impl>::AlphaXC::clearArchRegs() +{} + +template <class Impl> +uint64_t +AlphaFullCPU<Impl>::AlphaXC::readIntReg(int reg_idx) +{ + DPRINTF(Fault, "Reading int register through the XC!\n"); + return cpu->readArchIntReg(reg_idx, thread->tid); +} + +template <class Impl> +float +AlphaFullCPU<Impl>::AlphaXC::readFloatRegSingle(int reg_idx) +{ + DPRINTF(Fault, "Reading float register through the XC!\n"); + return cpu->readArchFloatRegSingle(reg_idx, thread->tid); +} + +template <class Impl> +double +AlphaFullCPU<Impl>::AlphaXC::readFloatRegDouble(int reg_idx) +{ + DPRINTF(Fault, "Reading float register through the XC!\n"); + return cpu->readArchFloatRegDouble(reg_idx, thread->tid); +} + +template <class Impl> +uint64_t +AlphaFullCPU<Impl>::AlphaXC::readFloatRegInt(int reg_idx) +{ + DPRINTF(Fault, "Reading floatint register through the XC!\n"); + return cpu->readArchFloatRegInt(reg_idx, thread->tid); +} + +template <class Impl> +void +AlphaFullCPU<Impl>::AlphaXC::setIntReg(int reg_idx, uint64_t val) +{ + DPRINTF(Fault, "Setting int register through the XC!\n"); + cpu->setArchIntReg(reg_idx, val, thread->tid); + + if (!thread->trapPending && !thread->inSyscall) { + cpu->squashFromXC(thread->tid); + } +} + +template <class Impl> +void +AlphaFullCPU<Impl>::AlphaXC::setFloatRegSingle(int reg_idx, float val) +{ + DPRINTF(Fault, "Setting float register through the XC!\n"); + cpu->setArchFloatRegSingle(reg_idx, val, thread->tid); + + if (!thread->trapPending && !thread->inSyscall) { + cpu->squashFromXC(thread->tid); + } +} + +template <class Impl> +void +AlphaFullCPU<Impl>::AlphaXC::setFloatRegDouble(int reg_idx, double val) +{ + DPRINTF(Fault, "Setting float register through the XC!\n"); + cpu->setArchFloatRegDouble(reg_idx, val, thread->tid); + + if (!thread->trapPending && !thread->inSyscall) { + cpu->squashFromXC(thread->tid); + } +} + +template <class Impl> +void +AlphaFullCPU<Impl>::AlphaXC::setFloatRegInt(int reg_idx, uint64_t val) +{ + DPRINTF(Fault, "Setting floatint register through the XC!\n"); + cpu->setArchFloatRegInt(reg_idx, val, thread->tid); + + if (!thread->trapPending && !thread->inSyscall) { + cpu->squashFromXC(thread->tid); + } +} + +template <class Impl> +void +AlphaFullCPU<Impl>::AlphaXC::setPC(uint64_t val) +{ + cpu->setPC(val, thread->tid); + + if (!thread->trapPending && !thread->inSyscall) { + cpu->squashFromXC(thread->tid); + } +} + +template <class Impl> +void +AlphaFullCPU<Impl>::AlphaXC::setNextPC(uint64_t val) +{ + cpu->setNextPC(val, thread->tid); + + if (!thread->trapPending && !thread->inSyscall) { + cpu->squashFromXC(thread->tid); + } +} + +template <class Impl> +Fault +AlphaFullCPU<Impl>::AlphaXC::setMiscReg(int misc_reg, const MiscReg &val) +{ + DPRINTF(Fault, "Setting misc register through the XC!\n"); + + Fault ret_fault = cpu->setMiscReg(misc_reg, val, thread->tid); + + if (!thread->trapPending && !thread->inSyscall) { + cpu->squashFromXC(thread->tid); + } + + return ret_fault; +} + +template <class Impl> +Fault +AlphaFullCPU<Impl>::AlphaXC::setMiscRegWithEffect(int misc_reg, const MiscReg &val) +{ + DPRINTF(Fault, "Setting misc register through the XC!\n"); + + Fault ret_fault = cpu->setMiscRegWithEffect(misc_reg, val, thread->tid); + + if (!thread->trapPending && !thread->inSyscall) { + cpu->squashFromXC(thread->tid); + } + + return ret_fault; +} + +#if !FULL_SYSTEM + +template <class Impl> +TheISA::IntReg +AlphaFullCPU<Impl>::AlphaXC::getSyscallArg(int i) +{ + return cpu->getSyscallArg(i, thread->tid); +} + +template <class Impl> +void +AlphaFullCPU<Impl>::AlphaXC::setSyscallArg(int i, IntReg val) +{ + cpu->setSyscallArg(i, val, thread->tid); +} + +template <class Impl> +void +AlphaFullCPU<Impl>::AlphaXC::setSyscallReturn(SyscallReturn return_value) +{ + cpu->setSyscallReturn(return_value, thread->tid); +} + +#endif // FULL_SYSTEM + +template <class Impl> +MiscReg +AlphaFullCPU<Impl>::readMiscReg(int misc_reg, unsigned tid) +{ + return this->regFile.readMiscReg(misc_reg, tid); +} + +template <class Impl> +MiscReg +AlphaFullCPU<Impl>::readMiscRegWithEffect(int misc_reg, Fault &fault, + unsigned tid) +{ + return this->regFile.readMiscRegWithEffect(misc_reg, fault, tid); +} + +template <class Impl> +Fault +AlphaFullCPU<Impl>::setMiscReg(int misc_reg, const MiscReg &val, unsigned tid) +{ + return this->regFile.setMiscReg(misc_reg, val, tid); +} + +template <class Impl> +Fault +AlphaFullCPU<Impl>::setMiscRegWithEffect(int misc_reg, const MiscReg &val, + unsigned tid) +{ + return this->regFile.setMiscRegWithEffect(misc_reg, val, tid); +} + +template <class Impl> +void +AlphaFullCPU<Impl>::squashFromXC(unsigned tid) +{ + this->thread[tid]->inSyscall = true; + this->commit.generateXCEvent(tid); +} + +#if FULL_SYSTEM + +template <class Impl> +void +AlphaFullCPU<Impl>::post_interrupt(int int_num, int index) +{ + BaseCPU::post_interrupt(int_num, index); + + if (this->thread[0]->status() == ExecContext::Suspended) { + DPRINTF(IPI,"Suspended Processor awoke\n"); +// xcProxies[0]->activate(); + this->execContexts[0]->activate(); + } +} + +template <class Impl> +int +AlphaFullCPU<Impl>::readIntrFlag() +{ + return this->regFile.readIntrFlag(); +} + +template <class Impl> +void +AlphaFullCPU<Impl>::setIntrFlag(int val) +{ + this->regFile.setIntrFlag(val); +} + +template <class Impl> +Fault +AlphaFullCPU<Impl>::hwrei(unsigned tid) +{ + // Need to clear the lock flag upon returning from an interrupt. + this->lockFlag = false; + + this->thread[tid]->kernelStats->hwrei(); + + this->checkInterrupts = true; + + // FIXME: XXX check for interrupts? XXX + return NoFault; +} + +template <class Impl> +bool +AlphaFullCPU<Impl>::simPalCheck(int palFunc, unsigned tid) +{ + if (this->thread[tid]->kernelStats) + this->thread[tid]->kernelStats->callpal(palFunc, + this->execContexts[tid]); + + switch (palFunc) { + case PAL::halt: + halt(); + if (--System::numSystemsRunning == 0) + new SimExitEvent("all cpus halted"); + break; + + case PAL::bpt: + case PAL::bugchk: + if (this->system->breakpoint()) + return false; + break; + } + + return true; +} + +template <class Impl> +void +AlphaFullCPU<Impl>::trap(Fault fault, unsigned tid) +{ + fault->invoke(this->execContexts[tid]); +} + +template <class Impl> +void +AlphaFullCPU<Impl>::processInterrupts() +{ + // Check for interrupts here. For now can copy the code that + // exists within isa_fullsys_traits.hh. Also assume that thread 0 + // is the one that handles the interrupts. + // @todo: Possibly consolidate the interrupt checking code. + // @todo: Allow other threads to handle interrupts. + + // Check if there are any outstanding interrupts + //Handle the interrupts + int ipl = 0; + int summary = 0; + + this->checkInterrupts = false; + + if (this->readMiscReg(IPR_ASTRR, 0)) + panic("asynchronous traps not implemented\n"); + + if (this->readMiscReg(IPR_SIRR, 0)) { + for (int i = INTLEVEL_SOFTWARE_MIN; + i < INTLEVEL_SOFTWARE_MAX; i++) { + if (this->readMiscReg(IPR_SIRR, 0) & (ULL(1) << i)) { + // See table 4-19 of the 21164 hardware reference + ipl = (i - INTLEVEL_SOFTWARE_MIN) + 1; + summary |= (ULL(1) << i); + } + } + } + + uint64_t interrupts = this->intr_status(); + + if (interrupts) { + for (int i = INTLEVEL_EXTERNAL_MIN; + i < INTLEVEL_EXTERNAL_MAX; i++) { + if (interrupts & (ULL(1) << i)) { + // See table 4-19 of the 21164 hardware reference + ipl = i; + summary |= (ULL(1) << i); + } + } + } + + if (ipl && ipl > this->readMiscReg(IPR_IPLR, 0)) { + this->setMiscReg(IPR_ISR, summary, 0); + this->setMiscReg(IPR_INTID, ipl, 0); + if (this->checker) { + this->checker->cpuXCBase()->setMiscReg(IPR_ISR, summary); + this->checker->cpuXCBase()->setMiscReg(IPR_INTID, ipl); + } + this->trap(Fault(new InterruptFault), 0); + DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n", + this->readMiscReg(IPR_IPLR, 0), ipl, summary); + } +} + +#endif // FULL_SYSTEM + +#if !FULL_SYSTEM + +template <class Impl> +void +AlphaFullCPU<Impl>::syscall(int tid) +{ + DPRINTF(FullCPU, "AlphaFullCPU: [tid:%i] Executing syscall().\n\n", tid); + + DPRINTF(Activity,"Activity: syscall() called.\n"); + + // Temporarily increase this by one to account for the syscall + // instruction. + ++(this->thread[tid]->funcExeInst); + + // Execute the actual syscall. + this->thread[tid]->syscall(); + + // Decrease funcExeInst by one as the normal commit will handle + // incrementing it. + --(this->thread[tid]->funcExeInst); +} + +template <class Impl> +TheISA::IntReg +AlphaFullCPU<Impl>::getSyscallArg(int i, int tid) +{ + return this->readArchIntReg(AlphaISA::ArgumentReg0 + i, tid); +} + +template <class Impl> +void +AlphaFullCPU<Impl>::setSyscallArg(int i, IntReg val, int tid) +{ + this->setArchIntReg(AlphaISA::ArgumentReg0 + i, val, tid); +} + +template <class Impl> +void +AlphaFullCPU<Impl>::setSyscallReturn(SyscallReturn return_value, int tid) +{ + // check for error condition. Alpha syscall convention is to + // indicate success/failure in reg a3 (r19) and put the + // return value itself in the standard return value reg (v0). + if (return_value.successful()) { + // no error + this->setArchIntReg(SyscallSuccessReg, 0, tid); + this->setArchIntReg(ReturnValueReg, return_value.value(), tid); + } else { + // got an error, return details + this->setArchIntReg(SyscallSuccessReg, (IntReg) -1, tid); + this->setArchIntReg(ReturnValueReg, -return_value.value(), tid); + } +} +#endif diff --git a/cpu/o3/alpha_dyn_inst.cc b/src/cpu/o3/alpha_dyn_inst.cc index 72ac77d95..72ac77d95 100644 --- a/cpu/o3/alpha_dyn_inst.cc +++ b/src/cpu/o3/alpha_dyn_inst.cc diff --git a/src/cpu/o3/alpha_dyn_inst.hh b/src/cpu/o3/alpha_dyn_inst.hh new file mode 100644 index 000000000..b03c8c337 --- /dev/null +++ b/src/cpu/o3/alpha_dyn_inst.hh @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2004-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __CPU_O3_ALPHA_DYN_INST_HH__ +#define __CPU_O3_ALPHA_DYN_INST_HH__ + +#include "cpu/base_dyn_inst.hh" +#include "cpu/inst_seq.hh" +#include "cpu/o3/alpha_cpu.hh" +#include "cpu/o3/alpha_impl.hh" + +/** + * Mostly implementation & ISA specific AlphaDynInst. As with most + * other classes in the new CPU model, it is templated on the Impl to + * allow for passing in of all types, such as the CPU type and the ISA + * type. The AlphaDynInst serves as the primary interface to the CPU + * for instructions that are executing. + */ +template <class Impl> +class AlphaDynInst : public BaseDynInst<Impl> +{ + public: + /** Typedef for the CPU. */ + typedef typename Impl::FullCPU FullCPU; + + /** Binary machine instruction type. */ + typedef TheISA::MachInst MachInst; + /** Extended machine instruction type. */ + typedef TheISA::ExtMachInst ExtMachInst; + /** Logical register index type. */ + typedef TheISA::RegIndex RegIndex; + /** Integer register index type. */ + typedef TheISA::IntReg IntReg; + /** Misc register index type. */ + typedef TheISA::MiscReg MiscReg; + + enum { + MaxInstSrcRegs = TheISA::MaxInstSrcRegs, //< Max source regs + MaxInstDestRegs = TheISA::MaxInstDestRegs, //< Max dest regs + }; + + public: + /** BaseDynInst constructor given a binary instruction. */ + AlphaDynInst(ExtMachInst inst, Addr PC, Addr Pred_PC, InstSeqNum seq_num, + FullCPU *cpu); + + /** BaseDynInst constructor given a static inst pointer. */ + AlphaDynInst(StaticInstPtr &_staticInst); + + /** Executes the instruction.*/ + Fault execute(); + + /** Initiates the access. Only valid for memory operations. */ + Fault initiateAcc(); + + /** Completes the access. Only valid for memory operations. */ + Fault completeAcc(); + + private: + /** Initializes variables. */ + void initVars(); + + public: + MiscReg readMiscReg(int misc_reg) + { + return this->cpu->readMiscReg(misc_reg, this->threadNumber); + } + + MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault) + { + return this->cpu->readMiscRegWithEffect(misc_reg, fault, + this->threadNumber); + } + + Fault setMiscReg(int misc_reg, const MiscReg &val) + { + this->instResult.integer = val; + return this->cpu->setMiscReg(misc_reg, val, this->threadNumber); + } + + Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val) + { + return this->cpu->setMiscRegWithEffect(misc_reg, val, + this->threadNumber); + } + +#if FULL_SYSTEM + /** Calls hardware return from error interrupt. */ + Fault hwrei(); + /** Reads interrupt flag. */ + int readIntrFlag(); + /** Sets interrupt flag. */ + void setIntrFlag(int val); + /** Checks if system is in PAL mode. */ + bool inPalMode(); + /** Traps to handle specified fault. */ + void trap(Fault fault); + bool simPalCheck(int palFunc); +#else + /** Calls a syscall. */ + void syscall(); +#endif + + private: + /** Physical register index of the destination registers of this + * instruction. + */ + PhysRegIndex _destRegIdx[MaxInstDestRegs]; + + /** Physical register index of the source registers of this + * instruction. + */ + PhysRegIndex _srcRegIdx[MaxInstSrcRegs]; + + /** Physical register index of the previous producers of the + * architected destinations. + */ + PhysRegIndex _prevDestRegIdx[MaxInstDestRegs]; + + public: + + // The register accessor methods provide the index of the + // instruction's operand (e.g., 0 or 1), not the architectural + // register index, to simplify the implementation of register + // renaming. We find the architectural register index by indexing + // into the instruction's own operand index table. Note that a + // raw pointer to the StaticInst is provided instead of a + // ref-counted StaticInstPtr to redice overhead. This is fine as + // long as these methods don't copy the pointer into any long-term + // storage (which is pretty hard to imagine they would have reason + // to do). + + uint64_t readIntReg(const StaticInst *si, int idx) + { + return this->cpu->readIntReg(_srcRegIdx[idx]); + } + + FloatReg readFloatReg(const StaticInst *si, int idx, int width) + { + return this->cpu->readFloatReg(_srcRegIdx[idx], width); + } + + FloatReg readFloatReg(const StaticInst *si, int idx) + { + return this->cpu->readFloatReg(_srcRegIdx[idx]); + } + + FloatRegBits readFloatRegBits(const StaticInst *si, int idx, int width) + { + return this->cpu->readFloatRegBits(_srcRegIdx[idx], width); + } + + FloatRegBits readFloatRegBits(const StaticInst *si, int idx) + { + return this->cpu->readFloatRegBits(_srcRegIdx[idx]); + } + + /** @todo: Make results into arrays so they can handle multiple dest + * registers. + */ + void setIntReg(const StaticInst *si, int idx, uint64_t val) + { + this->cpu->setIntReg(_destRegIdx[idx], val); + BaseDynInst<Impl>::setIntReg(si, idx, val); + } + + void setFloatReg(const StaticInst *si, int idx, FloatReg val, int width) + { + this->cpu->setFloatReg(_destRegIdx[idx], val, width); + BaseDynInst<Impl>::setFloatRegSingle(si, idx, val); + } + + void setFloatReg(const StaticInst *si, int idx, FloatReg val) + { + this->cpu->setFloatReg(_destRegIdx[idx], val); + BaseDynInst<Impl>::setFloatRegDouble(si, idx, val); + } + + void setFloatRegBits(const StaticInst *si, int idx, + FloatRegBits val, int width) + { + this->cpu->setFloatRegBits(_destRegIdx[idx], val, width); + this->instResult.integer = val; + } + + void setFloatRegBits(const StaticInst *si, int idx, FloatRegBits val) + { + this->cpu->setFloatRegBits(_destRegIdx[idx], val); + BaseDynInst<Impl>::setFloatRegInt(si, idx, val); + } + + /** Returns the physical register index of the i'th destination + * register. + */ + PhysRegIndex renamedDestRegIdx(int idx) const + { + return _destRegIdx[idx]; + } + + /** Returns the physical register index of the i'th source register. */ + PhysRegIndex renamedSrcRegIdx(int idx) const + { + return _srcRegIdx[idx]; + } + + /** Returns the physical register index of the previous physical register + * that remapped to the same logical register index. + */ + PhysRegIndex prevDestRegIdx(int idx) const + { + return _prevDestRegIdx[idx]; + } + + /** Renames a destination register to a physical register. Also records + * the previous physical register that the logical register mapped to. + */ + void renameDestReg(int idx, + PhysRegIndex renamed_dest, + PhysRegIndex previous_rename) + { + _destRegIdx[idx] = renamed_dest; + _prevDestRegIdx[idx] = previous_rename; + } + + /** Renames a source logical register to the physical register which + * has/will produce that logical register's result. + * @todo: add in whether or not the source register is ready. + */ + void renameSrcReg(int idx, PhysRegIndex renamed_src) + { + _srcRegIdx[idx] = renamed_src; + } + + public: + /** Calculates EA part of a memory instruction. Currently unused, + * though it may be useful in the future if we want to split + * memory operations into EA calculation and memory access parts. + */ + Fault calcEA() + { + return this->staticInst->eaCompInst()->execute(this, this->traceData); + } + + /** Does the memory access part of a memory instruction. Currently unused, + * though it may be useful in the future if we want to split + * memory operations into EA calculation and memory access parts. + */ + Fault memAccess() + { + return this->staticInst->memAccInst()->execute(this, this->traceData); + } +}; + +#endif // __CPU_O3_ALPHA_DYN_INST_HH__ + diff --git a/cpu/o3/alpha_dyn_inst_impl.hh b/src/cpu/o3/alpha_dyn_inst_impl.hh index 541d5ab82..541d5ab82 100644 --- a/cpu/o3/alpha_dyn_inst_impl.hh +++ b/src/cpu/o3/alpha_dyn_inst_impl.hh diff --git a/cpu/o3/alpha_impl.hh b/src/cpu/o3/alpha_impl.hh index f404bd3ec..f404bd3ec 100644 --- a/cpu/o3/alpha_impl.hh +++ b/src/cpu/o3/alpha_impl.hh diff --git a/cpu/o3/alpha_params.hh b/src/cpu/o3/alpha_params.hh index e3acf2c05..e3acf2c05 100644 --- a/cpu/o3/alpha_params.hh +++ b/src/cpu/o3/alpha_params.hh diff --git a/cpu/o3/bpred_unit.cc b/src/cpu/o3/bpred_unit.cc index 92344111f..92344111f 100644 --- a/cpu/o3/bpred_unit.cc +++ b/src/cpu/o3/bpred_unit.cc diff --git a/cpu/o3/bpred_unit.hh b/src/cpu/o3/bpred_unit.hh index b7814b2e9..b7814b2e9 100644 --- a/cpu/o3/bpred_unit.hh +++ b/src/cpu/o3/bpred_unit.hh diff --git a/cpu/o3/bpred_unit_impl.hh b/src/cpu/o3/bpred_unit_impl.hh index c37df606b..c37df606b 100644 --- a/cpu/o3/bpred_unit_impl.hh +++ b/src/cpu/o3/bpred_unit_impl.hh diff --git a/cpu/o3/btb.cc b/src/cpu/o3/btb.cc index e5f69043a..e5f69043a 100644 --- a/cpu/o3/btb.cc +++ b/src/cpu/o3/btb.cc diff --git a/cpu/o3/btb.hh b/src/cpu/o3/btb.hh index b9ff42573..b9ff42573 100644 --- a/cpu/o3/btb.hh +++ b/src/cpu/o3/btb.hh diff --git a/cpu/o3/comm.hh b/src/cpu/o3/comm.hh index c36c58d3d..c36c58d3d 100644 --- a/cpu/o3/comm.hh +++ b/src/cpu/o3/comm.hh diff --git a/cpu/o3/commit.cc b/src/cpu/o3/commit.cc index fe5e9c1de..fe5e9c1de 100644 --- a/cpu/o3/commit.cc +++ b/src/cpu/o3/commit.cc diff --git a/cpu/o3/commit.hh b/src/cpu/o3/commit.hh index 66abf8dc6..66abf8dc6 100644 --- a/cpu/o3/commit.hh +++ b/src/cpu/o3/commit.hh diff --git a/cpu/o3/commit_impl.hh b/src/cpu/o3/commit_impl.hh index 346a8bc1c..346a8bc1c 100644 --- a/cpu/o3/commit_impl.hh +++ b/src/cpu/o3/commit_impl.hh diff --git a/src/cpu/o3/cpu.cc b/src/cpu/o3/cpu.cc new file mode 100644 index 000000000..ed02a845b --- /dev/null +++ b/src/cpu/o3/cpu.cc @@ -0,0 +1,1196 @@ +/* + * Copyright (c) 2004-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config/full_system.hh" + +#if FULL_SYSTEM +#include "sim/system.hh" +#else +#include "sim/process.hh" +#endif + +#include "cpu/activity.hh" +#include "cpu/checker/cpu.hh" +#include "cpu/cpu_exec_context.hh" +#include "cpu/exec_context.hh" +#include "cpu/o3/alpha_dyn_inst.hh" +#include "cpu/o3/alpha_impl.hh" +#include "cpu/o3/cpu.hh" + +#include "sim/root.hh" +#include "sim/stat_control.hh" + +using namespace std; + +BaseFullCPU::BaseFullCPU(Params *params) + : BaseCPU(params), cpu_id(0) +{ +} + +void +BaseFullCPU::regStats() +{ + BaseCPU::regStats(); +} + +template <class Impl> +FullO3CPU<Impl>::TickEvent::TickEvent(FullO3CPU<Impl> *c) + : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c) +{ +} + +template <class Impl> +void +FullO3CPU<Impl>::TickEvent::process() +{ + cpu->tick(); +} + +template <class Impl> +const char * +FullO3CPU<Impl>::TickEvent::description() +{ + return "FullO3CPU tick event"; +} + +template <class Impl> +FullO3CPU<Impl>::FullO3CPU(Params *params) + : BaseFullCPU(params), + tickEvent(this), + removeInstsThisCycle(false), + fetch(params), + decode(params), + rename(params), + iew(params), + commit(params), + + regFile(params->numPhysIntRegs, params->numPhysFloatRegs), + + freeList(params->numberOfThreads,//number of activeThreads + TheISA::NumIntRegs, params->numPhysIntRegs, + TheISA::NumFloatRegs, params->numPhysFloatRegs), + + rob(params->numROBEntries, params->squashWidth, + params->smtROBPolicy, params->smtROBThreshold, + params->numberOfThreads), + + scoreboard(params->numberOfThreads,//number of activeThreads + TheISA::NumIntRegs, params->numPhysIntRegs, + TheISA::NumFloatRegs, params->numPhysFloatRegs, + TheISA::NumMiscRegs * number_of_threads, + TheISA::ZeroReg), + + // For now just have these time buffers be pretty big. + // @todo: Make these time buffer sizes parameters or derived + // from latencies + timeBuffer(5, 5), + fetchQueue(5, 5), + decodeQueue(5, 5), + renameQueue(5, 5), + iewQueue(5, 5), + activityRec(NumStages, 10, params->activity), + + globalSeqNum(1), + +#if FULL_SYSTEM + system(params->system), + memCtrl(system->memctrl), + physmem(system->physmem), + mem(params->mem), +#else +// pTable(params->pTable), + mem(params->workload[0]->getMemory()), +#endif // FULL_SYSTEM + switchCount(0), + icacheInterface(params->icacheInterface), + dcacheInterface(params->dcacheInterface), + deferRegistration(params->deferRegistration), + numThreads(number_of_threads) +{ + _status = Idle; + + if (params->checker) { + BaseCPU *temp_checker = params->checker; + checker = dynamic_cast<Checker<DynInstPtr> *>(temp_checker); + checker->setMemory(mem); +#if FULL_SYSTEM + checker->setSystem(params->system); +#endif + } else { + checker = NULL; + } + +#if !FULL_SYSTEM + thread.resize(number_of_threads); + tids.resize(number_of_threads); +#endif + + // The stages also need their CPU pointer setup. However this + // must be done at the upper level CPU because they have pointers + // to the upper level CPU, and not this FullO3CPU. + + // Set up Pointers to the activeThreads list for each stage + fetch.setActiveThreads(&activeThreads); + decode.setActiveThreads(&activeThreads); + rename.setActiveThreads(&activeThreads); + iew.setActiveThreads(&activeThreads); + commit.setActiveThreads(&activeThreads); + + // Give each of the stages the time buffer they will use. + fetch.setTimeBuffer(&timeBuffer); + decode.setTimeBuffer(&timeBuffer); + rename.setTimeBuffer(&timeBuffer); + iew.setTimeBuffer(&timeBuffer); + commit.setTimeBuffer(&timeBuffer); + + // Also setup each of the stages' queues. + fetch.setFetchQueue(&fetchQueue); + decode.setFetchQueue(&fetchQueue); + commit.setFetchQueue(&fetchQueue); + decode.setDecodeQueue(&decodeQueue); + rename.setDecodeQueue(&decodeQueue); + rename.setRenameQueue(&renameQueue); + iew.setRenameQueue(&renameQueue); + iew.setIEWQueue(&iewQueue); + commit.setIEWQueue(&iewQueue); + commit.setRenameQueue(&renameQueue); + + commit.setFetchStage(&fetch); + commit.setIEWStage(&iew); + rename.setIEWStage(&iew); + rename.setCommitStage(&commit); + +#if !FULL_SYSTEM + int active_threads = params->workload.size(); +#else + int active_threads = 1; +#endif + + //Make Sure That this a Valid Architeture + assert(params->numPhysIntRegs >= numThreads * TheISA::NumIntRegs); + assert(params->numPhysFloatRegs >= numThreads * TheISA::NumFloatRegs); + + rename.setScoreboard(&scoreboard); + iew.setScoreboard(&scoreboard); + + // Setup the rename map for whichever stages need it. + PhysRegIndex lreg_idx = 0; + PhysRegIndex freg_idx = params->numPhysIntRegs; //Index to 1 after int regs + + for (int tid=0; tid < numThreads; tid++) { + bool bindRegs = (tid <= active_threads - 1); + + commitRenameMap[tid].init(TheISA::NumIntRegs, + params->numPhysIntRegs, + lreg_idx, //Index for Logical. Regs + + TheISA::NumFloatRegs, + params->numPhysFloatRegs, + freg_idx, //Index for Float Regs + + TheISA::NumMiscRegs, + + TheISA::ZeroReg, + TheISA::ZeroReg, + + tid, + false); + + renameMap[tid].init(TheISA::NumIntRegs, + params->numPhysIntRegs, + lreg_idx, //Index for Logical. Regs + + TheISA::NumFloatRegs, + params->numPhysFloatRegs, + freg_idx, //Index for Float Regs + + TheISA::NumMiscRegs, + + TheISA::ZeroReg, + TheISA::ZeroReg, + + tid, + bindRegs); + } + + rename.setRenameMap(renameMap); + commit.setRenameMap(commitRenameMap); + + // Give renameMap & rename stage access to the freeList; + for (int i=0; i < numThreads; i++) { + renameMap[i].setFreeList(&freeList); + } + rename.setFreeList(&freeList); + + // Setup the page table for whichever stages need it. +#if !FULL_SYSTEM +// fetch.setPageTable(pTable); +// iew.setPageTable(pTable); +#endif + + // Setup the ROB for whichever stages need it. + commit.setROB(&rob); + + lastRunningCycle = curTick; + + contextSwitch = false; +} + +template <class Impl> +FullO3CPU<Impl>::~FullO3CPU() +{ +} + +template <class Impl> +void +FullO3CPU<Impl>::fullCPURegStats() +{ + BaseFullCPU::regStats(); + + // Register any of the FullCPU's stats here. + timesIdled + .name(name() + ".timesIdled") + .desc("Number of times that the entire CPU went into an idle state and" + " unscheduled itself") + .prereq(timesIdled); + + idleCycles + .name(name() + ".idleCycles") + .desc("Total number of cycles that the CPU has spent unscheduled due " + "to idling") + .prereq(idleCycles); + + // Number of Instructions simulated + // -------------------------------- + // Should probably be in Base CPU but need templated + // MaxThreads so put in here instead + committedInsts + .init(numThreads) + .name(name() + ".committedInsts") + .desc("Number of Instructions Simulated"); + + totalCommittedInsts + .name(name() + ".committedInsts_total") + .desc("Number of Instructions Simulated"); + + cpi + .name(name() + ".cpi") + .desc("CPI: Cycles Per Instruction") + .precision(6); + cpi = simTicks / committedInsts; + + totalCpi + .name(name() + ".cpi_total") + .desc("CPI: Total CPI of All Threads") + .precision(6); + totalCpi = simTicks / totalCommittedInsts; + + ipc + .name(name() + ".ipc") + .desc("IPC: Instructions Per Cycle") + .precision(6); + ipc = committedInsts / simTicks; + + totalIpc + .name(name() + ".ipc_total") + .desc("IPC: Total IPC of All Threads") + .precision(6); + totalIpc = totalCommittedInsts / simTicks; + +} + +template <class Impl> +void +FullO3CPU<Impl>::tick() +{ + DPRINTF(FullCPU, "\n\nFullCPU: Ticking main, FullO3CPU.\n"); + + ++numCycles; + +// activity = false; + + //Tick each of the stages + fetch.tick(); + + decode.tick(); + + rename.tick(); + + iew.tick(); + + commit.tick(); + +#if !FULL_SYSTEM + doContextSwitch(); +#endif + + // Now advance the time buffers + timeBuffer.advance(); + + fetchQueue.advance(); + decodeQueue.advance(); + renameQueue.advance(); + iewQueue.advance(); + + activityRec.advance(); + + if (removeInstsThisCycle) { + cleanUpRemovedInsts(); + } + + if (!tickEvent.scheduled()) { + if (_status == SwitchedOut) { + // increment stat + lastRunningCycle = curTick; + } else if (!activityRec.active()) { + lastRunningCycle = curTick; + timesIdled++; + } else { + tickEvent.schedule(curTick + cycles(1)); + } + } + +#if !FULL_SYSTEM + updateThreadPriority(); +#endif + +} + +template <class Impl> +void +FullO3CPU<Impl>::init() +{ + if (!deferRegistration) { + registerExecContexts(); + } + + // Set inSyscall so that the CPU doesn't squash when initially + // setting up registers. + for (int i = 0; i < number_of_threads; ++i) + thread[i]->inSyscall = true; + + for (int tid=0; tid < number_of_threads; tid++) { +#if FULL_SYSTEM + ExecContext *src_xc = execContexts[tid]; +#else + ExecContext *src_xc = thread[tid]->getXCProxy(); +#endif + // Threads start in the Suspended State + if (src_xc->status() != ExecContext::Suspended) { + continue; + } + +#if FULL_SYSTEM + TheISA::initCPU(src_xc, src_xc->readCpuId()); +#endif + } + + // Clear inSyscall. + for (int i = 0; i < number_of_threads; ++i) + thread[i]->inSyscall = false; + + // Initialize stages. + fetch.initStage(); + iew.initStage(); + rename.initStage(); + commit.initStage(); + + commit.setThreads(thread); +} + +template <class Impl> +void +FullO3CPU<Impl>::insertThread(unsigned tid) +{ + DPRINTF(FullCPU,"[tid:%i] Initializing thread data"); + // Will change now that the PC and thread state is internal to the CPU + // and not in the CPUExecContext. +#if 0 +#if FULL_SYSTEM + ExecContext *src_xc = system->execContexts[tid]; +#else + CPUExecContext *src_xc = thread[tid]; +#endif + + //Bind Int Regs to Rename Map + for (int ireg = 0; ireg < TheISA::NumIntRegs; ireg++) { + PhysRegIndex phys_reg = freeList.getIntReg(); + + renameMap[tid].setEntry(ireg,phys_reg); + scoreboard.setReg(phys_reg); + } + + //Bind Float Regs to Rename Map + for (int freg = 0; freg < TheISA::NumFloatRegs; freg++) { + PhysRegIndex phys_reg = freeList.getFloatReg(); + + renameMap[tid].setEntry(freg,phys_reg); + scoreboard.setReg(phys_reg); + } + + //Copy Thread Data Into RegFile + this->copyFromXC(tid); + + //Set PC/NPC + regFile.pc[tid] = src_xc->readPC(); + regFile.npc[tid] = src_xc->readNextPC(); + + src_xc->setStatus(ExecContext::Active); + + activateContext(tid,1); + + //Reset ROB/IQ/LSQ Entries + commit.rob->resetEntries(); + iew.resetEntries(); +#endif +} + +template <class Impl> +void +FullO3CPU<Impl>::removeThread(unsigned tid) +{ + DPRINTF(FullCPU,"[tid:%i] Removing thread data"); +#if 0 + //Unbind Int Regs from Rename Map + for (int ireg = 0; ireg < TheISA::NumIntRegs; ireg++) { + PhysRegIndex phys_reg = renameMap[tid].lookup(ireg); + + scoreboard.unsetReg(phys_reg); + freeList.addReg(phys_reg); + } + + //Unbind Float Regs from Rename Map + for (int freg = 0; freg < TheISA::NumFloatRegs; freg++) { + PhysRegIndex phys_reg = renameMap[tid].lookup(freg); + + scoreboard.unsetReg(phys_reg); + freeList.addReg(phys_reg); + } + + //Copy Thread Data From RegFile + /* Fix Me: + * Do we really need to do this if we are removing a thread + * in the sense that it's finished (exiting)? If the thread is just + * being suspended we might... + */ +// this->copyToXC(tid); + + //Squash Throughout Pipeline + fetch.squash(0,tid); + decode.squash(tid); + rename.squash(tid); + + assert(iew.ldstQueue.getCount(tid) == 0); + + //Reset ROB/IQ/LSQ Entries + if (activeThreads.size() >= 1) { + commit.rob->resetEntries(); + iew.resetEntries(); + } +#endif +} + + +template <class Impl> +void +FullO3CPU<Impl>::activateWhenReady(int tid) +{ + DPRINTF(FullCPU,"[tid:%i]: Checking if resources are available for incoming" + "(e.g. PhysRegs/ROB/IQ/LSQ) \n", + tid); + + bool ready = true; + + if (freeList.numFreeIntRegs() >= TheISA::NumIntRegs) { + DPRINTF(FullCPU,"[tid:%i] Suspending thread due to not enough " + "Phys. Int. Regs.\n", + tid); + ready = false; + } else if (freeList.numFreeFloatRegs() >= TheISA::NumFloatRegs) { + DPRINTF(FullCPU,"[tid:%i] Suspending thread due to not enough " + "Phys. Float. Regs.\n", + tid); + ready = false; + } else if (commit.rob->numFreeEntries() >= + commit.rob->entryAmount(activeThreads.size() + 1)) { + DPRINTF(FullCPU,"[tid:%i] Suspending thread due to not enough " + "ROB entries.\n", + tid); + ready = false; + } else if (iew.instQueue.numFreeEntries() >= + iew.instQueue.entryAmount(activeThreads.size() + 1)) { + DPRINTF(FullCPU,"[tid:%i] Suspending thread due to not enough " + "IQ entries.\n", + tid); + ready = false; + } else if (iew.ldstQueue.numFreeEntries() >= + iew.ldstQueue.entryAmount(activeThreads.size() + 1)) { + DPRINTF(FullCPU,"[tid:%i] Suspending thread due to not enough " + "LSQ entries.\n", + tid); + ready = false; + } + + if (ready) { + insertThread(tid); + + contextSwitch = false; + + cpuWaitList.remove(tid); + } else { + suspendContext(tid); + + //blocks fetch + contextSwitch = true; + + //do waitlist + cpuWaitList.push_back(tid); + } +} + +template <class Impl> +void +FullO3CPU<Impl>::activateContext(int tid, int delay) +{ + // Needs to set each stage to running as well. + list<unsigned>::iterator isActive = find( + activeThreads.begin(), activeThreads.end(), tid); + + if (isActive == activeThreads.end()) { + //May Need to Re-code this if the delay variable is the + //delay needed for thread to activate + DPRINTF(FullCPU, "Adding Thread %i to active threads list\n", + tid); + + activeThreads.push_back(tid); + } + + assert(_status == Idle || _status == SwitchedOut); + + scheduleTickEvent(delay); + + // Be sure to signal that there's some activity so the CPU doesn't + // deschedule itself. + activityRec.activity(); + fetch.wakeFromQuiesce(); + + _status = Running; +} + +template <class Impl> +void +FullO3CPU<Impl>::suspendContext(int tid) +{ + DPRINTF(FullCPU,"[tid: %i]: Suspended ...\n", tid); + unscheduleTickEvent(); + _status = Idle; +/* + //Remove From Active List, if Active + list<unsigned>::iterator isActive = find( + activeThreads.begin(), activeThreads.end(), tid); + + if (isActive != activeThreads.end()) { + DPRINTF(FullCPU,"[tid:%i]: Removing from active threads list\n", + tid); + activeThreads.erase(isActive); + } +*/ +} + +template <class Impl> +void +FullO3CPU<Impl>::deallocateContext(int tid) +{ + DPRINTF(FullCPU,"[tid:%i]: Deallocating ...", tid); +/* + //Remove From Active List, if Active + list<unsigned>::iterator isActive = find( + activeThreads.begin(), activeThreads.end(), tid); + + if (isActive != activeThreads.end()) { + DPRINTF(FullCPU,"[tid:%i]: Removing from active threads list\n", + tid); + activeThreads.erase(isActive); + + removeThread(tid); + } +*/ +} + +template <class Impl> +void +FullO3CPU<Impl>::haltContext(int tid) +{ + DPRINTF(FullCPU,"[tid:%i]: Halted ...", tid); +/* + //Remove From Active List, if Active + list<unsigned>::iterator isActive = find( + activeThreads.begin(), activeThreads.end(), tid); + + if (isActive != activeThreads.end()) { + DPRINTF(FullCPU,"[tid:%i]: Removing from active threads list\n", + tid); + activeThreads.erase(isActive); + + removeThread(tid); + } +*/ +} + +template <class Impl> +void +FullO3CPU<Impl>::switchOut(Sampler *_sampler) +{ + sampler = _sampler; + switchCount = 0; + fetch.switchOut(); + decode.switchOut(); + rename.switchOut(); + iew.switchOut(); + commit.switchOut(); + + // Wake the CPU and record activity so everything can drain out if + // the CPU is currently idle. + wakeCPU(); + activityRec.activity(); +} + +template <class Impl> +void +FullO3CPU<Impl>::signalSwitched() +{ + if (++switchCount == NumStages) { + fetch.doSwitchOut(); + rename.doSwitchOut(); + commit.doSwitchOut(); + instList.clear(); + while (!removeList.empty()) { + removeList.pop(); + } + + if (checker) + checker->switchOut(sampler); + + if (tickEvent.scheduled()) + tickEvent.squash(); + sampler->signalSwitched(); + _status = SwitchedOut; + } + assert(switchCount <= 5); +} + +template <class Impl> +void +FullO3CPU<Impl>::takeOverFrom(BaseCPU *oldCPU) +{ + // Flush out any old data from the time buffers. + for (int i = 0; i < 10; ++i) { + timeBuffer.advance(); + fetchQueue.advance(); + decodeQueue.advance(); + renameQueue.advance(); + iewQueue.advance(); + } + + activityRec.reset(); + + BaseCPU::takeOverFrom(oldCPU); + + fetch.takeOverFrom(); + decode.takeOverFrom(); + rename.takeOverFrom(); + iew.takeOverFrom(); + commit.takeOverFrom(); + + assert(!tickEvent.scheduled()); + + // @todo: Figure out how to properly select the tid to put onto + // the active threads list. + int tid = 0; + + list<unsigned>::iterator isActive = find( + activeThreads.begin(), activeThreads.end(), tid); + + if (isActive == activeThreads.end()) { + //May Need to Re-code this if the delay variable is the delay + //needed for thread to activate + DPRINTF(FullCPU, "Adding Thread %i to active threads list\n", + tid); + + activeThreads.push_back(tid); + } + + // Set all statuses to active, schedule the CPU's tick event. + // @todo: Fix up statuses so this is handled properly + for (int i = 0; i < execContexts.size(); ++i) { + ExecContext *xc = execContexts[i]; + if (xc->status() == ExecContext::Active && _status != Running) { + _status = Running; + tickEvent.schedule(curTick); + } + } + if (!tickEvent.scheduled()) + tickEvent.schedule(curTick); +} + +template <class Impl> +uint64_t +FullO3CPU<Impl>::readIntReg(int reg_idx) +{ + return regFile.readIntReg(reg_idx); +} + +template <class Impl> +FloatReg +FullO3CPU<Impl>::readFloatReg(int reg_idx, int width) +{ + return regFile.readFloatReg(reg_idx, width); +} + +template <class Impl> +FloatReg +FullO3CPU<Impl>::readFloatReg(int reg_idx) +{ + return regFile.readFloatReg(reg_idx); +} + +template <class Impl> +FloatRegBits +FullO3CPU<Impl>::readFloatRegBits(int reg_idx, int width) + return regFile.readFloatRegBits(reg_idx, width); +} + +template <class Impl> +FloatRegBits +FullO3CPU<Impl>::readFloatRegBits(int reg_idx) +{ + return regFile.readFloatRegBits(reg_idx); +} + +template <class Impl> +void +FullO3CPU<Impl>::setIntReg(int reg_idx, uint64_t val) +{ + regFile.setIntReg(reg_idx, val); +} + +template <class Impl> +void +FullO3CPU<Impl>::setFloatReg(int reg_idx, FloatReg val, int width) +{ + regFile.setFloatReg(reg_idx, val, width); +} + +template <class Impl> +void +FullO3CPU<Impl>::setFloatReg(int reg_idx, FloatReg val) +{ + regFile.setFloatReg(reg_idx, val); +} + +template <class Impl> +void +FullO3CPU<Impl>::setFloatRegBits(int reg_idx, FloatRegBits val, int width) +{ + regFile.setFloatRegBits(reg_idx, val, width); +} + +template <class Impl> +void +FullO3CPU<Impl>::setFloatRegBits(int reg_idx, FloatRegBits val) +{ + regFile.setFloatRegBits(reg_idx, val); +} + +template <class Impl> +uint64_t +FullO3CPU<Impl>::readArchIntReg(int reg_idx, unsigned tid) +{ + PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx); + + return regFile.readIntReg(phys_reg); +} + +template <class Impl> +float +FullO3CPU<Impl>::readArchFloatRegSingle(int reg_idx, unsigned tid) +{ + int idx = reg_idx + TheISA::FP_Base_DepTag; + PhysRegIndex phys_reg = commitRenameMap[tid].lookup(idx); + + return regFile.readFloatRegSingle(phys_reg); +} + +template <class Impl> +double +FullO3CPU<Impl>::readArchFloatRegDouble(int reg_idx, unsigned tid) +{ + int idx = reg_idx + TheISA::FP_Base_DepTag; + PhysRegIndex phys_reg = commitRenameMap[tid].lookup(idx); + + return regFile.readFloatRegDouble(phys_reg); +} + +template <class Impl> +uint64_t +FullO3CPU<Impl>::readArchFloatRegInt(int reg_idx, unsigned tid) +{ + int idx = reg_idx + TheISA::FP_Base_DepTag; + PhysRegIndex phys_reg = commitRenameMap[tid].lookup(idx); + + return regFile.readFloatRegInt(phys_reg); +} + +template <class Impl> +void +FullO3CPU<Impl>::setArchIntReg(int reg_idx, uint64_t val, unsigned tid) +{ + PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx); + + regFile.setIntReg(phys_reg, val); +} + +template <class Impl> +void +FullO3CPU<Impl>::setArchFloatRegSingle(int reg_idx, float val, unsigned tid) +{ + PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx); + + regFile.setFloatRegSingle(phys_reg, val); +} + +template <class Impl> +void +FullO3CPU<Impl>::setArchFloatRegDouble(int reg_idx, double val, unsigned tid) +{ + PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx); + + regFile.setFloatRegDouble(phys_reg, val); +} + +template <class Impl> +void +FullO3CPU<Impl>::setArchFloatRegInt(int reg_idx, uint64_t val, unsigned tid) +{ + PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx); + + regFile.setFloatRegInt(phys_reg, val); +} + +template <class Impl> +uint64_t +FullO3CPU<Impl>::readPC(unsigned tid) +{ + return commit.readPC(tid); +} + +template <class Impl> +void +FullO3CPU<Impl>::setPC(Addr new_PC,unsigned tid) +{ + commit.setPC(new_PC, tid); +} + +template <class Impl> +uint64_t +FullO3CPU<Impl>::readNextPC(unsigned tid) +{ + return commit.readNextPC(tid); +} + +template <class Impl> +void +FullO3CPU<Impl>::setNextPC(uint64_t val,unsigned tid) +{ + commit.setNextPC(val, tid); +} + +template <class Impl> +typename FullO3CPU<Impl>::ListIt +FullO3CPU<Impl>::addInst(DynInstPtr &inst) +{ + instList.push_back(inst); + + return --(instList.end()); +} + +template <class Impl> +void +FullO3CPU<Impl>::instDone(unsigned tid) +{ + // Keep an instruction count. + thread[tid]->numInst++; + thread[tid]->numInsts++; + committedInsts[tid]++; + totalCommittedInsts++; + + // Check for instruction-count-based events. + comInstEventQueue[tid]->serviceEvents(thread[tid]->numInst); +} + +template <class Impl> +void +FullO3CPU<Impl>::addToRemoveList(DynInstPtr &inst) +{ + removeInstsThisCycle = true; + + removeList.push(inst->getInstListIt()); +} + +template <class Impl> +void +FullO3CPU<Impl>::removeFrontInst(DynInstPtr &inst) +{ + DPRINTF(FullCPU, "FullCPU: Removing committed instruction [tid:%i] PC %#x " + "[sn:%lli]\n", + inst->threadNumber, inst->readPC(), inst->seqNum); + + removeInstsThisCycle = true; + + // Remove the front instruction. + removeList.push(inst->getInstListIt()); +} + +template <class Impl> +void +FullO3CPU<Impl>::removeInstsNotInROB(unsigned tid) +{ + DPRINTF(FullCPU, "FullCPU: Thread %i: Deleting instructions from instruction" + " list.\n", tid); + + ListIt end_it; + + bool rob_empty = false; + + if (instList.empty()) { + return; + } else if (rob.isEmpty(/*tid*/)) { + DPRINTF(FullCPU, "FullCPU: ROB is empty, squashing all insts.\n"); + end_it = instList.begin(); + rob_empty = true; + } else { + end_it = (rob.readTailInst(tid))->getInstListIt(); + DPRINTF(FullCPU, "FullCPU: ROB is not empty, squashing insts not in ROB.\n"); + } + + removeInstsThisCycle = true; + + ListIt inst_it = instList.end(); + + inst_it--; + + // Walk through the instruction list, removing any instructions + // that were inserted after the given instruction iterator, end_it. + while (inst_it != end_it) { + assert(!instList.empty()); + + squashInstIt(inst_it, tid); + + inst_it--; + } + + // If the ROB was empty, then we actually need to remove the first + // instruction as well. + if (rob_empty) { + squashInstIt(inst_it, tid); + } +} + +template <class Impl> +void +FullO3CPU<Impl>::removeInstsUntil(const InstSeqNum &seq_num, + unsigned tid) +{ + assert(!instList.empty()); + + removeInstsThisCycle = true; + + ListIt inst_iter = instList.end(); + + inst_iter--; + + DPRINTF(FullCPU, "FullCPU: Deleting instructions from instruction " + "list that are from [tid:%i] and above [sn:%lli] (end=%lli).\n", + tid, seq_num, (*inst_iter)->seqNum); + + while ((*inst_iter)->seqNum > seq_num) { + + bool break_loop = (inst_iter == instList.begin()); + + squashInstIt(inst_iter, tid); + + inst_iter--; + + if (break_loop) + break; + } +} + +template <class Impl> +inline void +FullO3CPU<Impl>::squashInstIt(const ListIt &instIt, const unsigned &tid) +{ + if ((*instIt)->threadNumber == tid) { + DPRINTF(FullCPU, "FullCPU: Squashing instruction, " + "[tid:%i] [sn:%lli] PC %#x\n", + (*instIt)->threadNumber, + (*instIt)->seqNum, + (*instIt)->readPC()); + + // Mark it as squashed. + (*instIt)->setSquashed(); + + // @todo: Formulate a consistent method for deleting + // instructions from the instruction list + // Remove the instruction from the list. + removeList.push(instIt); + } +} + +template <class Impl> +void +FullO3CPU<Impl>::cleanUpRemovedInsts() +{ + while (!removeList.empty()) { + DPRINTF(FullCPU, "FullCPU: Removing instruction, " + "[tid:%i] [sn:%lli] PC %#x\n", + (*removeList.front())->threadNumber, + (*removeList.front())->seqNum, + (*removeList.front())->readPC()); + + instList.erase(removeList.front()); + + removeList.pop(); + } + + removeInstsThisCycle = false; +} +/* +template <class Impl> +void +FullO3CPU<Impl>::removeAllInsts() +{ + instList.clear(); +} +*/ +template <class Impl> +void +FullO3CPU<Impl>::dumpInsts() +{ + int num = 0; + + ListIt inst_list_it = instList.begin(); + + cprintf("Dumping Instruction List\n"); + + while (inst_list_it != instList.end()) { + cprintf("Instruction:%i\nPC:%#x\n[tid:%i]\n[sn:%lli]\nIssued:%i\n" + "Squashed:%i\n\n", + num, (*inst_list_it)->readPC(), (*inst_list_it)->threadNumber, + (*inst_list_it)->seqNum, (*inst_list_it)->isIssued(), + (*inst_list_it)->isSquashed()); + inst_list_it++; + ++num; + } +} +/* +template <class Impl> +void +FullO3CPU<Impl>::wakeDependents(DynInstPtr &inst) +{ + iew.wakeDependents(inst); +} +*/ +template <class Impl> +void +FullO3CPU<Impl>::wakeCPU() +{ + if (activityRec.active() || tickEvent.scheduled()) { + DPRINTF(Activity, "CPU already running.\n"); + return; + } + + DPRINTF(Activity, "Waking up CPU\n"); + + idleCycles += (curTick - 1) - lastRunningCycle; + + tickEvent.schedule(curTick); +} + +template <class Impl> +int +FullO3CPU<Impl>::getFreeTid() +{ + for (int i=0; i < numThreads; i++) { + if (!tids[i]) { + tids[i] = true; + return i; + } + } + + return -1; +} + +template <class Impl> +void +FullO3CPU<Impl>::doContextSwitch() +{ + if (contextSwitch) { + + //ADD CODE TO DEACTIVE THREAD HERE (???) + + for (int tid=0; tid < cpuWaitList.size(); tid++) { + activateWhenReady(tid); + } + + if (cpuWaitList.size() == 0) + contextSwitch = true; + } +} + +template <class Impl> +void +FullO3CPU<Impl>::updateThreadPriority() +{ + if (activeThreads.size() > 1) + { + //DEFAULT TO ROUND ROBIN SCHEME + //e.g. Move highest priority to end of thread list + list<unsigned>::iterator list_begin = activeThreads.begin(); + list<unsigned>::iterator list_end = activeThreads.end(); + + unsigned high_thread = *list_begin; + + activeThreads.erase(list_begin); + + activeThreads.push_back(high_thread); + } +} + +// Forward declaration of FullO3CPU. +template class FullO3CPU<AlphaSimpleImpl>; diff --git a/src/cpu/o3/cpu.hh b/src/cpu/o3/cpu.hh new file mode 100644 index 000000000..bed95ad54 --- /dev/null +++ b/src/cpu/o3/cpu.hh @@ -0,0 +1,525 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __CPU_O3_CPU_HH__ +#define __CPU_O3_CPU_HH__ + +#include <iostream> +#include <list> +#include <queue> +#include <set> +#include <vector> + +#include "base/statistics.hh" +#include "base/timebuf.hh" +#include "config/full_system.hh" +#include "cpu/activity.hh" +#include "cpu/base.hh" +#include "cpu/cpu_exec_context.hh" +#include "cpu/o3/comm.hh" +#include "cpu/o3/cpu_policy.hh" +#include "cpu/o3/scoreboard.hh" +#include "cpu/o3/thread_state.hh" +#include "sim/process.hh" + +template <class> +class Checker; +class ExecContext; +class MemInterface; +class Process; + +class BaseFullCPU : public BaseCPU +{ + //Stuff that's pretty ISA independent will go here. + public: + typedef BaseCPU::Params Params; + + BaseFullCPU(Params *params); + + void regStats(); + + protected: + int cpu_id; +}; + +template <class Impl> +class FullO3CPU : public BaseFullCPU +{ + public: + // Typedefs from the Impl here. + typedef typename Impl::CPUPol CPUPolicy; + typedef typename Impl::Params Params; + typedef typename Impl::DynInstPtr DynInstPtr; + + typedef O3ThreadState<Impl> Thread; + + typedef typename std::list<DynInstPtr>::iterator ListIt; + + public: + enum Status { + Running, + Idle, + Halted, + Blocked, + SwitchedOut + }; + + /** Overall CPU status. */ + Status _status; + + private: + class TickEvent : public Event + { + private: + /** Pointer to the CPU. */ + FullO3CPU<Impl> *cpu; + + public: + /** Constructs a tick event. */ + TickEvent(FullO3CPU<Impl> *c); + + /** Processes a tick event, calling tick() on the CPU. */ + void process(); + /** Returns the description of the tick event. */ + const char *description(); + }; + + /** The tick event used for scheduling CPU ticks. */ + TickEvent tickEvent; + + /** Schedule tick event, regardless of its current state. */ + void scheduleTickEvent(int delay) + { + if (tickEvent.squashed()) + tickEvent.reschedule(curTick + cycles(delay)); + else if (!tickEvent.scheduled()) + tickEvent.schedule(curTick + cycles(delay)); + } + + /** Unschedule tick event, regardless of its current state. */ + void unscheduleTickEvent() + { + if (tickEvent.scheduled()) + tickEvent.squash(); + } + + public: + /** Constructs a CPU with the given parameters. */ + FullO3CPU(Params *params); + /** Destructor. */ + ~FullO3CPU(); + + /** Registers statistics. */ + void fullCPURegStats(); + + /** Ticks CPU, calling tick() on each stage, and checking the overall + * activity to see if the CPU should deschedule itself. + */ + void tick(); + + /** Initialize the CPU */ + void init(); + + /** Setup CPU to insert a thread's context */ + void insertThread(unsigned tid); + + /** Remove all of a thread's context from CPU */ + void removeThread(unsigned tid); + + /** Count the Total Instructions Committed in the CPU. */ + virtual Counter totalInstructions() const + { + Counter total(0); + + for (int i=0; i < thread.size(); i++) + total += thread[i]->numInst; + + return total; + } + + /** Add Thread to Active Threads List. */ + void activateContext(int tid, int delay); + + /** Remove Thread from Active Threads List */ + void suspendContext(int tid); + + /** Remove Thread from Active Threads List && + * Remove Thread Context from CPU. + */ + void deallocateContext(int tid); + + /** Remove Thread from Active Threads List && + * Remove Thread Context from CPU. + */ + void haltContext(int tid); + + /** Activate a Thread When CPU Resources are Available. */ + void activateWhenReady(int tid); + + /** Add or Remove a Thread Context in the CPU. */ + void doContextSwitch(); + + /** Update The Order In Which We Process Threads. */ + void updateThreadPriority(); + + /** Executes a syscall on this cycle. + * --------------------------------------- + * Note: this is a virtual function. CPU-Specific + * functionality defined in derived classes + */ + virtual void syscall(int tid) { panic("Unimplemented!"); } + + /** Check if there are any system calls pending. */ + void checkSyscalls(); + + /** Switches out this CPU. + */ + void switchOut(Sampler *sampler); + + void signalSwitched(); + + /** Takes over from another CPU. + */ + void takeOverFrom(BaseCPU *oldCPU); + + /** Get the current instruction sequence number, and increment it. */ + InstSeqNum getAndIncrementInstSeq() + { return globalSeqNum++; } + +#if FULL_SYSTEM + /** Check if this address is a valid instruction address. */ + bool validInstAddr(Addr addr) { return true; } + + /** Check if this address is a valid data address. */ + bool validDataAddr(Addr addr) { return true; } + + /** Get instruction asid. */ + int getInstAsid(unsigned tid) + { return regFile.miscRegs[tid].getInstAsid(); } + + /** Get data asid. */ + int getDataAsid(unsigned tid) + { return regFile.miscRegs[tid].getDataAsid(); } +#else + /** Check if this address is a valid instruction address. */ + bool validInstAddr(Addr addr,unsigned tid) + { return thread[tid]->validInstAddr(addr); } + + /** Check if this address is a valid data address. */ + bool validDataAddr(Addr addr,unsigned tid) + { return thread[tid]->validDataAddr(addr); } + + /** Get instruction asid. */ + int getInstAsid(unsigned tid) + { return thread[tid]->asid; } + + /** Get data asid. */ + int getDataAsid(unsigned tid) + { return thread[tid]->asid; } + +#endif + + // + // New accessors for new decoder. + // + uint64_t readIntReg(int reg_idx); + + FloatReg readFloatReg(int reg_idx); + + FloatReg readFloatReg(int reg_idx, int width); + + FloatRegBits readFloatRegBits(int reg_idx); + + FloatRegBits readFloatRegBits(int reg_idx, int width); + + void setIntReg(int reg_idx, uint64_t val); + + void setFloatReg(int reg_idx, FloatReg val, int width); + + void setFloatReg(int reg_idx, FloatReg val, int width); + + void setFloatRegBits(int reg_idx, FloatRegBits val); + + void setFloatRegBits(int reg_idx, FloatRegBits val); + + uint64_t readArchIntReg(int reg_idx, unsigned tid); + + float readArchFloatRegSingle(int reg_idx, unsigned tid); + + double readArchFloatRegDouble(int reg_idx, unsigned tid); + + uint64_t readArchFloatRegInt(int reg_idx, unsigned tid); + + void setArchIntReg(int reg_idx, uint64_t val, unsigned tid); + + void setArchFloatRegSingle(int reg_idx, float val, unsigned tid); + + void setArchFloatRegDouble(int reg_idx, double val, unsigned tid); + + void setArchFloatRegInt(int reg_idx, uint64_t val, unsigned tid); + + uint64_t readPC(unsigned tid); + + void setPC(Addr new_PC,unsigned tid); + + uint64_t readNextPC(unsigned tid); + + void setNextPC(uint64_t val,unsigned tid); + + /** Function to add instruction onto the head of the list of the + * instructions. Used when new instructions are fetched. + */ + ListIt addInst(DynInstPtr &inst); + + /** Function to tell the CPU that an instruction has completed. */ + void instDone(unsigned tid); + + /** Add Instructions to the CPU Remove List*/ + void addToRemoveList(DynInstPtr &inst); + + /** Remove an instruction from the front end of the list. There's + * no restriction on location of the instruction. + */ + void removeFrontInst(DynInstPtr &inst); + + /** Remove all instructions that are not currently in the ROB. */ + void removeInstsNotInROB(unsigned tid); + + /** Remove all instructions younger than the given sequence number. */ + void removeInstsUntil(const InstSeqNum &seq_num,unsigned tid); + + inline void squashInstIt(const ListIt &instIt, const unsigned &tid); + + void cleanUpRemovedInsts(); + + /** Remove all instructions from the list. */ +// void removeAllInsts(); + + void dumpInsts(); + + /** Basically a wrapper function so that instructions executed at + * commit can tell the instruction queue that they have + * completed. Eventually this hack should be removed. + */ +// void wakeDependents(DynInstPtr &inst); + + public: + /** List of all the instructions in flight. */ + std::list<DynInstPtr> instList; + + /** List of all the instructions that will be removed at the end of this + * cycle. + */ + std::queue<ListIt> removeList; + +#ifdef DEBUG + std::set<InstSeqNum> snList; +#endif + + /** Records if instructions need to be removed this cycle due to + * being retired or squashed. + */ + bool removeInstsThisCycle; + + protected: + /** The fetch stage. */ + typename CPUPolicy::Fetch fetch; + + /** The decode stage. */ + typename CPUPolicy::Decode decode; + + /** The dispatch stage. */ + typename CPUPolicy::Rename rename; + + /** The issue/execute/writeback stages. */ + typename CPUPolicy::IEW iew; + + /** The commit stage. */ + typename CPUPolicy::Commit commit; + + /** The register file. */ + typename CPUPolicy::RegFile regFile; + + /** The free list. */ + typename CPUPolicy::FreeList freeList; + + /** The rename map. */ + typename CPUPolicy::RenameMap renameMap[Impl::MaxThreads]; + + /** The commit rename map. */ + typename CPUPolicy::RenameMap commitRenameMap[Impl::MaxThreads]; + + /** The re-order buffer. */ + typename CPUPolicy::ROB rob; + + /** Active Threads List */ + std::list<unsigned> activeThreads; + + /** Integer Register Scoreboard */ + Scoreboard scoreboard; + + public: + /** Enum to give each stage a specific index, so when calling + * activateStage() or deactivateStage(), they can specify which stage + * is being activated/deactivated. + */ + enum StageIdx { + FetchIdx, + DecodeIdx, + RenameIdx, + IEWIdx, + CommitIdx, + NumStages }; + + /** Typedefs from the Impl to get the structs that each of the + * time buffers should use. + */ + typedef typename CPUPolicy::TimeStruct TimeStruct; + + typedef typename CPUPolicy::FetchStruct FetchStruct; + + typedef typename CPUPolicy::DecodeStruct DecodeStruct; + + typedef typename CPUPolicy::RenameStruct RenameStruct; + + typedef typename CPUPolicy::IEWStruct IEWStruct; + + /** The main time buffer to do backwards communication. */ + TimeBuffer<TimeStruct> timeBuffer; + + /** The fetch stage's instruction queue. */ + TimeBuffer<FetchStruct> fetchQueue; + + /** The decode stage's instruction queue. */ + TimeBuffer<DecodeStruct> decodeQueue; + + /** The rename stage's instruction queue. */ + TimeBuffer<RenameStruct> renameQueue; + + /** The IEW stage's instruction queue. */ + TimeBuffer<IEWStruct> iewQueue; + + public: + ActivityRecorder activityRec; + + void activityThisCycle() { activityRec.activity(); } + + void activateStage(const StageIdx idx) + { activityRec.activateStage(idx); } + + void deactivateStage(const StageIdx idx) + { activityRec.deactivateStage(idx); } + + /** Wakes the CPU, rescheduling the CPU if it's not already active. */ + void wakeCPU(); + + /** Gets a free thread id. Use if thread ids change across system. */ + int getFreeTid(); + + public: + /** Temporary function to get pointer to exec context. */ + ExecContext *xcBase(unsigned tid) + { + return thread[tid]->getXCProxy(); + } + + /** The global sequence number counter. */ + InstSeqNum globalSeqNum; + + Checker<DynInstPtr> *checker; + +#if FULL_SYSTEM + /** Pointer to the system. */ + System *system; + + /** Pointer to the memory controller. */ + MemoryController *memCtrl; + /** Pointer to physical memory. */ + PhysicalMemory *physmem; +#endif + + /** Pointer to memory. */ + FunctionalMemory *mem; + + Sampler *sampler; + + int switchCount; + + // List of all ExecContexts. + std::vector<Thread *> thread; + +#if 0 + /** Page table pointer. */ + PageTable *pTable; +#endif + + /** Pointer to the icache interface. */ + MemInterface *icacheInterface; + /** Pointer to the dcache interface. */ + MemInterface *dcacheInterface; + + /** Whether or not the CPU should defer its registration. */ + bool deferRegistration; + + /** Is there a context switch pending? */ + bool contextSwitch; + + /** Threads Scheduled to Enter CPU */ + std::list<int> cpuWaitList; + + /** The cycle that the CPU was last running, used for statistics. */ + Tick lastRunningCycle; + + /** Number of Threads CPU can process */ + unsigned numThreads; + + /** Mapping for system thread id to cpu id */ + std::map<unsigned,unsigned> threadMap; + + /** Available thread ids in the cpu*/ + std::vector<unsigned> tids; + + /** Stat for total number of times the CPU is descheduled. */ + Stats::Scalar<> timesIdled; + /** Stat for total number of cycles the CPU spends descheduled. */ + Stats::Scalar<> idleCycles; + /** Stat for the number of committed instructions per thread. */ + Stats::Vector<> committedInsts; + /** Stat for the total number of committed instructions. */ + Stats::Scalar<> totalCommittedInsts; + /** Stat for the CPI per thread. */ + Stats::Formula cpi; + /** Stat for the total CPI. */ + Stats::Formula totalCpi; + /** Stat for the IPC per thread. */ + Stats::Formula ipc; + /** Stat for the total IPC. */ + Stats::Formula totalIpc; +}; + +#endif // __CPU_O3_CPU_HH__ diff --git a/cpu/o3/cpu_policy.hh b/src/cpu/o3/cpu_policy.hh index 52227013e..52227013e 100644 --- a/cpu/o3/cpu_policy.hh +++ b/src/cpu/o3/cpu_policy.hh diff --git a/cpu/o3/decode.cc b/src/cpu/o3/decode.cc index b14fbb7a3..b14fbb7a3 100644 --- a/cpu/o3/decode.cc +++ b/src/cpu/o3/decode.cc diff --git a/cpu/o3/decode.hh b/src/cpu/o3/decode.hh index 3035b3387..3035b3387 100644 --- a/cpu/o3/decode.hh +++ b/src/cpu/o3/decode.hh diff --git a/cpu/o3/decode_impl.hh b/src/cpu/o3/decode_impl.hh index 2ed7ec6fc..2ed7ec6fc 100644 --- a/cpu/o3/decode_impl.hh +++ b/src/cpu/o3/decode_impl.hh diff --git a/cpu/o3/fetch.cc b/src/cpu/o3/fetch.cc index 7959416be..7959416be 100644 --- a/cpu/o3/fetch.cc +++ b/src/cpu/o3/fetch.cc diff --git a/cpu/o3/fetch.hh b/src/cpu/o3/fetch.hh index 3fcfdc3a1..3fcfdc3a1 100644 --- a/cpu/o3/fetch.hh +++ b/src/cpu/o3/fetch.hh diff --git a/cpu/o3/fetch_impl.hh b/src/cpu/o3/fetch_impl.hh index 1c5e508f6..1c5e508f6 100644 --- a/cpu/o3/fetch_impl.hh +++ b/src/cpu/o3/fetch_impl.hh diff --git a/cpu/o3/free_list.cc b/src/cpu/o3/free_list.cc index bd0f4f034..bd0f4f034 100644 --- a/cpu/o3/free_list.cc +++ b/src/cpu/o3/free_list.cc diff --git a/cpu/o3/free_list.hh b/src/cpu/o3/free_list.hh index 29e84cd44..29e84cd44 100644 --- a/cpu/o3/free_list.hh +++ b/src/cpu/o3/free_list.hh diff --git a/cpu/o3/iew.cc b/src/cpu/o3/iew.cc index 90d035f71..90d035f71 100644 --- a/cpu/o3/iew.cc +++ b/src/cpu/o3/iew.cc diff --git a/cpu/o3/iew.hh b/src/cpu/o3/iew.hh index 935320628..935320628 100644 --- a/cpu/o3/iew.hh +++ b/src/cpu/o3/iew.hh diff --git a/cpu/o3/iew_impl.hh b/src/cpu/o3/iew_impl.hh index b0137d7fc..b0137d7fc 100644 --- a/cpu/o3/iew_impl.hh +++ b/src/cpu/o3/iew_impl.hh diff --git a/cpu/o3/inst_queue.cc b/src/cpu/o3/inst_queue.cc index 95ae2b699..95ae2b699 100644 --- a/cpu/o3/inst_queue.cc +++ b/src/cpu/o3/inst_queue.cc diff --git a/cpu/o3/inst_queue.hh b/src/cpu/o3/inst_queue.hh index 518de73d9..518de73d9 100644 --- a/cpu/o3/inst_queue.hh +++ b/src/cpu/o3/inst_queue.hh diff --git a/cpu/o3/inst_queue_impl.hh b/src/cpu/o3/inst_queue_impl.hh index f1dc4e01f..f1dc4e01f 100644 --- a/cpu/o3/inst_queue_impl.hh +++ b/src/cpu/o3/inst_queue_impl.hh diff --git a/cpu/o3/mem_dep_unit.cc b/src/cpu/o3/mem_dep_unit.cc index ccdd1a515..ccdd1a515 100644 --- a/cpu/o3/mem_dep_unit.cc +++ b/src/cpu/o3/mem_dep_unit.cc diff --git a/cpu/o3/mem_dep_unit.hh b/src/cpu/o3/mem_dep_unit.hh index acbe08ec2..acbe08ec2 100644 --- a/cpu/o3/mem_dep_unit.hh +++ b/src/cpu/o3/mem_dep_unit.hh diff --git a/cpu/o3/mem_dep_unit_impl.hh b/src/cpu/o3/mem_dep_unit_impl.hh index 8b195baab..8b195baab 100644 --- a/cpu/o3/mem_dep_unit_impl.hh +++ b/src/cpu/o3/mem_dep_unit_impl.hh diff --git a/cpu/o3/ras.cc b/src/cpu/o3/ras.cc index 0b3ea4918..0b3ea4918 100644 --- a/cpu/o3/ras.cc +++ b/src/cpu/o3/ras.cc diff --git a/cpu/o3/ras.hh b/src/cpu/o3/ras.hh index 27e7c2df4..27e7c2df4 100644 --- a/cpu/o3/ras.hh +++ b/src/cpu/o3/ras.hh diff --git a/src/cpu/o3/regfile.hh b/src/cpu/o3/regfile.hh new file mode 100644 index 000000000..3350903db --- /dev/null +++ b/src/cpu/o3/regfile.hh @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __CPU_O3_REGFILE_HH__ +#define __CPU_O3_REGFILE_HH__ + +#include "arch/isa_traits.hh" +#include "arch/faults.hh" +#include "base/trace.hh" +#include "config/full_system.hh" +#include "cpu/o3/comm.hh" + +#if FULL_SYSTEM +#include "kern/kernel_stats.hh" + +#endif + +#include <vector> + +/** + * Simple physical register file class. + * This really only depends on the ISA, and not the Impl. Things that are + * in the ifdef FULL_SYSTEM are pretty dependent on the ISA, and probably + * should go in the AlphaFullCPU. + */ +template <class Impl> +class PhysRegFile +{ + protected: + typedef TheISA::IntReg IntReg; + typedef TheISA::FloatReg FloatReg; + typedef TheISA::MiscRegFile MiscRegFile; + typedef TheISA::MiscReg MiscReg; + // Note that most of the definitions of the IntReg, FloatReg, etc. exist + // within the Impl/ISA class and not within this PhysRegFile class. + + // Will make these registers public for now, but they probably should + // be private eventually with some accessor functions. + public: + typedef typename Impl::FullCPU FullCPU; + + /** + * Constructs a physical register file with the specified amount of + * integer and floating point registers. + */ + PhysRegFile(unsigned _numPhysicalIntRegs, + unsigned _numPhysicalFloatRegs); + + //Everything below should be pretty well identical to the normal + //register file that exists within AlphaISA class. + //The duplication is unfortunate but it's better than having + //different ways to access certain registers. + + //Add these in later when everything else is in place +// void serialize(std::ostream &os); +// void unserialize(Checkpoint *cp, const std::string §ion); + + /** Reads an integer register. */ + uint64_t readIntReg(PhysRegIndex reg_idx) + { + assert(reg_idx < numPhysicalIntRegs); + + DPRINTF(IEW, "RegFile: Access to int register %i, has data " + "%i\n", int(reg_idx), intRegFile[reg_idx]); + return intRegFile[reg_idx]; + } + + FloatReg readFloatReg(PhysRegIndex reg_idx, int width) + { + // Remove the base Float reg dependency. + reg_idx = reg_idx - numPhysicalIntRegs; + + assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs); + + FloatReg floatReg = floatRegFile.readReg(reg_idx, width); + + DPRINTF(IEW, "RegFile: Access to %d byte float register %i, has " + "data %8.8d\n", int(reg_idx), (double)floatReg); + + return floatReg; + } + + /** Reads a floating point register (double precision). */ + FloatReg readFloatReg(PhysRegIndex reg_idx) + { + // Remove the base Float reg dependency. + reg_idx = reg_idx - numPhysicalIntRegs; + + assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs); + + FloatReg floatReg = floatRegFile.readReg(reg_idx); + + DPRINTF(IEW, "RegFile: Access to float register %i, has " + "data %8.8d\n", int(reg_idx), (double)floatReg); + + return floatReg; + } + + /** Reads a floating point register as an integer. */ + FloatRegBits readFloatRegBits(PhysRegIndex reg_idx, int width) + { + // Remove the base Float reg dependency. + reg_idx = reg_idx - numPhysicalIntRegs; + + assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs); + + FloatRegBits floatRegBits = floatRegFile.readRegBits(reg_idx, width); + + DPRINTF(IEW, "RegFile: Access to %d byte float register %i as int, " + "has data %lli\n", int(reg_idx), (uint64_t)floatRegBits); + + return floatRegBits; + } + + FloatRegBits readFloatRegBits(PhysRegIndex reg_idx) + { + // Remove the base Float reg dependency. + reg_idx = reg_idx - numPhysicalIntRegs; + + assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs); + + FloatRegBits floatRegBits = floatRegFile.readRegBits(reg_idx); + + DPRINTF(IEW, "RegFile: Access to float register %i as int, " + "has data %lli\n", int(reg_idx), (uint64_t)floatRegBits); + + return floatRegBits; + } + + /** Sets an integer register to the given value. */ + void setIntReg(PhysRegIndex reg_idx, uint64_t val) + { + assert(reg_idx < numPhysicalIntRegs); + + DPRINTF(IEW, "RegFile: Setting int register %i to %lli\n", + int(reg_idx), val); + + if (reg_idx != TheISA::ZeroReg) + intRegFile[reg_idx] = val; + } + + /** Sets a single precision floating point register to the given value. */ + void setFloatReg(PhysRegIndex reg_idx, FloatReg val, int width) + { + // Remove the base Float reg dependency. + reg_idx = reg_idx - numPhysicalIntRegs; + + assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs); + + DPRINTF(IEW, "RegFile: Setting float register %i to %8.8d\n", + int(reg_idx), (double)val); + + if (reg_idx != TheISA::ZeroReg) + floatRegFile.setReg(reg_idx, val, width); + } + + /** Sets a double precision floating point register to the given value. */ + void setFloatReg(PhysRegIndex reg_idx, FloatReg val) + { + // Remove the base Float reg dependency. + reg_idx = reg_idx - numPhysicalIntRegs; + + assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs); + + DPRINTF(IEW, "RegFile: Setting float register %i to %8.8d\n", + int(reg_idx), (double)val); + + if (reg_idx != TheISA::ZeroReg) + floatRegFile.setReg(reg_idx, val); + } + + /** Sets a floating point register to the given integer value. */ + void setFloatRegBits(PhysRegIndex reg_idx, FloatRegBits val, int width) + { + // Remove the base Float reg dependency. + reg_idx = reg_idx - numPhysicalIntRegs; + + assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs); + + DPRINTF(IEW, "RegFile: Setting float register %i to %lli\n", + int(reg_idx), (uint64_t)val); + + floatRegFile.setRegBits(reg_idx, val, width); + } + + void setFloatRegBits(PhysRegIndex reg_idx, FloatRegBits val) + { + // Remove the base Float reg dependency. + reg_idx = reg_idx - numPhysicalIntRegs; + + assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs); + + DPRINTF(IEW, "RegFile: Setting float register %i to %lli\n", + int(reg_idx), (uint64_t)val); + } + + MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault, + unsigned thread_id) + { + return miscRegs[thread_id].readRegWithEffect(misc_reg, fault, + cpu->xcBase(thread_id)); + } + + Fault setMiscReg(int misc_reg, const MiscReg &val, unsigned thread_id) + { + return miscRegs[thread_id].setReg(misc_reg, val); + } + + Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val, + unsigned thread_id) + { + return miscRegs[thread_id].setRegWithEffect(misc_reg, val, + cpu->xcBase(thread_id)); + } + +#if FULL_SYSTEM + int readIntrFlag() { return intrflag; } + /** Sets an interrupt flag. */ + void setIntrFlag(int val) { intrflag = val; } +#endif + + public: + /** (signed) integer register file. */ + std::vector<IntReg> intRegFile; + + /** Floating point register file. */ + std::vector<FloatReg> floatRegFile; + + /** Miscellaneous register file. */ + MiscRegFile miscRegs[Impl::MaxThreads]; + +#if FULL_SYSTEM + private: + int intrflag; // interrupt flag +#endif + + private: + /** CPU pointer. */ + FullCPU *cpu; + + public: + /** Sets the CPU pointer. */ + void setCPU(FullCPU *cpu_ptr) { cpu = cpu_ptr; } + + /** Number of physical integer registers. */ + unsigned numPhysicalIntRegs; + /** Number of physical floating point registers. */ + unsigned numPhysicalFloatRegs; +}; + +template <class Impl> +PhysRegFile<Impl>::PhysRegFile(unsigned _numPhysicalIntRegs, + unsigned _numPhysicalFloatRegs) + : numPhysicalIntRegs(_numPhysicalIntRegs), + numPhysicalFloatRegs(_numPhysicalFloatRegs) +{ + intRegFile.resize(numPhysicalIntRegs); + floatRegFile.resize(numPhysicalFloatRegs); + + //memset(intRegFile, 0, sizeof(*intRegFile)); + //memset(floatRegFile, 0, sizeof(*floatRegFile)); +} + +#endif diff --git a/cpu/o3/rename.cc b/src/cpu/o3/rename.cc index 4dc3bf6b2..4dc3bf6b2 100644 --- a/cpu/o3/rename.cc +++ b/src/cpu/o3/rename.cc diff --git a/cpu/o3/rename.hh b/src/cpu/o3/rename.hh index 3f1a27bb5..3f1a27bb5 100644 --- a/cpu/o3/rename.hh +++ b/src/cpu/o3/rename.hh diff --git a/cpu/o3/rename_impl.hh b/src/cpu/o3/rename_impl.hh index b4f1077d1..b4f1077d1 100644 --- a/cpu/o3/rename_impl.hh +++ b/src/cpu/o3/rename_impl.hh diff --git a/cpu/o3/rename_map.cc b/src/cpu/o3/rename_map.cc index fc59058a1..fc59058a1 100644 --- a/cpu/o3/rename_map.cc +++ b/src/cpu/o3/rename_map.cc diff --git a/cpu/o3/rename_map.hh b/src/cpu/o3/rename_map.hh index d7e49ae83..d7e49ae83 100644 --- a/cpu/o3/rename_map.hh +++ b/src/cpu/o3/rename_map.hh diff --git a/cpu/o3/rob.cc b/src/cpu/o3/rob.cc index c10f782fd..c10f782fd 100644 --- a/cpu/o3/rob.cc +++ b/src/cpu/o3/rob.cc diff --git a/cpu/o3/rob.hh b/src/cpu/o3/rob.hh index e05eebe5a..e05eebe5a 100644 --- a/cpu/o3/rob.hh +++ b/src/cpu/o3/rob.hh diff --git a/cpu/o3/rob_impl.hh b/src/cpu/o3/rob_impl.hh index 25e0c80fd..25e0c80fd 100644 --- a/cpu/o3/rob_impl.hh +++ b/src/cpu/o3/rob_impl.hh diff --git a/src/cpu/o3/sat_counter.cc b/src/cpu/o3/sat_counter.cc new file mode 100644 index 000000000..b481b4ad2 --- /dev/null +++ b/src/cpu/o3/sat_counter.cc @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "base/misc.hh" +#include "cpu/o3/sat_counter.hh" + +SatCounter::SatCounter() + : initialVal(0), counter(0) +{ +} + +SatCounter::SatCounter(unsigned bits) + : initialVal(0), maxVal((1 << bits) - 1), counter(0) +{ +} + +SatCounter::SatCounter(unsigned bits, uint8_t initial_val) + : initialVal(initialVal), maxVal((1 << bits) - 1), counter(initial_val) +{ + // Check to make sure initial value doesn't exceed the max counter value. + if (initial_val > maxVal) { + fatal("BP: Initial counter value exceeds max size."); + } +} + +void +SatCounter::setBits(unsigned bits) +{ + maxVal = (1 << bits) - 1; +} diff --git a/cpu/o3/sat_counter.hh b/src/cpu/o3/sat_counter.hh index d01fd93ce..d01fd93ce 100644 --- a/cpu/o3/sat_counter.hh +++ b/src/cpu/o3/sat_counter.hh diff --git a/cpu/o3/store_set.cc b/src/cpu/o3/store_set.cc index 0c957c8c7..0c957c8c7 100644 --- a/cpu/o3/store_set.cc +++ b/src/cpu/o3/store_set.cc diff --git a/cpu/o3/store_set.hh b/src/cpu/o3/store_set.hh index 7189db3ab..7189db3ab 100644 --- a/cpu/o3/store_set.hh +++ b/src/cpu/o3/store_set.hh diff --git a/cpu/o3/tournament_pred.cc b/src/cpu/o3/tournament_pred.cc index 89da7b9f5..89da7b9f5 100644 --- a/cpu/o3/tournament_pred.cc +++ b/src/cpu/o3/tournament_pred.cc diff --git a/cpu/o3/tournament_pred.hh b/src/cpu/o3/tournament_pred.hh index 7b600aa53..7b600aa53 100644 --- a/cpu/o3/tournament_pred.hh +++ b/src/cpu/o3/tournament_pred.hh diff --git a/src/cpu/op_class.cc b/src/cpu/op_class.cc new file mode 100644 index 000000000..00136ded5 --- /dev/null +++ b/src/cpu/op_class.cc @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "cpu/op_class.hh" + +/** OpClass enum -> description string */ +const char * +opClassStrings[Num_OpClasses] = +{ + "(null)", + "IntAlu", + "IntMult", + "IntDiv", + "FloatAdd", + "FloatCmp", + "FloatCvt", + "FloatMult", + "FloatDiv", + "FloatSqrt", + "MemRead", + "MemWrite", + "IprAccess", + "InstPrefetch" +}; + diff --git a/src/cpu/op_class.hh b/src/cpu/op_class.hh new file mode 100644 index 000000000..cdb40a0fb --- /dev/null +++ b/src/cpu/op_class.hh @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __CPU__OP_CLASS_HH__ +#define __CPU__OP_CLASS_HH__ + +/** + * @file + * Definition of operation classes. + */ + +/** + * Instruction operation classes. These classes are used for + * assigning instructions to functional units. + */ +enum OpClass { + No_OpClass = 0, ///< Instruction does not use a functional unit + IntAluOp, ///< Integer ALU operaton (add/sub/logical) + IntMultOp, ///< Integer multiply + IntDivOp, ///< Integer divide + FloatAddOp, ///< Floating point add/subtract + FloatCmpOp, ///< Floating point comparison + FloatCvtOp, ///< Floating point<->integer conversion + FloatMultOp, ///< Floating point multiply + FloatDivOp, ///< Floating point divide + FloatSqrtOp, ///< Floating point square root + MemReadOp, ///< Memory read port + MemWriteOp, ///< Memory write port + IprAccessOp, ///< Internal Processor Register read/write port + InstPrefetchOp, ///< Instruction prefetch port (on I-cache) + Num_OpClasses ///< Total number of operation classes +}; + +/** + * Array mapping OpClass enum values to strings. Defined in op_class.cc. + */ +extern const char *opClassStrings[]; + +#endif // __CPU__OP_CLASS_HH__ diff --git a/cpu/ozone/cpu.cc b/src/cpu/ozone/cpu.cc index d2ea0164c..d2ea0164c 100644 --- a/cpu/ozone/cpu.cc +++ b/src/cpu/ozone/cpu.cc diff --git a/cpu/ozone/cpu.hh b/src/cpu/ozone/cpu.hh index 5af2b02b2..5af2b02b2 100644 --- a/cpu/ozone/cpu.hh +++ b/src/cpu/ozone/cpu.hh diff --git a/cpu/ozone/cpu_impl.hh b/src/cpu/ozone/cpu_impl.hh index 5675da3a8..5675da3a8 100644 --- a/cpu/ozone/cpu_impl.hh +++ b/src/cpu/ozone/cpu_impl.hh diff --git a/cpu/ozone/ea_list.cc b/src/cpu/ozone/ea_list.cc index 6114a0ca1..6114a0ca1 100644 --- a/cpu/ozone/ea_list.cc +++ b/src/cpu/ozone/ea_list.cc diff --git a/cpu/ozone/ea_list.hh b/src/cpu/ozone/ea_list.hh index c0eee4bb8..c0eee4bb8 100644 --- a/cpu/ozone/ea_list.hh +++ b/src/cpu/ozone/ea_list.hh diff --git a/cpu/pc_event.cc b/src/cpu/pc_event.cc index 050bf1a88..050bf1a88 100644 --- a/cpu/pc_event.cc +++ b/src/cpu/pc_event.cc diff --git a/src/cpu/pc_event.hh b/src/cpu/pc_event.hh new file mode 100644 index 000000000..32b7f3ef5 --- /dev/null +++ b/src/cpu/pc_event.hh @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __PC_EVENT_HH__ +#define __PC_EVENT_HH__ + +#include <vector> + +#include "base/misc.hh" + +class ExecContext; +class PCEventQueue; + +class PCEvent +{ + protected: + std::string description; + PCEventQueue *queue; + Addr evpc; + + public: + PCEvent(PCEventQueue *q, const std::string &desc, Addr pc); + + virtual ~PCEvent() { if (queue) remove(); } + + // for DPRINTF + virtual const std::string name() const { return description; } + + std::string descr() const { return description; } + Addr pc() const { return evpc; } + + bool remove(); + virtual void process(ExecContext *xc) = 0; +}; + +class PCEventQueue +{ + protected: + typedef PCEvent * record_t; + class MapCompare { + public: + bool operator()(const record_t &l, const record_t &r) const { + return l->pc() < r->pc(); + } + bool operator()(const record_t &l, Addr pc) const { + return l->pc() < pc; + } + bool operator()(Addr pc, const record_t &r) const { + return pc < r->pc(); + } + }; + typedef std::vector<record_t> map_t; + + public: + typedef map_t::iterator iterator; + typedef map_t::const_iterator const_iterator; + + protected: + typedef std::pair<iterator, iterator> range_t; + typedef std::pair<const_iterator, const_iterator> const_range_t; + + protected: + map_t pc_map; + + bool doService(ExecContext *xc); + + public: + PCEventQueue(); + ~PCEventQueue(); + + bool remove(PCEvent *event); + bool schedule(PCEvent *event); + bool service(ExecContext *xc) + { + if (pc_map.empty()) + return false; + + return doService(xc); + } + + range_t equal_range(Addr pc); + range_t equal_range(PCEvent *event) { return equal_range(event->pc()); } + + void dump() const; +}; + + +inline +PCEvent::PCEvent(PCEventQueue *q, const std::string &desc, Addr pc) + : description(desc), queue(q), evpc(pc) +{ + queue->schedule(this); +} + +inline bool +PCEvent::remove() +{ + if (!queue) + panic("cannot remove an uninitialized event;"); + + return queue->remove(this); +} + +class BreakPCEvent : public PCEvent +{ + protected: + bool remove; + + public: + BreakPCEvent(PCEventQueue *q, const std::string &desc, Addr addr, + bool del = false); + virtual void process(ExecContext *xc); +}; + +#endif // __PC_EVENT_HH__ diff --git a/cpu/profile.cc b/src/cpu/profile.cc index fe3458b61..fe3458b61 100644 --- a/cpu/profile.cc +++ b/src/cpu/profile.cc diff --git a/cpu/profile.hh b/src/cpu/profile.hh index d55c9eec9..d55c9eec9 100644 --- a/cpu/profile.hh +++ b/src/cpu/profile.hh diff --git a/src/cpu/simple/atomic.cc b/src/cpu/simple/atomic.cc new file mode 100644 index 000000000..3cad6e43f --- /dev/null +++ b/src/cpu/simple/atomic.cc @@ -0,0 +1,546 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "arch/utility.hh" +#include "cpu/exetrace.hh" +#include "cpu/simple/atomic.hh" +#include "mem/packet_impl.hh" +#include "sim/builder.hh" + +using namespace std; +using namespace TheISA; + +AtomicSimpleCPU::TickEvent::TickEvent(AtomicSimpleCPU *c) + : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c) +{ +} + + +void +AtomicSimpleCPU::TickEvent::process() +{ + cpu->tick(); +} + +const char * +AtomicSimpleCPU::TickEvent::description() +{ + return "AtomicSimpleCPU tick event"; +} + + +void +AtomicSimpleCPU::init() +{ + //Create Memory Ports (conect them up) + Port *mem_dport = mem->getPort(""); + dcachePort.setPeer(mem_dport); + mem_dport->setPeer(&dcachePort); + + Port *mem_iport = mem->getPort(""); + icachePort.setPeer(mem_iport); + mem_iport->setPeer(&icachePort); + + BaseCPU::init(); +#if FULL_SYSTEM + for (int i = 0; i < execContexts.size(); ++i) { + ExecContext *xc = execContexts[i]; + + // initialize CPU, including PC + TheISA::initCPU(xc, xc->readCpuId()); + } +#endif +} + +bool +AtomicSimpleCPU::CpuPort::recvTiming(Packet *pkt) +{ + panic("AtomicSimpleCPU doesn't expect recvAtomic callback!"); + return true; +} + +Tick +AtomicSimpleCPU::CpuPort::recvAtomic(Packet *pkt) +{ + panic("AtomicSimpleCPU doesn't expect recvAtomic callback!"); + return curTick; +} + +void +AtomicSimpleCPU::CpuPort::recvFunctional(Packet *pkt) +{ + panic("AtomicSimpleCPU doesn't expect recvFunctional callback!"); +} + +void +AtomicSimpleCPU::CpuPort::recvStatusChange(Status status) +{ + if (status == RangeChange) + return; + + panic("AtomicSimpleCPU doesn't expect recvStatusChange callback!"); +} + +Packet * +AtomicSimpleCPU::CpuPort::recvRetry() +{ + panic("AtomicSimpleCPU doesn't expect recvRetry callback!"); + return NULL; +} + + +AtomicSimpleCPU::AtomicSimpleCPU(Params *p) + : BaseSimpleCPU(p), tickEvent(this), + width(p->width), simulate_stalls(p->simulate_stalls), + icachePort(name() + "-iport", this), dcachePort(name() + "-iport", this) +{ + _status = Idle; + + ifetch_req = new Request(true); + ifetch_req->setAsid(0); + // @todo fix me and get the real cpu iD!!! + ifetch_req->setCpuNum(0); + ifetch_req->setSize(sizeof(MachInst)); + ifetch_pkt = new Packet(ifetch_req, Packet::ReadReq, Packet::Broadcast); + ifetch_pkt->dataStatic(&inst); + + data_read_req = new Request(true); + // @todo fix me and get the real cpu iD!!! + data_read_req->setCpuNum(0); + data_read_req->setAsid(0); + data_read_pkt = new Packet(data_read_req, Packet::ReadReq, + Packet::Broadcast); + data_read_pkt->dataStatic(&dataReg); + + data_write_req = new Request(true); + // @todo fix me and get the real cpu iD!!! + data_write_req->setCpuNum(0); + data_write_req->setAsid(0); + data_write_pkt = new Packet(data_write_req, Packet::WriteReq, + Packet::Broadcast); +} + + +AtomicSimpleCPU::~AtomicSimpleCPU() +{ +} + +void +AtomicSimpleCPU::serialize(ostream &os) +{ + BaseSimpleCPU::serialize(os); + SERIALIZE_ENUM(_status); + nameOut(os, csprintf("%s.tickEvent", name())); + tickEvent.serialize(os); +} + +void +AtomicSimpleCPU::unserialize(Checkpoint *cp, const string §ion) +{ + BaseSimpleCPU::unserialize(cp, section); + UNSERIALIZE_ENUM(_status); + tickEvent.unserialize(cp, csprintf("%s.tickEvent", section)); +} + +void +AtomicSimpleCPU::switchOut(Sampler *s) +{ + sampler = s; + if (status() == Running) { + _status = SwitchedOut; + + tickEvent.squash(); + } + sampler->signalSwitched(); +} + + +void +AtomicSimpleCPU::takeOverFrom(BaseCPU *oldCPU) +{ + BaseCPU::takeOverFrom(oldCPU); + + assert(!tickEvent.scheduled()); + + // if any of this CPU's ExecContexts are active, mark the CPU as + // running and schedule its tick event. + for (int i = 0; i < execContexts.size(); ++i) { + ExecContext *xc = execContexts[i]; + if (xc->status() == ExecContext::Active && _status != Running) { + _status = Running; + tickEvent.schedule(curTick); + break; + } + } +} + + +void +AtomicSimpleCPU::activateContext(int thread_num, int delay) +{ + assert(thread_num == 0); + assert(cpuXC); + + assert(_status == Idle); + assert(!tickEvent.scheduled()); + + notIdleFraction++; + tickEvent.schedule(curTick + cycles(delay)); + _status = Running; +} + + +void +AtomicSimpleCPU::suspendContext(int thread_num) +{ + assert(thread_num == 0); + assert(cpuXC); + + assert(_status == Running); + + // tick event may not be scheduled if this gets called from inside + // an instruction's execution, e.g. "quiesce" + if (tickEvent.scheduled()) + tickEvent.deschedule(); + + notIdleFraction--; + _status = Idle; +} + + +template <class T> +Fault +AtomicSimpleCPU::read(Addr addr, T &data, unsigned flags) +{ + data_read_req->setVaddr(addr); + data_read_req->setSize(sizeof(T)); + data_read_req->setFlags(flags); + data_read_req->setTime(curTick); + + if (traceData) { + traceData->setAddr(addr); + } + + // translate to physical address + Fault fault = cpuXC->translateDataReadReq(data_read_req); + + // Now do the access. + if (fault == NoFault) { + data_read_pkt->reset(); + data_read_pkt->reinitFromRequest(); + + dcache_complete = dcachePort.sendAtomic(data_read_pkt); + dcache_access = true; + + assert(data_read_pkt->result == Packet::Success); + data = data_read_pkt->get<T>(); + + } + + // This will need a new way to tell if it has a dcache attached. + if (data_read_req->getFlags() & UNCACHEABLE) + recordEvent("Uncached Read"); + + return fault; +} + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +template +Fault +AtomicSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags); + +template +Fault +AtomicSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags); + +template +Fault +AtomicSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags); + +template +Fault +AtomicSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags); + +#endif //DOXYGEN_SHOULD_SKIP_THIS + +template<> +Fault +AtomicSimpleCPU::read(Addr addr, double &data, unsigned flags) +{ + return read(addr, *(uint64_t*)&data, flags); +} + +template<> +Fault +AtomicSimpleCPU::read(Addr addr, float &data, unsigned flags) +{ + return read(addr, *(uint32_t*)&data, flags); +} + + +template<> +Fault +AtomicSimpleCPU::read(Addr addr, int32_t &data, unsigned flags) +{ + return read(addr, (uint32_t&)data, flags); +} + + +template <class T> +Fault +AtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) +{ + data_write_req->setVaddr(addr); + data_write_req->setTime(curTick); + data_write_req->setSize(sizeof(T)); + data_write_req->setFlags(flags); + + if (traceData) { + traceData->setAddr(addr); + } + + // translate to physical address + Fault fault = cpuXC->translateDataWriteReq(data_write_req); + + // Now do the access. + if (fault == NoFault) { + data_write_pkt->reset(); + data = htog(data); + data_write_pkt->dataStatic(&data); + data_write_pkt->reinitFromRequest(); + + dcache_complete = dcachePort.sendAtomic(data_write_pkt); + dcache_access = true; + + assert(data_write_pkt->result == Packet::Success); + + if (res && data_write_req->getFlags() & LOCKED) { + *res = data_write_req->getScResult(); + } + } + + // This will need a new way to tell if it's hooked up to a cache or not. + if (data_write_req->getFlags() & UNCACHEABLE) + recordEvent("Uncached Write"); + + // If the write needs to have a fault on the access, consider calling + // changeStatus() and changing it to "bad addr write" or something. + return fault; +} + + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +template +Fault +AtomicSimpleCPU::write(uint64_t data, Addr addr, + unsigned flags, uint64_t *res); + +template +Fault +AtomicSimpleCPU::write(uint32_t data, Addr addr, + unsigned flags, uint64_t *res); + +template +Fault +AtomicSimpleCPU::write(uint16_t data, Addr addr, + unsigned flags, uint64_t *res); + +template +Fault +AtomicSimpleCPU::write(uint8_t data, Addr addr, + unsigned flags, uint64_t *res); + +#endif //DOXYGEN_SHOULD_SKIP_THIS + +template<> +Fault +AtomicSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) +{ + return write(*(uint64_t*)&data, addr, flags, res); +} + +template<> +Fault +AtomicSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) +{ + return write(*(uint32_t*)&data, addr, flags, res); +} + + +template<> +Fault +AtomicSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) +{ + return write((uint32_t)data, addr, flags, res); +} + + +void +AtomicSimpleCPU::tick() +{ + Tick latency = cycles(1); // instruction takes one cycle by default + + for (int i = 0; i < width; ++i) { + numCycles++; + + checkForInterrupts(); + + ifetch_req->resetMin(); + ifetch_pkt->reset(); + Fault fault = setupFetchPacket(ifetch_pkt); + + if (fault == NoFault) { + Tick icache_complete = icachePort.sendAtomic(ifetch_pkt); + // ifetch_req is initialized to read the instruction directly + // into the CPU object's inst field. + + dcache_access = false; // assume no dcache access + preExecute(); + fault = curStaticInst->execute(this, traceData); + postExecute(); + + if (simulate_stalls) { + // This calculation assumes that the icache and dcache + // access latencies are always a multiple of the CPU's + // cycle time. If not, the next tick event may get + // scheduled at a non-integer multiple of the CPU + // cycle time. + Tick icache_stall = icache_complete - curTick - cycles(1); + Tick dcache_stall = + dcache_access ? dcache_complete - curTick - cycles(1) : 0; + latency += icache_stall + dcache_stall; + } + + } + + advancePC(fault); + } + + if (_status != Idle) + tickEvent.schedule(curTick + latency); +} + + +//////////////////////////////////////////////////////////////////////// +// +// AtomicSimpleCPU Simulation Object +// +BEGIN_DECLARE_SIM_OBJECT_PARAMS(AtomicSimpleCPU) + + Param<Counter> max_insts_any_thread; + Param<Counter> max_insts_all_threads; + Param<Counter> max_loads_any_thread; + Param<Counter> max_loads_all_threads; + SimObjectParam<MemObject *> mem; + +#if FULL_SYSTEM + SimObjectParam<AlphaITB *> itb; + SimObjectParam<AlphaDTB *> dtb; + SimObjectParam<System *> system; + Param<int> cpu_id; + Param<Tick> profile; +#else + SimObjectParam<Process *> workload; +#endif // FULL_SYSTEM + + Param<int> clock; + + Param<bool> defer_registration; + Param<int> width; + Param<bool> function_trace; + Param<Tick> function_trace_start; + Param<bool> simulate_stalls; + +END_DECLARE_SIM_OBJECT_PARAMS(AtomicSimpleCPU) + +BEGIN_INIT_SIM_OBJECT_PARAMS(AtomicSimpleCPU) + + INIT_PARAM(max_insts_any_thread, + "terminate when any thread reaches this inst count"), + INIT_PARAM(max_insts_all_threads, + "terminate when all threads have reached this inst count"), + INIT_PARAM(max_loads_any_thread, + "terminate when any thread reaches this load count"), + INIT_PARAM(max_loads_all_threads, + "terminate when all threads have reached this load count"), + INIT_PARAM(mem, "memory"), + +#if FULL_SYSTEM + INIT_PARAM(itb, "Instruction TLB"), + INIT_PARAM(dtb, "Data TLB"), + INIT_PARAM(system, "system object"), + INIT_PARAM(cpu_id, "processor ID"), + INIT_PARAM(profile, ""), +#else + INIT_PARAM(workload, "processes to run"), +#endif // FULL_SYSTEM + + INIT_PARAM(clock, "clock speed"), + INIT_PARAM(defer_registration, "defer system registration (for sampling)"), + INIT_PARAM(width, "cpu width"), + INIT_PARAM(function_trace, "Enable function trace"), + INIT_PARAM(function_trace_start, "Cycle to start function trace"), + INIT_PARAM(simulate_stalls, "Simulate cache stall cycles") + +END_INIT_SIM_OBJECT_PARAMS(AtomicSimpleCPU) + + +CREATE_SIM_OBJECT(AtomicSimpleCPU) +{ + AtomicSimpleCPU::Params *params = new AtomicSimpleCPU::Params(); + params->name = getInstanceName(); + params->numberOfThreads = 1; + params->max_insts_any_thread = max_insts_any_thread; + params->max_insts_all_threads = max_insts_all_threads; + params->max_loads_any_thread = max_loads_any_thread; + params->max_loads_all_threads = max_loads_all_threads; + params->deferRegistration = defer_registration; + params->clock = clock; + params->functionTrace = function_trace; + params->functionTraceStart = function_trace_start; + params->width = width; + params->simulate_stalls = simulate_stalls; + params->mem = mem; + +#if FULL_SYSTEM + params->itb = itb; + params->dtb = dtb; + params->system = system; + params->cpu_id = cpu_id; + params->profile = profile; +#else + params->process = workload; +#endif + + AtomicSimpleCPU *cpu = new AtomicSimpleCPU(params); + return cpu; +} + +REGISTER_SIM_OBJECT("AtomicSimpleCPU", AtomicSimpleCPU) + diff --git a/src/cpu/simple/atomic.hh b/src/cpu/simple/atomic.hh new file mode 100644 index 000000000..ab3a3e8ef --- /dev/null +++ b/src/cpu/simple/atomic.hh @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __CPU_SIMPLE_ATOMIC_HH__ +#define __CPU_SIMPLE_ATOMIC_HH__ + +#include "cpu/simple/base.hh" + +class AtomicSimpleCPU : public BaseSimpleCPU +{ + public: + + struct Params : public BaseSimpleCPU::Params { + int width; + bool simulate_stalls; + }; + + AtomicSimpleCPU(Params *params); + virtual ~AtomicSimpleCPU(); + + virtual void init(); + + public: + // + enum Status { + Running, + Idle, + SwitchedOut + }; + + protected: + Status _status; + + Status status() const { return _status; } + + private: + + struct TickEvent : public Event + { + AtomicSimpleCPU *cpu; + + TickEvent(AtomicSimpleCPU *c); + void process(); + const char *description(); + }; + + TickEvent tickEvent; + + const int width; + const bool simulate_stalls; + + // main simulation loop (one cycle) + void tick(); + + class CpuPort : public Port + { + + AtomicSimpleCPU *cpu; + + public: + + CpuPort(const std::string &_name, AtomicSimpleCPU *_cpu) + : Port(_name), cpu(_cpu) + { } + + protected: + + virtual bool recvTiming(Packet *pkt); + + virtual Tick recvAtomic(Packet *pkt); + + virtual void recvFunctional(Packet *pkt); + + virtual void recvStatusChange(Status status); + + virtual Packet *recvRetry(); + + virtual void getDeviceAddressRanges(AddrRangeList &resp, + AddrRangeList &snoop) + { resp.clear(); snoop.clear(); } + }; + + CpuPort icachePort; + CpuPort dcachePort; + + Request *ifetch_req; + Packet *ifetch_pkt; + Request *data_read_req; + Packet *data_read_pkt; + Request *data_write_req; + Packet *data_write_pkt; + + bool dcache_access; + Tick dcache_complete; + + public: + + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); + + void switchOut(Sampler *s); + void takeOverFrom(BaseCPU *oldCPU); + + virtual void activateContext(int thread_num, int delay); + virtual void suspendContext(int thread_num); + + template <class T> + Fault read(Addr addr, T &data, unsigned flags); + + template <class T> + Fault write(T data, Addr addr, unsigned flags, uint64_t *res); +}; + +#endif // __CPU_SIMPLE_ATOMIC_HH__ diff --git a/src/cpu/simple/base.cc b/src/cpu/simple/base.cc new file mode 100644 index 000000000..18f170449 --- /dev/null +++ b/src/cpu/simple/base.cc @@ -0,0 +1,482 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "arch/utility.hh" +#include "base/cprintf.hh" +#include "base/inifile.hh" +#include "base/loader/symtab.hh" +#include "base/misc.hh" +#include "base/pollevent.hh" +#include "base/range.hh" +#include "base/stats/events.hh" +#include "base/trace.hh" +#include "cpu/base.hh" +#include "cpu/cpu_exec_context.hh" +#include "cpu/exec_context.hh" +#include "cpu/exetrace.hh" +#include "cpu/profile.hh" +#include "cpu/sampler/sampler.hh" +#include "cpu/simple/base.hh" +#include "cpu/smt.hh" +#include "cpu/static_inst.hh" +#include "kern/kernel_stats.hh" +#include "mem/packet_impl.hh" +#include "sim/byteswap.hh" +#include "sim/builder.hh" +#include "sim/debug.hh" +#include "sim/host.hh" +#include "sim/sim_events.hh" +#include "sim/sim_object.hh" +#include "sim/stats.hh" + +#if FULL_SYSTEM +#include "base/remote_gdb.hh" +#include "sim/system.hh" +#include "arch/tlb.hh" +#include "arch/stacktrace.hh" +#include "arch/vtophys.hh" +#else // !FULL_SYSTEM +#include "mem/mem_object.hh" +#endif // FULL_SYSTEM + +using namespace std; +using namespace TheISA; + +BaseSimpleCPU::BaseSimpleCPU(Params *p) + : BaseCPU(p), mem(p->mem), cpuXC(NULL) +{ +#if FULL_SYSTEM + cpuXC = new CPUExecContext(this, 0, p->system, p->itb, p->dtb); +#else + cpuXC = new CPUExecContext(this, /* thread_num */ 0, p->process, + /* asid */ 0, mem); +#endif // !FULL_SYSTEM + + xcProxy = cpuXC->getProxy(); + + numInst = 0; + startNumInst = 0; + numLoad = 0; + startNumLoad = 0; + lastIcacheStall = 0; + lastDcacheStall = 0; + + execContexts.push_back(xcProxy); +} + +BaseSimpleCPU::~BaseSimpleCPU() +{ +} + +void +BaseSimpleCPU::deallocateContext(int thread_num) +{ + // for now, these are equivalent + suspendContext(thread_num); +} + + +void +BaseSimpleCPU::haltContext(int thread_num) +{ + // for now, these are equivalent + suspendContext(thread_num); +} + + +void +BaseSimpleCPU::regStats() +{ + using namespace Stats; + + BaseCPU::regStats(); + + numInsts + .name(name() + ".num_insts") + .desc("Number of instructions executed") + ; + + numMemRefs + .name(name() + ".num_refs") + .desc("Number of memory references") + ; + + notIdleFraction + .name(name() + ".not_idle_fraction") + .desc("Percentage of non-idle cycles") + ; + + idleFraction + .name(name() + ".idle_fraction") + .desc("Percentage of idle cycles") + ; + + icacheStallCycles + .name(name() + ".icache_stall_cycles") + .desc("ICache total stall cycles") + .prereq(icacheStallCycles) + ; + + dcacheStallCycles + .name(name() + ".dcache_stall_cycles") + .desc("DCache total stall cycles") + .prereq(dcacheStallCycles) + ; + + icacheRetryCycles + .name(name() + ".icache_retry_cycles") + .desc("ICache total retry cycles") + .prereq(icacheRetryCycles) + ; + + dcacheRetryCycles + .name(name() + ".dcache_retry_cycles") + .desc("DCache total retry cycles") + .prereq(dcacheRetryCycles) + ; + + idleFraction = constant(1.0) - notIdleFraction; +} + +void +BaseSimpleCPU::resetStats() +{ + startNumInst = numInst; + // notIdleFraction = (_status != Idle); +} + +void +BaseSimpleCPU::serialize(ostream &os) +{ + BaseCPU::serialize(os); + SERIALIZE_SCALAR(inst); + nameOut(os, csprintf("%s.xc", name())); + cpuXC->serialize(os); +} + +void +BaseSimpleCPU::unserialize(Checkpoint *cp, const string §ion) +{ + BaseCPU::unserialize(cp, section); + UNSERIALIZE_SCALAR(inst); + cpuXC->unserialize(cp, csprintf("%s.xc", section)); +} + +void +change_thread_state(int thread_number, int activate, int priority) +{ +} + +Fault +BaseSimpleCPU::copySrcTranslate(Addr src) +{ +#if 0 + static bool no_warn = true; + int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; + // Only support block sizes of 64 atm. + assert(blk_size == 64); + int offset = src & (blk_size - 1); + + // Make sure block doesn't span page + if (no_warn && + (src & PageMask) != ((src + blk_size) & PageMask) && + (src >> 40) != 0xfffffc) { + warn("Copied block source spans pages %x.", src); + no_warn = false; + } + + memReq->reset(src & ~(blk_size - 1), blk_size); + + // translate to physical address + Fault fault = cpuXC->translateDataReadReq(req); + + if (fault == NoFault) { + cpuXC->copySrcAddr = src; + cpuXC->copySrcPhysAddr = memReq->paddr + offset; + } else { + assert(!fault->isAlignmentFault()); + + cpuXC->copySrcAddr = 0; + cpuXC->copySrcPhysAddr = 0; + } + return fault; +#else + return NoFault; +#endif +} + +Fault +BaseSimpleCPU::copy(Addr dest) +{ +#if 0 + static bool no_warn = true; + int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; + // Only support block sizes of 64 atm. + assert(blk_size == 64); + uint8_t data[blk_size]; + //assert(cpuXC->copySrcAddr); + int offset = dest & (blk_size - 1); + + // Make sure block doesn't span page + if (no_warn && + (dest & PageMask) != ((dest + blk_size) & PageMask) && + (dest >> 40) != 0xfffffc) { + no_warn = false; + warn("Copied block destination spans pages %x. ", dest); + } + + memReq->reset(dest & ~(blk_size -1), blk_size); + // translate to physical address + Fault fault = cpuXC->translateDataWriteReq(req); + + if (fault == NoFault) { + Addr dest_addr = memReq->paddr + offset; + // Need to read straight from memory since we have more than 8 bytes. + memReq->paddr = cpuXC->copySrcPhysAddr; + cpuXC->mem->read(memReq, data); + memReq->paddr = dest_addr; + cpuXC->mem->write(memReq, data); + if (dcacheInterface) { + memReq->cmd = Copy; + memReq->completionEvent = NULL; + memReq->paddr = cpuXC->copySrcPhysAddr; + memReq->dest = dest_addr; + memReq->size = 64; + memReq->time = curTick; + memReq->flags &= ~INST_READ; + dcacheInterface->access(memReq); + } + } + else + assert(!fault->isAlignmentFault()); + + return fault; +#else + panic("copy not implemented"); + return NoFault; +#endif +} + +#if FULL_SYSTEM +Addr +BaseSimpleCPU::dbg_vtophys(Addr addr) +{ + return vtophys(xcProxy, addr); +} +#endif // FULL_SYSTEM + +#if FULL_SYSTEM +void +BaseSimpleCPU::post_interrupt(int int_num, int index) +{ + BaseCPU::post_interrupt(int_num, index); + + if (cpuXC->status() == ExecContext::Suspended) { + DPRINTF(IPI,"Suspended Processor awoke\n"); + cpuXC->activate(); + } +} +#endif // FULL_SYSTEM + +void +BaseSimpleCPU::checkForInterrupts() +{ +#if FULL_SYSTEM + if (checkInterrupts && check_interrupts() && !cpuXC->inPalMode()) { + int ipl = 0; + int summary = 0; + checkInterrupts = false; + + if (cpuXC->readMiscReg(IPR_SIRR)) { + for (int i = INTLEVEL_SOFTWARE_MIN; + i < INTLEVEL_SOFTWARE_MAX; i++) { + if (cpuXC->readMiscReg(IPR_SIRR) & (ULL(1) << i)) { + // See table 4-19 of 21164 hardware reference + ipl = (i - INTLEVEL_SOFTWARE_MIN) + 1; + summary |= (ULL(1) << i); + } + } + } + + uint64_t interrupts = cpuXC->cpu->intr_status(); + for (int i = INTLEVEL_EXTERNAL_MIN; + i < INTLEVEL_EXTERNAL_MAX; i++) { + if (interrupts & (ULL(1) << i)) { + // See table 4-19 of 21164 hardware reference + ipl = i; + summary |= (ULL(1) << i); + } + } + + if (cpuXC->readMiscReg(IPR_ASTRR)) + panic("asynchronous traps not implemented\n"); + + if (ipl && ipl > cpuXC->readMiscReg(IPR_IPLR)) { + cpuXC->setMiscReg(IPR_ISR, summary); + cpuXC->setMiscReg(IPR_INTID, ipl); + + Fault(new InterruptFault)->invoke(xcProxy); + + DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n", + cpuXC->readMiscReg(IPR_IPLR), ipl, summary); + } + } +#endif +} + + +Fault +BaseSimpleCPU::setupFetchPacket(Packet *ifetch_pkt) +{ + // Try to fetch an instruction + + // set up memory request for instruction fetch + + DPRINTF(Fetch,"Fetch: PC:%08p NPC:%08p NNPC:%08p\n",cpuXC->readPC(), + cpuXC->readNextPC(),cpuXC->readNextNPC()); + + Request *ifetch_req = ifetch_pkt->req; + ifetch_req->setVaddr(cpuXC->readPC() & ~3); + ifetch_req->setTime(curTick); +#if FULL_SYSTEM + ifetch_req->setFlags((cpuXC->readPC() & 1) ? PHYSICAL : 0); +#else + ifetch_req->setFlags(0); +#endif + + Fault fault = cpuXC->translateInstReq(ifetch_req); + + if (fault == NoFault) { + ifetch_pkt->reinitFromRequest(); + } + + return fault; +} + + +void +BaseSimpleCPU::preExecute() +{ + // maintain $r0 semantics + cpuXC->setIntReg(ZeroReg, 0); +#if THE_ISA == ALPHA_ISA + cpuXC->setFloatReg(ZeroReg, 0.0); +#endif // ALPHA_ISA + + // keep an instruction count + numInst++; + numInsts++; + + cpuXC->func_exe_inst++; + + // check for instruction-count-based events + comInstEventQueue[0]->serviceEvents(numInst); + + // decode the instruction + inst = gtoh(inst); + curStaticInst = StaticInst::decode(makeExtMI(inst, cpuXC->readPC())); + + traceData = Trace::getInstRecord(curTick, xcProxy, this, curStaticInst, + cpuXC->readPC()); + + DPRINTF(Decode,"Decode: Decoded %s instruction (opcode: 0x%x): 0x%x\n", + curStaticInst->getName(), curStaticInst->getOpcode(), + curStaticInst->machInst); + +#if FULL_SYSTEM + cpuXC->setInst(inst); +#endif // FULL_SYSTEM +} + +void +BaseSimpleCPU::postExecute() +{ +#if FULL_SYSTEM + if (system->kernelBinning->fnbin) { + assert(kernelStats); + system->kernelBinning->execute(xcProxy, inst); + } + + if (cpuXC->profile) { + bool usermode = + (cpuXC->readMiscReg(AlphaISA::IPR_DTB_CM) & 0x18) != 0; + cpuXC->profilePC = usermode ? 1 : cpuXC->readPC(); + ProfileNode *node = cpuXC->profile->consume(xcProxy, inst); + if (node) + cpuXC->profileNode = node; + } +#endif + + if (curStaticInst->isMemRef()) { + numMemRefs++; + } + + if (curStaticInst->isLoad()) { + ++numLoad; + comLoadEventQueue[0]->serviceEvents(numLoad); + } + + traceFunctions(cpuXC->readPC()); + + if (traceData) { + traceData->finalize(); + } +} + + +void +BaseSimpleCPU::advancePC(Fault fault) +{ + if (fault != NoFault) { +#if FULL_SYSTEM + fault->invoke(xcProxy); +#else // !FULL_SYSTEM + fatal("fault (%s) detected @ PC %08p", fault->name(), cpuXC->readPC()); +#endif // FULL_SYSTEM + } + else { + // go to the next instruction + cpuXC->setPC(cpuXC->readNextPC()); +#if THE_ISA == ALPHA_ISA + cpuXC->setNextPC(cpuXC->readNextPC() + sizeof(MachInst)); +#else + cpuXC->setNextPC(cpuXC->readNextNPC()); + cpuXC->setNextNPC(cpuXC->readNextNPC() + sizeof(MachInst)); +#endif + + } + +#if FULL_SYSTEM + Addr oldpc; + do { + oldpc = cpuXC->readPC(); + system->pcEventQueue.service(xcProxy); + } while (oldpc != cpuXC->readPC()); +#endif +} + diff --git a/src/cpu/simple/base.hh b/src/cpu/simple/base.hh new file mode 100644 index 000000000..4c0e6f3c7 --- /dev/null +++ b/src/cpu/simple/base.hh @@ -0,0 +1,316 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __CPU_SIMPLE_BASE_HH__ +#define __CPU_SIMPLE_BASE_HH__ + +#include "base/statistics.hh" +#include "config/full_system.hh" +#include "cpu/base.hh" +#include "cpu/cpu_exec_context.hh" +#include "cpu/pc_event.hh" +#include "cpu/sampler/sampler.hh" +#include "cpu/static_inst.hh" +#include "mem/packet.hh" +#include "mem/port.hh" +#include "mem/request.hh" +#include "sim/eventq.hh" + +// forward declarations +#if FULL_SYSTEM +class Processor; +class AlphaITB; +class AlphaDTB; +class MemObject; + +class RemoteGDB; +class GDBListener; + +#else + +class Process; + +#endif // FULL_SYSTEM + +class ExecContext; +class Checkpoint; + +namespace Trace { + class InstRecord; +} + + +class BaseSimpleCPU : public BaseCPU +{ + protected: + typedef TheISA::MachInst MachInst; + typedef TheISA::MiscReg MiscReg; + typedef TheISA::FloatReg FloatReg; + typedef TheISA::FloatRegBits FloatRegBits; + + MemObject *mem; + + protected: + Trace::InstRecord *traceData; + + public: + void post_interrupt(int int_num, int index); + + void zero_fill_64(Addr addr) { + static int warned = 0; + if (!warned) { + warn ("WH64 is not implemented"); + warned = 1; + } + }; + + public: + struct Params : public BaseCPU::Params + { + MemObject *mem; +#if FULL_SYSTEM + AlphaITB *itb; + AlphaDTB *dtb; +#else + Process *process; +#endif + }; + BaseSimpleCPU(Params *params); + virtual ~BaseSimpleCPU(); + + public: + // execution context + CPUExecContext *cpuXC; + + ExecContext *xcProxy; + +#if FULL_SYSTEM + Addr dbg_vtophys(Addr addr); + + bool interval_stats; +#endif + + // current instruction + MachInst inst; + + // Static data storage + TheISA::IntReg dataReg; + + // Pointer to the sampler that is telling us to switchover. + // Used to signal the completion of the pipe drain and schedule + // the next switchover + Sampler *sampler; + + StaticInstPtr curStaticInst; + + void checkForInterrupts(); + Fault setupFetchPacket(Packet *ifetch_pkt); + void preExecute(); + void postExecute(); + void advancePC(Fault fault); + + virtual void deallocateContext(int thread_num); + virtual void haltContext(int thread_num); + + // statistics + virtual void regStats(); + virtual void resetStats(); + + // number of simulated instructions + Counter numInst; + Counter startNumInst; + Stats::Scalar<> numInsts; + + virtual Counter totalInstructions() const + { + return numInst - startNumInst; + } + + // number of simulated memory references + Stats::Scalar<> numMemRefs; + + // number of simulated loads + Counter numLoad; + Counter startNumLoad; + + // number of idle cycles + Stats::Average<> notIdleFraction; + Stats::Formula idleFraction; + + // number of cycles stalled for I-cache responses + Stats::Scalar<> icacheStallCycles; + Counter lastIcacheStall; + + // number of cycles stalled for I-cache retries + Stats::Scalar<> icacheRetryCycles; + Counter lastIcacheRetry; + + // number of cycles stalled for D-cache responses + Stats::Scalar<> dcacheStallCycles; + Counter lastDcacheStall; + + // number of cycles stalled for D-cache retries + Stats::Scalar<> dcacheRetryCycles; + Counter lastDcacheRetry; + + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); + + // These functions are only used in CPU models that split + // effective address computation from the actual memory access. + void setEA(Addr EA) { panic("BaseSimpleCPU::setEA() not implemented\n"); } + Addr getEA() { panic("BaseSimpleCPU::getEA() not implemented\n"); } + + void prefetch(Addr addr, unsigned flags) + { + // need to do this... + } + + void writeHint(Addr addr, int size, unsigned flags) + { + // need to do this... + } + + Fault copySrcTranslate(Addr src); + + Fault copy(Addr dest); + + // The register accessor methods provide the index of the + // instruction's operand (e.g., 0 or 1), not the architectural + // register index, to simplify the implementation of register + // renaming. We find the architectural register index by indexing + // into the instruction's own operand index table. Note that a + // raw pointer to the StaticInst is provided instead of a + // ref-counted StaticInstPtr to redice overhead. This is fine as + // long as these methods don't copy the pointer into any long-term + // storage (which is pretty hard to imagine they would have reason + // to do). + + uint64_t readIntReg(const StaticInst *si, int idx) + { + return cpuXC->readIntReg(si->srcRegIdx(idx)); + } + + FloatReg readFloatReg(const StaticInst *si, int idx, int width) + { + int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag; + return cpuXC->readFloatReg(reg_idx, width); + } + + FloatReg readFloatReg(const StaticInst *si, int idx) + { + int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag; + return cpuXC->readFloatReg(reg_idx); + } + + FloatRegBits readFloatRegBits(const StaticInst *si, int idx, int width) + { + int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag; + return cpuXC->readFloatRegBits(reg_idx, width); + } + + FloatRegBits readFloatRegBits(const StaticInst *si, int idx) + { + int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag; + return cpuXC->readFloatRegBits(reg_idx); + } + + void setIntReg(const StaticInst *si, int idx, uint64_t val) + { + cpuXC->setIntReg(si->destRegIdx(idx), val); + } + + void setFloatReg(const StaticInst *si, int idx, FloatReg val, int width) + { + int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag; + cpuXC->setFloatReg(reg_idx, val, width); + } + + void setFloatReg(const StaticInst *si, int idx, FloatReg val) + { + int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag; + cpuXC->setFloatReg(reg_idx, val); + } + + void setFloatRegBits(const StaticInst *si, int idx, + FloatRegBits val, int width) + { + int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag; + cpuXC->setFloatRegBits(reg_idx, val, width); + } + + void setFloatRegBits(const StaticInst *si, int idx, FloatRegBits val) + { + int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag; + cpuXC->setFloatRegBits(reg_idx, val); + } + + uint64_t readPC() { return cpuXC->readPC(); } + uint64_t readNextPC() { return cpuXC->readNextPC(); } + uint64_t readNextNPC() { return cpuXC->readNextNPC(); } + + void setPC(uint64_t val) { cpuXC->setPC(val); } + void setNextPC(uint64_t val) { cpuXC->setNextPC(val); } + void setNextNPC(uint64_t val) { cpuXC->setNextNPC(val); } + + MiscReg readMiscReg(int misc_reg) + { + return cpuXC->readMiscReg(misc_reg); + } + + MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault) + { + return cpuXC->readMiscRegWithEffect(misc_reg, fault); + } + + Fault setMiscReg(int misc_reg, const MiscReg &val) + { + return cpuXC->setMiscReg(misc_reg, val); + } + + Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val) + { + return cpuXC->setMiscRegWithEffect(misc_reg, val); + } + +#if FULL_SYSTEM + Fault hwrei() { return cpuXC->hwrei(); } + int readIntrFlag() { return cpuXC->readIntrFlag(); } + void setIntrFlag(int val) { cpuXC->setIntrFlag(val); } + bool inPalMode() { return cpuXC->inPalMode(); } + void ev5_trap(Fault fault) { fault->invoke(xcProxy); } + bool simPalCheck(int palFunc) { return cpuXC->simPalCheck(palFunc); } +#else + void syscall(int64_t callnum) { cpuXC->syscall(callnum); } +#endif + + bool misspeculating() { return cpuXC->misspeculating(); } + ExecContext *xcBase() { return xcProxy; } +}; + +#endif // __CPU_SIMPLE_BASE_HH__ diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc new file mode 100644 index 000000000..7cdcdafa1 --- /dev/null +++ b/src/cpu/simple/timing.cc @@ -0,0 +1,570 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "arch/utility.hh" +#include "cpu/exetrace.hh" +#include "cpu/simple/timing.hh" +#include "mem/packet_impl.hh" +#include "sim/builder.hh" + +using namespace std; +using namespace TheISA; + + +void +TimingSimpleCPU::init() +{ + //Create Memory Ports (conect them up) + Port *mem_dport = mem->getPort(""); + dcachePort.setPeer(mem_dport); + mem_dport->setPeer(&dcachePort); + + Port *mem_iport = mem->getPort(""); + icachePort.setPeer(mem_iport); + mem_iport->setPeer(&icachePort); + + BaseCPU::init(); +#if FULL_SYSTEM + for (int i = 0; i < execContexts.size(); ++i) { + ExecContext *xc = execContexts[i]; + + // initialize CPU, including PC + TheISA::initCPU(xc, xc->readCpuId()); + } +#endif +} + +Tick +TimingSimpleCPU::CpuPort::recvAtomic(Packet *pkt) +{ + panic("TimingSimpleCPU doesn't expect recvAtomic callback!"); + return curTick; +} + +void +TimingSimpleCPU::CpuPort::recvFunctional(Packet *pkt) +{ + panic("TimingSimpleCPU doesn't expect recvFunctional callback!"); +} + +void +TimingSimpleCPU::CpuPort::recvStatusChange(Status status) +{ + if (status == RangeChange) + return; + + panic("TimingSimpleCPU doesn't expect recvStatusChange callback!"); +} + +TimingSimpleCPU::TimingSimpleCPU(Params *p) + : BaseSimpleCPU(p), icachePort(this), dcachePort(this) +{ + _status = Idle; + ifetch_pkt = dcache_pkt = NULL; +} + + +TimingSimpleCPU::~TimingSimpleCPU() +{ +} + +void +TimingSimpleCPU::serialize(ostream &os) +{ + BaseSimpleCPU::serialize(os); + SERIALIZE_ENUM(_status); +} + +void +TimingSimpleCPU::unserialize(Checkpoint *cp, const string §ion) +{ + BaseSimpleCPU::unserialize(cp, section); + UNSERIALIZE_ENUM(_status); +} + +void +TimingSimpleCPU::switchOut(Sampler *s) +{ + sampler = s; + if (status() == Running) { + _status = SwitchedOut; + } + sampler->signalSwitched(); +} + + +void +TimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU) +{ + BaseCPU::takeOverFrom(oldCPU); + + // if any of this CPU's ExecContexts are active, mark the CPU as + // running and schedule its tick event. + for (int i = 0; i < execContexts.size(); ++i) { + ExecContext *xc = execContexts[i]; + if (xc->status() == ExecContext::Active && _status != Running) { + _status = Running; + break; + } + } +} + + +void +TimingSimpleCPU::activateContext(int thread_num, int delay) +{ + assert(thread_num == 0); + assert(cpuXC); + + assert(_status == Idle); + + notIdleFraction++; + _status = Running; + // kick things off by initiating the fetch of the next instruction + Event *e = + new EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch>(this, true); + e->schedule(curTick + cycles(delay)); +} + + +void +TimingSimpleCPU::suspendContext(int thread_num) +{ + assert(thread_num == 0); + assert(cpuXC); + + assert(_status == Running); + + // just change status to Idle... if status != Running, + // completeInst() will not initiate fetch of next instruction. + + notIdleFraction--; + _status = Idle; +} + + +template <class T> +Fault +TimingSimpleCPU::read(Addr addr, T &data, unsigned flags) +{ + Request *data_read_req = new Request(true); + + data_read_req->setVaddr(addr); + data_read_req->setSize(sizeof(T)); + data_read_req->setFlags(flags); + data_read_req->setTime(curTick); + + if (traceData) { + traceData->setAddr(data_read_req->getVaddr()); + } + + // translate to physical address + Fault fault = cpuXC->translateDataReadReq(data_read_req); + + // Now do the access. + if (fault == NoFault) { + Packet *data_read_pkt = + new Packet(data_read_req, Packet::ReadReq, Packet::Broadcast); + data_read_pkt->dataDynamic<T>(new T); + + if (!dcachePort.sendTiming(data_read_pkt)) { + _status = DcacheRetry; + dcache_pkt = data_read_pkt; + } else { + _status = DcacheWaitResponse; + dcache_pkt = NULL; + } + } + + // This will need a new way to tell if it has a dcache attached. + if (data_read_req->getFlags() & UNCACHEABLE) + recordEvent("Uncached Read"); + + return fault; +} + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +template +Fault +TimingSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags); + +template +Fault +TimingSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags); + +template +Fault +TimingSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags); + +template +Fault +TimingSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags); + +#endif //DOXYGEN_SHOULD_SKIP_THIS + +template<> +Fault +TimingSimpleCPU::read(Addr addr, double &data, unsigned flags) +{ + return read(addr, *(uint64_t*)&data, flags); +} + +template<> +Fault +TimingSimpleCPU::read(Addr addr, float &data, unsigned flags) +{ + return read(addr, *(uint32_t*)&data, flags); +} + + +template<> +Fault +TimingSimpleCPU::read(Addr addr, int32_t &data, unsigned flags) +{ + return read(addr, (uint32_t&)data, flags); +} + + +template <class T> +Fault +TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) +{ + Request *data_write_req = new Request(true); + data_write_req->setVaddr(addr); + data_write_req->setTime(curTick); + data_write_req->setSize(sizeof(T)); + data_write_req->setFlags(flags); + + // translate to physical address + Fault fault = cpuXC->translateDataWriteReq(data_write_req); + // Now do the access. + if (fault == NoFault) { + Packet *data_write_pkt = + new Packet(data_write_req, Packet::WriteReq, Packet::Broadcast); + data_write_pkt->allocate(); + data_write_pkt->set(data); + + if (!dcachePort.sendTiming(data_write_pkt)) { + _status = DcacheRetry; + dcache_pkt = data_write_pkt; + } else { + _status = DcacheWaitResponse; + dcache_pkt = NULL; + } + } + + // This will need a new way to tell if it's hooked up to a cache or not. + if (data_write_req->getFlags() & UNCACHEABLE) + recordEvent("Uncached Write"); + + // If the write needs to have a fault on the access, consider calling + // changeStatus() and changing it to "bad addr write" or something. + return fault; +} + + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +template +Fault +TimingSimpleCPU::write(uint64_t data, Addr addr, + unsigned flags, uint64_t *res); + +template +Fault +TimingSimpleCPU::write(uint32_t data, Addr addr, + unsigned flags, uint64_t *res); + +template +Fault +TimingSimpleCPU::write(uint16_t data, Addr addr, + unsigned flags, uint64_t *res); + +template +Fault +TimingSimpleCPU::write(uint8_t data, Addr addr, + unsigned flags, uint64_t *res); + +#endif //DOXYGEN_SHOULD_SKIP_THIS + +template<> +Fault +TimingSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) +{ + return write(*(uint64_t*)&data, addr, flags, res); +} + +template<> +Fault +TimingSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) +{ + return write(*(uint32_t*)&data, addr, flags, res); +} + + +template<> +Fault +TimingSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) +{ + return write((uint32_t)data, addr, flags, res); +} + + +void +TimingSimpleCPU::fetch() +{ + checkForInterrupts(); + + Request *ifetch_req = new Request(true); + ifetch_req->setSize(sizeof(MachInst)); + + ifetch_pkt = new Packet(ifetch_req, Packet::ReadReq, Packet::Broadcast); + ifetch_pkt->dataStatic(&inst); + + Fault fault = setupFetchPacket(ifetch_pkt); + if (fault == NoFault) { + if (!icachePort.sendTiming(ifetch_pkt)) { + // Need to wait for retry + _status = IcacheRetry; + } else { + // Need to wait for cache to respond + _status = IcacheWaitResponse; + // ownership of packet transferred to memory system + ifetch_pkt = NULL; + } + } else { + // fetch fault: advance directly to next instruction (fault handler) + advanceInst(fault); + } +} + + +void +TimingSimpleCPU::advanceInst(Fault fault) +{ + advancePC(fault); + + if (_status == Running) { + // kick off fetch of next instruction... callback from icache + // response will cause that instruction to be executed, + // keeping the CPU running. + fetch(); + } +} + + +void +TimingSimpleCPU::completeIfetch(Packet *pkt) +{ + // received a response from the icache: execute the received + // instruction + assert(pkt->result == Packet::Success); + assert(_status == IcacheWaitResponse); + _status = Running; + + delete pkt->req; + delete pkt; + + preExecute(); + if (curStaticInst->isMemRef() && !curStaticInst->isDataPrefetch()) { + // load or store: just send to dcache + Fault fault = curStaticInst->initiateAcc(this, traceData); + if (fault == NoFault) { + // successfully initiated access: instruction will + // complete in dcache response callback + assert(_status == DcacheWaitResponse); + } else { + // fault: complete now to invoke fault handler + postExecute(); + advanceInst(fault); + } + } else { + // non-memory instruction: execute completely now + Fault fault = curStaticInst->execute(this, traceData); + postExecute(); + advanceInst(fault); + } +} + + +bool +TimingSimpleCPU::IcachePort::recvTiming(Packet *pkt) +{ + cpu->completeIfetch(pkt); + return true; +} + +Packet * +TimingSimpleCPU::IcachePort::recvRetry() +{ + // we shouldn't get a retry unless we have a packet that we're + // waiting to transmit + assert(cpu->ifetch_pkt != NULL); + assert(cpu->_status == IcacheRetry); + cpu->_status = IcacheWaitResponse; + Packet *tmp = cpu->ifetch_pkt; + cpu->ifetch_pkt = NULL; + return tmp; +} + +void +TimingSimpleCPU::completeDataAccess(Packet *pkt) +{ + // received a response from the dcache: complete the load or store + // instruction + assert(pkt->result == Packet::Success); + assert(_status == DcacheWaitResponse); + _status = Running; + + Fault fault = curStaticInst->completeAcc(pkt, this, traceData); + + delete pkt->req; + delete pkt; + + postExecute(); + advanceInst(fault); +} + + + +bool +TimingSimpleCPU::DcachePort::recvTiming(Packet *pkt) +{ + cpu->completeDataAccess(pkt); + return true; +} + +Packet * +TimingSimpleCPU::DcachePort::recvRetry() +{ + // we shouldn't get a retry unless we have a packet that we're + // waiting to transmit + assert(cpu->dcache_pkt != NULL); + assert(cpu->_status == DcacheRetry); + cpu->_status = DcacheWaitResponse; + Packet *tmp = cpu->dcache_pkt; + cpu->dcache_pkt = NULL; + return tmp; +} + + +//////////////////////////////////////////////////////////////////////// +// +// TimingSimpleCPU Simulation Object +// +BEGIN_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU) + + Param<Counter> max_insts_any_thread; + Param<Counter> max_insts_all_threads; + Param<Counter> max_loads_any_thread; + Param<Counter> max_loads_all_threads; + SimObjectParam<MemObject *> mem; + +#if FULL_SYSTEM + SimObjectParam<AlphaITB *> itb; + SimObjectParam<AlphaDTB *> dtb; + SimObjectParam<System *> system; + Param<int> cpu_id; + Param<Tick> profile; +#else + SimObjectParam<Process *> workload; +#endif // FULL_SYSTEM + + Param<int> clock; + + Param<bool> defer_registration; + Param<int> width; + Param<bool> function_trace; + Param<Tick> function_trace_start; + Param<bool> simulate_stalls; + +END_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU) + +BEGIN_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU) + + INIT_PARAM(max_insts_any_thread, + "terminate when any thread reaches this inst count"), + INIT_PARAM(max_insts_all_threads, + "terminate when all threads have reached this inst count"), + INIT_PARAM(max_loads_any_thread, + "terminate when any thread reaches this load count"), + INIT_PARAM(max_loads_all_threads, + "terminate when all threads have reached this load count"), + INIT_PARAM(mem, "memory"), + +#if FULL_SYSTEM + INIT_PARAM(itb, "Instruction TLB"), + INIT_PARAM(dtb, "Data TLB"), + INIT_PARAM(system, "system object"), + INIT_PARAM(cpu_id, "processor ID"), + INIT_PARAM(profile, ""), +#else + INIT_PARAM(workload, "processes to run"), +#endif // FULL_SYSTEM + + INIT_PARAM(clock, "clock speed"), + INIT_PARAM(defer_registration, "defer system registration (for sampling)"), + INIT_PARAM(width, "cpu width"), + INIT_PARAM(function_trace, "Enable function trace"), + INIT_PARAM(function_trace_start, "Cycle to start function trace"), + INIT_PARAM(simulate_stalls, "Simulate cache stall cycles") + +END_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU) + + +CREATE_SIM_OBJECT(TimingSimpleCPU) +{ + TimingSimpleCPU::Params *params = new TimingSimpleCPU::Params(); + params->name = getInstanceName(); + params->numberOfThreads = 1; + params->max_insts_any_thread = max_insts_any_thread; + params->max_insts_all_threads = max_insts_all_threads; + params->max_loads_any_thread = max_loads_any_thread; + params->max_loads_all_threads = max_loads_all_threads; + params->deferRegistration = defer_registration; + params->clock = clock; + params->functionTrace = function_trace; + params->functionTraceStart = function_trace_start; + params->mem = mem; + +#if FULL_SYSTEM + params->itb = itb; + params->dtb = dtb; + params->system = system; + params->cpu_id = cpu_id; + params->profile = profile; +#else + params->process = workload; +#endif + + TimingSimpleCPU *cpu = new TimingSimpleCPU(params); + return cpu; +} + +REGISTER_SIM_OBJECT("TimingSimpleCPU", TimingSimpleCPU) + diff --git a/src/cpu/simple/timing.hh b/src/cpu/simple/timing.hh new file mode 100644 index 000000000..b46631d5a --- /dev/null +++ b/src/cpu/simple/timing.hh @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __CPU_SIMPLE_TIMING_HH__ +#define __CPU_SIMPLE_TIMING_HH__ + +#include "cpu/simple/base.hh" + +class TimingSimpleCPU : public BaseSimpleCPU +{ + public: + + struct Params : public BaseSimpleCPU::Params { + }; + + TimingSimpleCPU(Params *params); + virtual ~TimingSimpleCPU(); + + virtual void init(); + + public: + // + enum Status { + Idle, + Running, + IcacheRetry, + IcacheWaitResponse, + IcacheWaitSwitch, + DcacheRetry, + DcacheWaitResponse, + DcacheWaitSwitch, + SwitchedOut + }; + + protected: + Status _status; + + Status status() const { return _status; } + + private: + + class CpuPort : public Port + { + protected: + TimingSimpleCPU *cpu; + + public: + + CpuPort(const std::string &_name, TimingSimpleCPU *_cpu) + : Port(_name), cpu(_cpu) + { } + + protected: + + virtual Tick recvAtomic(Packet *pkt); + + virtual void recvFunctional(Packet *pkt); + + virtual void recvStatusChange(Status status); + + virtual void getDeviceAddressRanges(AddrRangeList &resp, + AddrRangeList &snoop) + { resp.clear(); snoop.clear(); } + }; + + class IcachePort : public CpuPort + { + public: + + IcachePort(TimingSimpleCPU *_cpu) + : CpuPort(_cpu->name() + "-iport", _cpu) + { } + + protected: + + virtual bool recvTiming(Packet *pkt); + + virtual Packet *recvRetry(); + }; + + class DcachePort : public CpuPort + { + public: + + DcachePort(TimingSimpleCPU *_cpu) + : CpuPort(_cpu->name() + "-dport", _cpu) + { } + + protected: + + virtual bool recvTiming(Packet *pkt); + + virtual Packet *recvRetry(); + }; + + IcachePort icachePort; + DcachePort dcachePort; + + Packet *ifetch_pkt; + Packet *dcache_pkt; + + public: + + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); + + void switchOut(Sampler *s); + void takeOverFrom(BaseCPU *oldCPU); + + virtual void activateContext(int thread_num, int delay); + virtual void suspendContext(int thread_num); + + template <class T> + Fault read(Addr addr, T &data, unsigned flags); + + template <class T> + Fault write(T data, Addr addr, unsigned flags, uint64_t *res); + + void fetch(); + void completeIfetch(Packet *); + void completeDataAccess(Packet *); + void advanceInst(Fault fault); +}; + +#endif // __CPU_SIMPLE_TIMING_HH__ diff --git a/cpu/smt.hh b/src/cpu/smt.hh index 9c52abf95..9c52abf95 100644 --- a/cpu/smt.hh +++ b/src/cpu/smt.hh diff --git a/cpu/static_inst.cc b/src/cpu/static_inst.cc index c307dc6fc..c307dc6fc 100644 --- a/cpu/static_inst.cc +++ b/src/cpu/static_inst.cc diff --git a/src/cpu/static_inst.hh b/src/cpu/static_inst.hh new file mode 100644 index 000000000..803b7a09b --- /dev/null +++ b/src/cpu/static_inst.hh @@ -0,0 +1,490 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __CPU_STATIC_INST_HH__ +#define __CPU_STATIC_INST_HH__ + +#include <bitset> +#include <string> + +#include "base/hashmap.hh" +#include "base/misc.hh" +#include "base/refcnt.hh" +#include "cpu/op_class.hh" +#include "sim/host.hh" +#include "arch/isa_traits.hh" + +// forward declarations +struct AlphaSimpleImpl; +struct OzoneImpl; +struct SimpleImpl; +class ExecContext; +class DynInst; +class Packet; + +template <class Impl> +class AlphaDynInst; + +template <class Impl> +class OzoneDynInst; + +class CheckerCPU; +class FastCPU; +class AtomicSimpleCPU; +class TimingSimpleCPU; +class InorderCPU; +class SymbolTable; + +namespace Trace { + class InstRecord; +} + +/** + * Base, ISA-independent static instruction class. + * + * The main component of this class is the vector of flags and the + * associated methods for reading them. Any object that can rely + * solely on these flags can process instructions without being + * recompiled for multiple ISAs. + */ +class StaticInstBase : public RefCounted +{ + protected: + + /// Set of boolean static instruction properties. + /// + /// Notes: + /// - The IsInteger and IsFloating flags are based on the class of + /// registers accessed by the instruction. Although most + /// instructions will have exactly one of these two flags set, it + /// is possible for an instruction to have neither (e.g., direct + /// unconditional branches, memory barriers) or both (e.g., an + /// FP/int conversion). + /// - If IsMemRef is set, then exactly one of IsLoad or IsStore + /// will be set. + /// - If IsControl is set, then exactly one of IsDirectControl or + /// IsIndirect Control will be set, and exactly one of + /// IsCondControl or IsUncondControl will be set. + /// - IsSerializing, IsMemBarrier, and IsWriteBarrier are + /// implemented as flags since in the current model there's no + /// other way for instructions to inject behavior into the + /// pipeline outside of fetch. Once we go to an exec-in-exec CPU + /// model we should be able to get rid of these flags and + /// implement this behavior via the execute() methods. + /// + enum Flags { + IsNop, ///< Is a no-op (no effect at all). + + IsInteger, ///< References integer regs. + IsFloating, ///< References FP regs. + + IsMemRef, ///< References memory (load, store, or prefetch). + IsLoad, ///< Reads from memory (load or prefetch). + IsStore, ///< Writes to memory. + IsStoreConditional, ///< Store conditional instruction. + IsInstPrefetch, ///< Instruction-cache prefetch. + IsDataPrefetch, ///< Data-cache prefetch. + IsCopy, ///< Fast Cache block copy + + IsControl, ///< Control transfer instruction. + IsDirectControl, ///< PC relative control transfer. + IsIndirectControl, ///< Register indirect control transfer. + IsCondControl, ///< Conditional control transfer. + IsUncondControl, ///< Unconditional control transfer. + IsCall, ///< Subroutine call. + IsReturn, ///< Subroutine return. + + IsCondDelaySlot,///< Conditional Delay-Slot Instruction + + IsThreadSync, ///< Thread synchronization operation. + + IsSerializing, ///< Serializes pipeline: won't execute until all + /// older instructions have committed. + IsSerializeBefore, + IsSerializeAfter, + IsMemBarrier, ///< Is a memory barrier + IsWriteBarrier, ///< Is a write barrier + + IsNonSpeculative, ///< Should not be executed speculatively + IsQuiesce, ///< Is a quiesce instruction + + IsIprAccess, ///< Accesses IPRs + IsUnverifiable, ///< Can't be verified by a checker + + NumFlags + }; + + /// Flag values for this instruction. + std::bitset<NumFlags> flags; + + /// See opClass(). + OpClass _opClass; + + /// See numSrcRegs(). + int8_t _numSrcRegs; + + /// See numDestRegs(). + int8_t _numDestRegs; + + /// The following are used to track physical register usage + /// for machines with separate int & FP reg files. + //@{ + int8_t _numFPDestRegs; + int8_t _numIntDestRegs; + //@} + + /// Constructor. + /// It's important to initialize everything here to a sane + /// default, since the decoder generally only overrides + /// the fields that are meaningful for the particular + /// instruction. + StaticInstBase(OpClass __opClass) + : _opClass(__opClass), _numSrcRegs(0), _numDestRegs(0), + _numFPDestRegs(0), _numIntDestRegs(0) + { + } + + public: + + /// @name Register information. + /// The sum of numFPDestRegs() and numIntDestRegs() equals + /// numDestRegs(). The former two functions are used to track + /// physical register usage for machines with separate int & FP + /// reg files. + //@{ + /// Number of source registers. + int8_t numSrcRegs() const { return _numSrcRegs; } + /// Number of destination registers. + int8_t numDestRegs() const { return _numDestRegs; } + /// Number of floating-point destination regs. + int8_t numFPDestRegs() const { return _numFPDestRegs; } + /// Number of integer destination regs. + int8_t numIntDestRegs() const { return _numIntDestRegs; } + //@} + + /// @name Flag accessors. + /// These functions are used to access the values of the various + /// instruction property flags. See StaticInstBase::Flags for descriptions + /// of the individual flags. + //@{ + + bool isNop() const { return flags[IsNop]; } + + bool isMemRef() const { return flags[IsMemRef]; } + bool isLoad() const { return flags[IsLoad]; } + bool isStore() const { return flags[IsStore]; } + bool isStoreConditional() const { return flags[IsStoreConditional]; } + bool isInstPrefetch() const { return flags[IsInstPrefetch]; } + bool isDataPrefetch() const { return flags[IsDataPrefetch]; } + bool isCopy() const { return flags[IsCopy];} + + bool isInteger() const { return flags[IsInteger]; } + bool isFloating() const { return flags[IsFloating]; } + + bool isControl() const { return flags[IsControl]; } + bool isCall() const { return flags[IsCall]; } + bool isReturn() const { return flags[IsReturn]; } + bool isDirectCtrl() const { return flags[IsDirectControl]; } + bool isIndirectCtrl() const { return flags[IsIndirectControl]; } + bool isCondCtrl() const { return flags[IsCondControl]; } + bool isUncondCtrl() const { return flags[IsUncondControl]; } + + bool isThreadSync() const { return flags[IsThreadSync]; } + bool isSerializing() const { return flags[IsSerializing] || + flags[IsSerializeBefore] || + flags[IsSerializeAfter]; } + bool isSerializeBefore() const { return flags[IsSerializeBefore]; } + bool isSerializeAfter() const { return flags[IsSerializeAfter]; } + bool isMemBarrier() const { return flags[IsMemBarrier]; } + bool isWriteBarrier() const { return flags[IsWriteBarrier]; } + bool isNonSpeculative() const { return flags[IsNonSpeculative]; } + bool isQuiesce() const { return flags[IsQuiesce]; } + bool isIprAccess() const { return flags[IsIprAccess]; } + bool isUnverifiable() const { return flags[IsUnverifiable]; } + //@} + + /// Operation class. Used to select appropriate function unit in issue. + OpClass opClass() const { return _opClass; } +}; + + +// forward declaration +class StaticInstPtr; + +/** + * Generic yet ISA-dependent static instruction class. + * + * This class builds on StaticInstBase, defining fields and interfaces + * that are generic across all ISAs but that differ in details + * according to the specific ISA being used. + */ +class StaticInst : public StaticInstBase +{ + public: + + /// Binary machine instruction type. + typedef TheISA::MachInst MachInst; + /// Binary extended machine instruction type. + typedef TheISA::ExtMachInst ExtMachInst; + /// Logical register index type. + typedef TheISA::RegIndex RegIndex; + + enum { + MaxInstSrcRegs = TheISA::MaxInstSrcRegs, //< Max source regs + MaxInstDestRegs = TheISA::MaxInstDestRegs, //< Max dest regs + }; + + + /// Return logical index (architectural reg num) of i'th destination reg. + /// Only the entries from 0 through numDestRegs()-1 are valid. + RegIndex destRegIdx(int i) const { return _destRegIdx[i]; } + + /// Return logical index (architectural reg num) of i'th source reg. + /// Only the entries from 0 through numSrcRegs()-1 are valid. + RegIndex srcRegIdx(int i) const { return _srcRegIdx[i]; } + + /// Pointer to a statically allocated "null" instruction object. + /// Used to give eaCompInst() and memAccInst() something to return + /// when called on non-memory instructions. + static StaticInstPtr nullStaticInstPtr; + + /** + * Memory references only: returns "fake" instruction representing + * the effective address part of the memory operation. Used to + * obtain the dependence info (numSrcRegs and srcRegIdx[]) for + * just the EA computation. + */ + virtual const + StaticInstPtr &eaCompInst() const { return nullStaticInstPtr; } + + /** + * Memory references only: returns "fake" instruction representing + * the memory access part of the memory operation. Used to + * obtain the dependence info (numSrcRegs and srcRegIdx[]) for + * just the memory access (not the EA computation). + */ + virtual const + StaticInstPtr &memAccInst() const { return nullStaticInstPtr; } + + /// The binary machine instruction. + const ExtMachInst machInst; + + protected: + + /// See destRegIdx(). + RegIndex _destRegIdx[MaxInstDestRegs]; + /// See srcRegIdx(). + RegIndex _srcRegIdx[MaxInstSrcRegs]; + + /** + * Base mnemonic (e.g., "add"). Used by generateDisassembly() + * methods. Also useful to readily identify instructions from + * within the debugger when #cachedDisassembly has not been + * initialized. + */ + const char *mnemonic; + + /** + * String representation of disassembly (lazily evaluated via + * disassemble()). + */ + mutable std::string *cachedDisassembly; + + /** + * Internal function to generate disassembly string. + */ + virtual std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const = 0; + + /// Constructor. + StaticInst(const char *_mnemonic, ExtMachInst _machInst, OpClass __opClass) + : StaticInstBase(__opClass), + machInst(_machInst), mnemonic(_mnemonic), cachedDisassembly(0) + { + } + + public: + + virtual ~StaticInst() + { + if (cachedDisassembly) + delete cachedDisassembly; + } + +/** + * The execute() signatures are auto-generated by scons based on the + * set of CPU models we are compiling in today. + */ +#include "cpu/static_inst_exec_sigs.hh" + + /** + * Return the target address for a PC-relative branch. + * Invalid if not a PC-relative branch (i.e. isDirectCtrl() + * should be true). + */ + virtual Addr branchTarget(Addr branchPC) const + { + panic("StaticInst::branchTarget() called on instruction " + "that is not a PC-relative branch."); + } + + /** + * Return the target address for an indirect branch (jump). The + * register value is read from the supplied execution context, so + * the result is valid only if the execution context is about to + * execute the branch in question. Invalid if not an indirect + * branch (i.e. isIndirectCtrl() should be true). + */ + virtual Addr branchTarget(ExecContext *xc) const + { + panic("StaticInst::branchTarget() called on instruction " + "that is not an indirect branch."); + } + + /** + * Return true if the instruction is a control transfer, and if so, + * return the target address as well. + */ + bool hasBranchTarget(Addr pc, ExecContext *xc, Addr &tgt) const; + + /** + * Return string representation of disassembled instruction. + * The default version of this function will call the internal + * virtual generateDisassembly() function to get the string, + * then cache it in #cachedDisassembly. If the disassembly + * should not be cached, this function should be overridden directly. + */ + virtual const std::string &disassemble(Addr pc, + const SymbolTable *symtab = 0) const + { + if (!cachedDisassembly) + cachedDisassembly = + new std::string(generateDisassembly(pc, symtab)); + + return *cachedDisassembly; + } + + /// Decoded instruction cache type. + /// For now we're using a generic hash_map; this seems to work + /// pretty well. + typedef m5::hash_map<ExtMachInst, StaticInstPtr> DecodeCache; + + /// A cache of decoded instruction objects. + static DecodeCache decodeCache; + + /** + * Dump some basic stats on the decode cache hash map. + * Only gets called if DECODE_CACHE_HASH_STATS is defined. + */ + static void dumpDecodeCacheStats(); + + /// Decode a machine instruction. + /// @param mach_inst The binary instruction to decode. + /// @retval A pointer to the corresponding StaticInst object. + //This is defined as inline below. + static StaticInstPtr decode(ExtMachInst mach_inst); + + //MIPS Decoder Debug Functions + int getOpcode() { return (machInst & 0xFC000000) >> 26 ; }//31..26 + int getRs() { return (machInst & 0x03E00000) >> 21; } //25...21 + int getRt() { return (machInst & 0x001F0000) >> 16; } //20...16 + int getRd() { return (machInst & 0x0000F800) >> 11; } //15...11 + int getImm() { return (machInst & 0x0000FFFF); } //15...0 + int getFunction(){ return (machInst & 0x0000003F); }//5...0 + int getBranch(){ return (machInst & 0x0000FFFF); }//15...0 + int getJump(){ return (machInst & 0x03FFFFFF); }//5...0 + int getHint(){ return (machInst & 0x000007C0) >> 6; } //10...6 + std::string getName() { return mnemonic; } +}; + +typedef RefCountingPtr<StaticInstBase> StaticInstBasePtr; + +/// Reference-counted pointer to a StaticInst object. +/// This type should be used instead of "StaticInst *" so that +/// StaticInst objects can be properly reference-counted. +class StaticInstPtr : public RefCountingPtr<StaticInst> +{ + public: + /// Constructor. + StaticInstPtr() + : RefCountingPtr<StaticInst>() + { + } + + /// Conversion from "StaticInst *". + StaticInstPtr(StaticInst *p) + : RefCountingPtr<StaticInst>(p) + { + } + + /// Copy constructor. + StaticInstPtr(const StaticInstPtr &r) + : RefCountingPtr<StaticInst>(r) + { + } + + /// Construct directly from machine instruction. + /// Calls StaticInst::decode(). + StaticInstPtr(TheISA::ExtMachInst mach_inst) + : RefCountingPtr<StaticInst>(StaticInst::decode(mach_inst)) + { + } + + /// Convert to pointer to StaticInstBase class. + operator const StaticInstBasePtr() + { + return this->get(); + } +}; + +inline StaticInstPtr +StaticInst::decode(StaticInst::ExtMachInst mach_inst) +{ +#ifdef DECODE_CACHE_HASH_STATS + // Simple stats on decode hash_map. Turns out the default + // hash function is as good as anything I could come up with. + const int dump_every_n = 10000000; + static int decodes_til_dump = dump_every_n; + + if (--decodes_til_dump == 0) { + dumpDecodeCacheStats(); + decodes_til_dump = dump_every_n; + } +#endif + + DecodeCache::iterator iter = decodeCache.find(mach_inst); + if (iter != decodeCache.end()) { + return iter->second; + } + + StaticInstPtr si = TheISA::decodeInst(mach_inst); + decodeCache[mach_inst] = si; + return si; +} + +#endif // __CPU_STATIC_INST_HH__ diff --git a/cpu/trace/opt_cpu.cc b/src/cpu/trace/opt_cpu.cc index 6cd23b0dd..6cd23b0dd 100644 --- a/cpu/trace/opt_cpu.cc +++ b/src/cpu/trace/opt_cpu.cc diff --git a/cpu/trace/opt_cpu.hh b/src/cpu/trace/opt_cpu.hh index f81691733..f81691733 100644 --- a/cpu/trace/opt_cpu.hh +++ b/src/cpu/trace/opt_cpu.hh diff --git a/cpu/trace/reader/ibm_reader.cc b/src/cpu/trace/reader/ibm_reader.cc index 420101b63..420101b63 100644 --- a/cpu/trace/reader/ibm_reader.cc +++ b/src/cpu/trace/reader/ibm_reader.cc diff --git a/cpu/trace/reader/ibm_reader.hh b/src/cpu/trace/reader/ibm_reader.hh index ce29206a2..ce29206a2 100644 --- a/cpu/trace/reader/ibm_reader.hh +++ b/src/cpu/trace/reader/ibm_reader.hh diff --git a/cpu/trace/reader/itx_reader.cc b/src/cpu/trace/reader/itx_reader.cc index 39ba27393..39ba27393 100644 --- a/cpu/trace/reader/itx_reader.cc +++ b/src/cpu/trace/reader/itx_reader.cc diff --git a/cpu/trace/reader/itx_reader.hh b/src/cpu/trace/reader/itx_reader.hh index a16a08085..a16a08085 100644 --- a/cpu/trace/reader/itx_reader.hh +++ b/src/cpu/trace/reader/itx_reader.hh diff --git a/cpu/trace/reader/m5_reader.cc b/src/cpu/trace/reader/m5_reader.cc index ce44672f2..ce44672f2 100644 --- a/cpu/trace/reader/m5_reader.cc +++ b/src/cpu/trace/reader/m5_reader.cc diff --git a/cpu/trace/reader/m5_reader.hh b/src/cpu/trace/reader/m5_reader.hh index 974a83ffa..974a83ffa 100644 --- a/cpu/trace/reader/m5_reader.hh +++ b/src/cpu/trace/reader/m5_reader.hh diff --git a/cpu/trace/reader/mem_trace_reader.cc b/src/cpu/trace/reader/mem_trace_reader.cc index 769f0be27..769f0be27 100644 --- a/cpu/trace/reader/mem_trace_reader.cc +++ b/src/cpu/trace/reader/mem_trace_reader.cc diff --git a/cpu/trace/reader/mem_trace_reader.hh b/src/cpu/trace/reader/mem_trace_reader.hh index b433cdbdd..b433cdbdd 100644 --- a/cpu/trace/reader/mem_trace_reader.hh +++ b/src/cpu/trace/reader/mem_trace_reader.hh diff --git a/cpu/trace/trace_cpu.cc b/src/cpu/trace/trace_cpu.cc index 20d0a567f..20d0a567f 100644 --- a/cpu/trace/trace_cpu.cc +++ b/src/cpu/trace/trace_cpu.cc diff --git a/cpu/trace/trace_cpu.hh b/src/cpu/trace/trace_cpu.hh index 69ca35321..69ca35321 100644 --- a/cpu/trace/trace_cpu.hh +++ b/src/cpu/trace/trace_cpu.hh diff --git a/dev/alpha_access.h b/src/dev/alpha_access.h index 5a1df6f39..5a1df6f39 100644 --- a/dev/alpha_access.h +++ b/src/dev/alpha_access.h diff --git a/src/dev/alpha_console.cc b/src/dev/alpha_console.cc new file mode 100644 index 000000000..0b4bb048c --- /dev/null +++ b/src/dev/alpha_console.cc @@ -0,0 +1,344 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file + * Alpha Console Definition + */ + +#include <cstddef> +#include <string> + +#include "arch/alpha/system.hh" +#include "base/inifile.hh" +#include "base/str.hh" +#include "base/trace.hh" +#include "cpu/base.hh" +#include "cpu/exec_context.hh" +#include "dev/alpha_console.hh" +#include "dev/platform.hh" +#include "dev/simconsole.hh" +#include "dev/simple_disk.hh" +#include "mem/physical.hh" +#include "sim/builder.hh" +#include "sim/sim_object.hh" + +using namespace std; +using namespace AlphaISA; + +AlphaConsole::AlphaConsole(Params *p) + : BasicPioDevice(p), disk(p->disk), + console(params()->cons), system(params()->alpha_sys), cpu(params()->cpu) +{ + + pioSize = sizeof(struct AlphaAccess); + + alphaAccess = new Access(); + alphaAccess->last_offset = pioSize - 1; + + alphaAccess->version = ALPHA_ACCESS_VERSION; + alphaAccess->diskUnit = 1; + + alphaAccess->diskCount = 0; + alphaAccess->diskPAddr = 0; + alphaAccess->diskBlock = 0; + alphaAccess->diskOperation = 0; + alphaAccess->outputChar = 0; + alphaAccess->inputChar = 0; + bzero(alphaAccess->cpuStack, sizeof(alphaAccess->cpuStack)); + +} + +void +AlphaConsole::startup() +{ + system->setAlphaAccess(pioAddr); + alphaAccess->numCPUs = system->getNumCPUs(); + alphaAccess->kernStart = system->getKernelStart(); + alphaAccess->kernEnd = system->getKernelEnd(); + alphaAccess->entryPoint = system->getKernelEntry(); + alphaAccess->mem_size = system->physmem->size(); + alphaAccess->cpuClock = cpu->frequency() / 1000000; // In MHz + alphaAccess->intrClockFrequency = params()->platform->intrFrequency(); +} + +Tick +AlphaConsole::read(Packet *pkt) +{ + + /** XXX Do we want to push the addr munging to a bus brige or something? So + * the device has it's physical address and then the bridge adds on whatever + * machine dependent address swizzle is required? + */ + + assert(pkt->result == Packet::Unknown); + assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); + + pkt->time += pioDelay; + Addr daddr = pkt->getAddr() - pioAddr; + + pkt->allocate(); + + switch (pkt->getSize()) + { + case sizeof(uint32_t): + switch (daddr) + { + case offsetof(AlphaAccess, last_offset): + pkt->set(alphaAccess->last_offset); + break; + case offsetof(AlphaAccess, version): + pkt->set(alphaAccess->version); + break; + case offsetof(AlphaAccess, numCPUs): + pkt->set(alphaAccess->numCPUs); + break; + case offsetof(AlphaAccess, intrClockFrequency): + pkt->set(alphaAccess->intrClockFrequency); + break; + default: + /* Old console code read in everyting as a 32bit int + * we now break that for better error checking. + */ + pkt->result = Packet::BadAddress; + } + DPRINTF(AlphaConsole, "read: offset=%#x val=%#x\n", daddr, + pkt->get<uint32_t>()); + break; + case sizeof(uint64_t): + switch (daddr) + { + case offsetof(AlphaAccess, inputChar): + pkt->set(console->console_in()); + break; + case offsetof(AlphaAccess, cpuClock): + pkt->set(alphaAccess->cpuClock); + break; + case offsetof(AlphaAccess, mem_size): + pkt->set(alphaAccess->mem_size); + break; + case offsetof(AlphaAccess, kernStart): + pkt->set(alphaAccess->kernStart); + break; + case offsetof(AlphaAccess, kernEnd): + pkt->set(alphaAccess->kernEnd); + break; + case offsetof(AlphaAccess, entryPoint): + pkt->set(alphaAccess->entryPoint); + break; + case offsetof(AlphaAccess, diskUnit): + pkt->set(alphaAccess->diskUnit); + break; + case offsetof(AlphaAccess, diskCount): + pkt->set(alphaAccess->diskCount); + break; + case offsetof(AlphaAccess, diskPAddr): + pkt->set(alphaAccess->diskPAddr); + break; + case offsetof(AlphaAccess, diskBlock): + pkt->set(alphaAccess->diskBlock); + break; + case offsetof(AlphaAccess, diskOperation): + pkt->set(alphaAccess->diskOperation); + break; + case offsetof(AlphaAccess, outputChar): + pkt->set(alphaAccess->outputChar); + break; + default: + int cpunum = (daddr - offsetof(AlphaAccess, cpuStack)) / + sizeof(alphaAccess->cpuStack[0]); + + if (cpunum >= 0 && cpunum < 64) + pkt->set(alphaAccess->cpuStack[cpunum]); + else + panic("Unknown 64bit access, %#x\n", daddr); + } + DPRINTF(AlphaConsole, "read: offset=%#x val=%#x\n", daddr, + pkt->get<uint64_t>()); + break; + default: + pkt->result = Packet::BadAddress; + } + if (pkt->result == Packet::Unknown) + pkt->result = Packet::Success; + return pioDelay; +} + +Tick +AlphaConsole::write(Packet *pkt) +{ + pkt->time += pioDelay; + + assert(pkt->result == Packet::Unknown); + assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); + Addr daddr = pkt->getAddr() - pioAddr; + + uint64_t val = pkt->get<uint64_t>(); + assert(pkt->getSize() == sizeof(uint64_t)); + + switch (daddr) { + case offsetof(AlphaAccess, diskUnit): + alphaAccess->diskUnit = val; + break; + + case offsetof(AlphaAccess, diskCount): + alphaAccess->diskCount = val; + break; + + case offsetof(AlphaAccess, diskPAddr): + alphaAccess->diskPAddr = val; + break; + + case offsetof(AlphaAccess, diskBlock): + alphaAccess->diskBlock = val; + break; + + case offsetof(AlphaAccess, diskOperation): + if (val == 0x13) + disk->read(alphaAccess->diskPAddr, alphaAccess->diskBlock, + alphaAccess->diskCount); + else + panic("Invalid disk operation!"); + + break; + + case offsetof(AlphaAccess, outputChar): + console->out((char)(val & 0xff)); + break; + + default: + int cpunum = (daddr - offsetof(AlphaAccess, cpuStack)) / + sizeof(alphaAccess->cpuStack[0]); + warn("%d: Trying to launch CPU number %d!", curTick, cpunum); + assert(val > 0 && "Must not access primary cpu"); + if (cpunum >= 0 && cpunum < 64) + alphaAccess->cpuStack[cpunum] = val; + else + panic("Unknown 64bit access, %#x\n", daddr); + } + + pkt->result = Packet::Success; + + return pioDelay; +} + +void +AlphaConsole::Access::serialize(ostream &os) +{ + SERIALIZE_SCALAR(last_offset); + SERIALIZE_SCALAR(version); + SERIALIZE_SCALAR(numCPUs); + SERIALIZE_SCALAR(mem_size); + SERIALIZE_SCALAR(cpuClock); + SERIALIZE_SCALAR(intrClockFrequency); + SERIALIZE_SCALAR(kernStart); + SERIALIZE_SCALAR(kernEnd); + SERIALIZE_SCALAR(entryPoint); + SERIALIZE_SCALAR(diskUnit); + SERIALIZE_SCALAR(diskCount); + SERIALIZE_SCALAR(diskPAddr); + SERIALIZE_SCALAR(diskBlock); + SERIALIZE_SCALAR(diskOperation); + SERIALIZE_SCALAR(outputChar); + SERIALIZE_SCALAR(inputChar); + SERIALIZE_ARRAY(cpuStack,64); +} + +void +AlphaConsole::Access::unserialize(Checkpoint *cp, const std::string §ion) +{ + UNSERIALIZE_SCALAR(last_offset); + UNSERIALIZE_SCALAR(version); + UNSERIALIZE_SCALAR(numCPUs); + UNSERIALIZE_SCALAR(mem_size); + UNSERIALIZE_SCALAR(cpuClock); + UNSERIALIZE_SCALAR(intrClockFrequency); + UNSERIALIZE_SCALAR(kernStart); + UNSERIALIZE_SCALAR(kernEnd); + UNSERIALIZE_SCALAR(entryPoint); + UNSERIALIZE_SCALAR(diskUnit); + UNSERIALIZE_SCALAR(diskCount); + UNSERIALIZE_SCALAR(diskPAddr); + UNSERIALIZE_SCALAR(diskBlock); + UNSERIALIZE_SCALAR(diskOperation); + UNSERIALIZE_SCALAR(outputChar); + UNSERIALIZE_SCALAR(inputChar); + UNSERIALIZE_ARRAY(cpuStack, 64); +} + +void +AlphaConsole::serialize(ostream &os) +{ + alphaAccess->serialize(os); +} + +void +AlphaConsole::unserialize(Checkpoint *cp, const std::string §ion) +{ + alphaAccess->unserialize(cp, section); +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaConsole) + + SimObjectParam<SimConsole *> sim_console; + SimObjectParam<SimpleDisk *> disk; + Param<Addr> pio_addr; + SimObjectParam<AlphaSystem *> system; + SimObjectParam<BaseCPU *> cpu; + SimObjectParam<Platform *> platform; + Param<Tick> pio_latency; + +END_DECLARE_SIM_OBJECT_PARAMS(AlphaConsole) + +BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaConsole) + + INIT_PARAM(sim_console, "The Simulator Console"), + INIT_PARAM(disk, "Simple Disk"), + INIT_PARAM(pio_addr, "Device Address"), + INIT_PARAM(system, "system object"), + INIT_PARAM(cpu, "Processor"), + INIT_PARAM(platform, "platform"), + INIT_PARAM_DFLT(pio_latency, "Programmed IO latency", 1000) + +END_INIT_SIM_OBJECT_PARAMS(AlphaConsole) + +CREATE_SIM_OBJECT(AlphaConsole) +{ + AlphaConsole::Params *p = new AlphaConsole::Params; + p->name = getInstanceName(); + p->platform = platform; + p->pio_addr = pio_addr; + p->pio_delay = pio_latency; + p->cons = sim_console; + p->disk = disk; + p->alpha_sys = system; + p->system = system; + p->cpu = cpu; + return new AlphaConsole(p); +} + +REGISTER_SIM_OBJECT("AlphaConsole", AlphaConsole) diff --git a/src/dev/alpha_console.hh b/src/dev/alpha_console.hh new file mode 100644 index 000000000..34d21e15c --- /dev/null +++ b/src/dev/alpha_console.hh @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file + * System Console Interface + */ + +#ifndef __ALPHA_CONSOLE_HH__ +#define __ALPHA_CONSOLE_HH__ + +#include "base/range.hh" +#include "dev/alpha_access.h" +#include "dev/io_device.hh" +#include "sim/host.hh" +#include "sim/sim_object.hh" + +class BaseCPU; +class SimConsole; +class AlphaSystem; +class SimpleDisk; + +/** + * Memory mapped interface to the system console. This device + * represents a shared data region between the OS Kernel and the + * System Console. + * + * The system console is a small standalone program that is initially + * run when the system boots. It contains the necessary code to + * access the boot disk, to read/write from the console, and to pass + * boot parameters to the kernel. + * + * This version of the system console is very different from the one + * that would be found in a real system. Many of the functions use + * some sort of backdoor to get their job done. For example, reading + * from the boot device on a real system would require a minimal + * device driver to access the disk controller, but since we have a + * simulator here, we are able to bypass the disk controller and + * access the disk image directly. There are also some things like + * reading the kernel off the disk image into memory that are normally + * taken care of by the console that are now taken care of by the + * simulator. + * + * These shortcuts are acceptable since the system console is + * primarily used doing boot before the kernel has loaded its device + * drivers. + */ +class AlphaConsole : public BasicPioDevice +{ + protected: + struct Access : public AlphaAccess + { + void serialize(std::ostream &os); + void unserialize(Checkpoint *cp, const std::string §ion); + }; + + union { + Access *alphaAccess; + uint8_t *consoleData; + }; + + /** the disk must be accessed from the console */ + SimpleDisk *disk; + + /** the system console (the terminal) is accessable from the console */ + SimConsole *console; + + /** a pointer to the system we are running in */ + AlphaSystem *system; + + /** a pointer to the CPU boot cpu */ + BaseCPU *cpu; + + public: + struct Params : public BasicPioDevice::Params + { + SimConsole *cons; + SimpleDisk *disk; + AlphaSystem *alpha_sys; + BaseCPU *cpu; + }; + protected: + const Params *params() const {return (const Params *)_params; } + + public: + + /** Standard Constructor */ + AlphaConsole(Params *p); + + virtual void startup(); + + /** + * memory mapped reads and writes + */ + virtual Tick read(Packet *pkt); + virtual Tick write(Packet *pkt); + + /** + * standard serialization routines for checkpointing + */ + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); +}; + +#endif // __ALPHA_CONSOLE_HH__ diff --git a/src/dev/baddev.cc b/src/dev/baddev.cc new file mode 100644 index 000000000..66fbd8a86 --- /dev/null +++ b/src/dev/baddev.cc @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file + * BadDevice implemenation + */ + +#include <deque> +#include <string> +#include <vector> + +#include "base/trace.hh" +#include "dev/baddev.hh" +#include "dev/platform.hh" +#include "mem/port.hh" +#include "sim/builder.hh" +#include "sim/system.hh" + +using namespace std; +using namespace TheISA; + +BadDevice::BadDevice(Params *p) + : BasicPioDevice(p), devname(p->device_name) +{ + pioSize = 0xf; +} + +Tick +BadDevice::read(Packet *pkt) +{ + panic("Device %s not imlpmented\n", devname); +} + +Tick +BadDevice::write(Packet *pkt) +{ + panic("Device %s not imlpmented\n", devname); +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(BadDevice) + + Param<string> devicename; + Param<Addr> pio_addr; + SimObjectParam<System *> system; + SimObjectParam<Platform *> platform; + Param<Tick> pio_latency; + +END_DECLARE_SIM_OBJECT_PARAMS(BadDevice) + +BEGIN_INIT_SIM_OBJECT_PARAMS(BadDevice) + + INIT_PARAM(devicename, "Name of device to error on"), + INIT_PARAM(pio_addr, "Device Address"), + INIT_PARAM(system, "system object"), + INIT_PARAM(platform, "platform"), + INIT_PARAM_DFLT(pio_latency, "Programmed IO latency", 1000) + +END_INIT_SIM_OBJECT_PARAMS(BadDevice) + +CREATE_SIM_OBJECT(BadDevice) +{ + BadDevice::Params *p = new BadDevice::Params; + p->name =getInstanceName(); + p->platform = platform; + p->pio_addr = pio_addr; + p->pio_delay = pio_latency; + p->system = system; + p->device_name = devicename; + return new BadDevice(p); +} + +REGISTER_SIM_OBJECT("BadDevice", BadDevice) diff --git a/src/dev/baddev.hh b/src/dev/baddev.hh new file mode 100644 index 000000000..35ae0382a --- /dev/null +++ b/src/dev/baddev.hh @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file + * This devices just panics when touched. For example if you have a + * kernel that touches the frame buffer which isn't allowed. + */ + +#ifndef __DEV_BADDEV_HH__ +#define __DEV_BADDEV_HH__ + +#include "base/range.hh" +#include "dev/io_device.hh" + + +/** + * BadDevice + * This device just panics when accessed. It is supposed to warn + * the user that the kernel they are running has unsupported + * options (i.e. frame buffer) + */ +class BadDevice : public BasicPioDevice +{ + private: + std::string devname; + + public: + struct Params : public BasicPioDevice::Params + { + std::string device_name; + }; + protected: + const Params *params() const { return (const Params *)_params; } + + public: + /** + * Constructor for the Baddev Class. + * @param p object parameters + * @param a base address of the write + */ + BadDevice(Params *p); + + virtual Tick read(Packet *pkt); + virtual Tick write(Packet *pkt); +}; + +#endif // __DEV_BADDEV_HH__ diff --git a/src/dev/disk_image.cc b/src/dev/disk_image.cc new file mode 100644 index 000000000..185a8b083 --- /dev/null +++ b/src/dev/disk_image.cc @@ -0,0 +1,470 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file + * Disk Image Definitions + */ + +#include <sys/types.h> +#include <sys/uio.h> +#include <errno.h> +#include <unistd.h> + +#include <cstring> +#include <fstream> +#include <string> + +#include "base/callback.hh" +#include "base/misc.hh" +#include "base/trace.hh" +#include "dev/disk_image.hh" +#include "sim/builder.hh" +#include "sim/sim_exit.hh" +#include "sim/byteswap.hh" + +using namespace std; + +//////////////////////////////////////////////////////////////////////// +// +// Raw Disk image +// +RawDiskImage::RawDiskImage(const string &name, const string &filename, + bool rd_only) + : DiskImage(name), disk_size(0) +{ open(filename, rd_only); } + +RawDiskImage::~RawDiskImage() +{ close(); } + +void +RawDiskImage::open(const string &filename, bool rd_only) +{ + if (!filename.empty()) { + initialized = true; + readonly = rd_only; + file = filename; + + ios::openmode mode = ios::in | ios::binary; + if (!readonly) + mode |= ios::out; + stream.open(file.c_str(), mode); + if (!stream.is_open()) + panic("Error opening %s", filename); + } +} + +void +RawDiskImage::close() +{ + stream.close(); +} + +off_t +RawDiskImage::size() const +{ + if (disk_size == 0) { + if (!stream.is_open()) + panic("file not open!\n"); + stream.seekg(0, ios::end); + disk_size = stream.tellg(); + } + + return disk_size / SectorSize; +} + +off_t +RawDiskImage::read(uint8_t *data, off_t offset) const +{ + if (!initialized) + panic("RawDiskImage not initialized"); + + if (!stream.is_open()) + panic("file not open!\n"); + + if (stream.seekg(offset * SectorSize, ios::beg) < 0) + panic("Could not seek to location in file"); + + streampos pos = stream.tellg(); + stream.read((char *)data, SectorSize); + + DPRINTF(DiskImageRead, "read: offset=%d\n", (uint64_t)offset); + DDUMP(DiskImageRead, data, SectorSize); + + return stream.tellg() - pos; +} + +off_t +RawDiskImage::write(const uint8_t *data, off_t offset) +{ + if (!initialized) + panic("RawDiskImage not initialized"); + + if (readonly) + panic("Cannot write to a read only disk image"); + + if (!stream.is_open()) + panic("file not open!\n"); + + if (stream.seekp(offset * SectorSize, ios::beg) < 0) + panic("Could not seek to location in file"); + + DPRINTF(DiskImageWrite, "write: offset=%d\n", (uint64_t)offset); + DDUMP(DiskImageWrite, data, SectorSize); + + streampos pos = stream.tellp(); + stream.write((const char *)data, SectorSize); + return stream.tellp() - pos; +} + +DEFINE_SIM_OBJECT_CLASS_NAME("DiskImage", DiskImage) + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(RawDiskImage) + + Param<string> image_file; + Param<bool> read_only; + +END_DECLARE_SIM_OBJECT_PARAMS(RawDiskImage) + +BEGIN_INIT_SIM_OBJECT_PARAMS(RawDiskImage) + + INIT_PARAM(image_file, "disk image file"), + INIT_PARAM_DFLT(read_only, "read only image", false) + +END_INIT_SIM_OBJECT_PARAMS(RawDiskImage) + + +CREATE_SIM_OBJECT(RawDiskImage) +{ + return new RawDiskImage(getInstanceName(), image_file, read_only); +} + +REGISTER_SIM_OBJECT("RawDiskImage", RawDiskImage) + +//////////////////////////////////////////////////////////////////////// +// +// Copy on Write Disk image +// +const int CowDiskImage::VersionMajor = 1; +const int CowDiskImage::VersionMinor = 0; + +CowDiskImage::CowDiskImage(const string &name, DiskImage *kid, int hash_size) + : DiskImage(name), child(kid), table(NULL) +{ init(hash_size); } + +class CowDiskCallback : public Callback +{ + private: + CowDiskImage *image; + + public: + CowDiskCallback(CowDiskImage *i) : image(i) {} + void process() { image->save(); delete this; } +}; + +CowDiskImage::CowDiskImage(const string &name, DiskImage *kid, int hash_size, + const string &file, bool read_only) + : DiskImage(name), filename(file), child(kid), table(NULL) +{ + if (!open(filename)) { + assert(!read_only && "why have a non-existent read only file?"); + init(hash_size); + } + + if (!read_only) + registerExitCallback(new CowDiskCallback(this)); +} + +CowDiskImage::~CowDiskImage() +{ + SectorTable::iterator i = table->begin(); + SectorTable::iterator end = table->end(); + + while (i != end) { + delete (*i).second; + ++i; + } +} + +void +SafeRead(ifstream &stream, void *data, int count) +{ + stream.read((char *)data, count); + if (!stream.is_open()) + panic("file not open"); + + if (stream.eof()) + panic("premature end-of-file"); + + if (stream.bad() || stream.fail()) + panic("error reading cowdisk image"); +} + +template<class T> +void +SafeRead(ifstream &stream, T &data) +{ + SafeRead(stream, &data, sizeof(data)); +} + +template<class T> +void +SafeReadSwap(ifstream &stream, T &data) +{ + SafeRead(stream, &data, sizeof(data)); + data = letoh(data); //is this the proper byte order conversion? +} + +bool +CowDiskImage::open(const string &file) +{ + ifstream stream(file.c_str()); + if (!stream.is_open()) + return false; + + if (stream.fail() || stream.bad()) + panic("Error opening %s", file); + + uint64_t magic; + SafeRead(stream, magic); + + if (memcmp(&magic, "COWDISK!", sizeof(magic)) != 0) + panic("Could not open %s: Invalid magic", file); + + uint32_t major, minor; + SafeReadSwap(stream, major); + SafeReadSwap(stream, minor); + + if (major != VersionMajor && minor != VersionMinor) + panic("Could not open %s: invalid version %d.%d != %d.%d", + file, major, minor, VersionMajor, VersionMinor); + + uint64_t sector_count; + SafeReadSwap(stream, sector_count); + table = new SectorTable(sector_count); + + + for (uint64_t i = 0; i < sector_count; i++) { + uint64_t offset; + SafeReadSwap(stream, offset); + + Sector *sector = new Sector; + SafeRead(stream, sector, sizeof(Sector)); + + assert(table->find(offset) == table->end()); + (*table)[offset] = sector; + } + + stream.close(); + + initialized = true; + return true; +} + +void +CowDiskImage::init(int hash_size) +{ + table = new SectorTable(hash_size); + + initialized = true; +} + +void +SafeWrite(ofstream &stream, const void *data, int count) +{ + stream.write((const char *)data, count); + if (!stream.is_open()) + panic("file not open"); + + if (stream.eof()) + panic("premature end-of-file"); + + if (stream.bad() || stream.fail()) + panic("error reading cowdisk image"); +} + +template<class T> +void +SafeWrite(ofstream &stream, const T &data) +{ + SafeWrite(stream, &data, sizeof(data)); +} + +template<class T> +void +SafeWriteSwap(ofstream &stream, const T &data) +{ + T swappeddata = letoh(data); //is this the proper byte order conversion? + SafeWrite(stream, &swappeddata, sizeof(data)); +} +void +CowDiskImage::save() +{ + save(filename); +} + +void +CowDiskImage::save(const string &file) +{ + if (!initialized) + panic("RawDiskImage not initialized"); + + ofstream stream(file.c_str()); + if (!stream.is_open() || stream.fail() || stream.bad()) + panic("Error opening %s", file); + + uint64_t magic; + memcpy(&magic, "COWDISK!", sizeof(magic)); + SafeWrite(stream, magic); + + SafeWriteSwap(stream, (uint32_t)VersionMajor); + SafeWriteSwap(stream, (uint32_t)VersionMinor); + SafeWriteSwap(stream, (uint64_t)table->size()); + + uint64_t size = table->size(); + SectorTable::iterator iter = table->begin(); + SectorTable::iterator end = table->end(); + + for (uint64_t i = 0; i < size; i++) { + if (iter == end) + panic("Incorrect Table Size during save of COW disk image"); + + SafeWriteSwap(stream, (uint64_t)(*iter).first); + SafeWrite(stream, (*iter).second->data, sizeof(Sector)); + ++iter; + } + + stream.close(); +} + +void +CowDiskImage::writeback() +{ + SectorTable::iterator i = table->begin(); + SectorTable::iterator end = table->end(); + + while (i != end) { + child->write((*i).second->data, (*i).first); + ++i; + } +} + +off_t +CowDiskImage::size() const +{ return child->size(); } + +off_t +CowDiskImage::read(uint8_t *data, off_t offset) const +{ + if (!initialized) + panic("CowDiskImage not initialized"); + + if (offset > size()) + panic("access out of bounds"); + + SectorTable::const_iterator i = table->find(offset); + if (i == table->end()) + return child->read(data, offset); + else { + memcpy(data, (*i).second->data, SectorSize); + DPRINTF(DiskImageRead, "read: offset=%d\n", (uint64_t)offset); + DDUMP(DiskImageRead, data, SectorSize); + return SectorSize; + } +} + +off_t +CowDiskImage::write(const uint8_t *data, off_t offset) +{ + if (!initialized) + panic("RawDiskImage not initialized"); + + if (offset > size()) + panic("access out of bounds"); + + SectorTable::iterator i = table->find(offset); + if (i == table->end()) { + Sector *sector = new Sector; + memcpy(sector, data, SectorSize); + table->insert(make_pair(offset, sector)); + } else { + memcpy((*i).second->data, data, SectorSize); + } + + DPRINTF(DiskImageWrite, "write: offset=%d\n", (uint64_t)offset); + DDUMP(DiskImageWrite, data, SectorSize); + + return SectorSize; +} + +void +CowDiskImage::serialize(ostream &os) +{ + string cowFilename = name() + ".cow"; + SERIALIZE_SCALAR(cowFilename); + save(Checkpoint::dir() + "/" + cowFilename); +} + +void +CowDiskImage::unserialize(Checkpoint *cp, const string §ion) +{ + string cowFilename; + UNSERIALIZE_SCALAR(cowFilename); + cowFilename = cp->cptDir + "/" + cowFilename; + open(cowFilename); +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(CowDiskImage) + + SimObjectParam<DiskImage *> child; + Param<string> image_file; + Param<int> table_size; + Param<bool> read_only; + +END_DECLARE_SIM_OBJECT_PARAMS(CowDiskImage) + +BEGIN_INIT_SIM_OBJECT_PARAMS(CowDiskImage) + + INIT_PARAM(child, "child image"), + INIT_PARAM_DFLT(image_file, "disk image file", ""), + INIT_PARAM_DFLT(table_size, "initial table size", 65536), + INIT_PARAM_DFLT(read_only, "don't write back to the copy-on-write file", + true) + +END_INIT_SIM_OBJECT_PARAMS(CowDiskImage) + + +CREATE_SIM_OBJECT(CowDiskImage) +{ + if (((string)image_file).empty()) + return new CowDiskImage(getInstanceName(), child, table_size); + else + return new CowDiskImage(getInstanceName(), child, table_size, + image_file, read_only); +} + +REGISTER_SIM_OBJECT("CowDiskImage", CowDiskImage) diff --git a/dev/disk_image.hh b/src/dev/disk_image.hh index 648aa20c6..648aa20c6 100644 --- a/dev/disk_image.hh +++ b/src/dev/disk_image.hh diff --git a/src/dev/etherbus.cc b/src/dev/etherbus.cc new file mode 100644 index 000000000..906e324d3 --- /dev/null +++ b/src/dev/etherbus.cc @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* @file + * Device module for modelling an ethernet hub + */ + +#include <cmath> +#include <deque> +#include <string> +#include <vector> + +#include "base/trace.hh" +#include "dev/etherbus.hh" +#include "dev/etherdump.hh" +#include "dev/etherint.hh" +#include "dev/etherpkt.hh" +#include "sim/builder.hh" +#include "sim/root.hh" + +using namespace std; + +EtherBus::EtherBus(const string &name, double speed, bool loop, + EtherDump *packet_dump) + : SimObject(name), ticksPerByte(speed), loopback(loop), + event(&mainEventQueue, this), sender(0), dump(packet_dump) +{ +} + +void +EtherBus::txDone() +{ + devlist_t::iterator i = devlist.begin(); + devlist_t::iterator end = devlist.end(); + + DPRINTF(Ethernet, "ethernet packet received: length=%d\n", packet->length); + DDUMP(EthernetData, packet->data, packet->length); + + while (i != end) { + if (loopback || *i != sender) + (*i)->sendPacket(packet); + ++i; + } + + sender->sendDone(); + + if (dump) + dump->dump(packet); + + sender = 0; + packet = 0; +} + +void +EtherBus::reg(EtherInt *dev) +{ devlist.push_back(dev); } + +bool +EtherBus::send(EtherInt *sndr, EthPacketPtr &pkt) +{ + if (busy()) { + DPRINTF(Ethernet, "ethernet packet not sent, bus busy\n", curTick); + return false; + } + + DPRINTF(Ethernet, "ethernet packet sent: length=%d\n", pkt->length); + DDUMP(EthernetData, pkt->data, pkt->length); + + packet = pkt; + sender = sndr; + int delay = (int)ceil(((double)pkt->length * ticksPerByte) + 1.0); + DPRINTF(Ethernet, "scheduling packet: delay=%d, (rate=%f)\n", + delay, ticksPerByte); + event.schedule(curTick + delay); + + return true; +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherBus) + + Param<bool> loopback; + Param<double> speed; + SimObjectParam<EtherDump *> packet_dump; + +END_DECLARE_SIM_OBJECT_PARAMS(EtherBus) + +BEGIN_INIT_SIM_OBJECT_PARAMS(EtherBus) + + INIT_PARAM(loopback, "send the packet back to the sending interface"), + INIT_PARAM(speed, "bus speed in ticks per byte"), + INIT_PARAM(packet_dump, "object to dump network packets to") + +END_INIT_SIM_OBJECT_PARAMS(EtherBus) + +CREATE_SIM_OBJECT(EtherBus) +{ + return new EtherBus(getInstanceName(), speed, loopback, packet_dump); +} + +REGISTER_SIM_OBJECT("EtherBus", EtherBus) diff --git a/src/dev/etherbus.hh b/src/dev/etherbus.hh new file mode 100644 index 000000000..4a364abd8 --- /dev/null +++ b/src/dev/etherbus.hh @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* @file + * Device module for modelling an ethernet hub + */ + +#ifndef __ETHERBUS_H__ +#define __ETHERBUS_H__ + +#include "sim/eventq.hh" +#include "dev/etherpkt.hh" +#include "sim/sim_object.hh" + +class EtherDump; +class EtherInt; +class EtherBus : public SimObject +{ + protected: + typedef std::list<EtherInt *> devlist_t; + devlist_t devlist; + double ticksPerByte; + bool loopback; + + protected: + class DoneEvent : public Event + { + protected: + EtherBus *bus; + + public: + DoneEvent(EventQueue *q, EtherBus *b) + : Event(q), bus(b) {} + virtual void process() { bus->txDone(); } + virtual const char *description() { return "ethernet bus completion"; } + }; + + DoneEvent event; + EthPacketPtr packet; + EtherInt *sender; + EtherDump *dump; + + public: + EtherBus(const std::string &name, double speed, bool loopback, + EtherDump *dump); + virtual ~EtherBus() {} + + void txDone(); + void reg(EtherInt *dev); + bool busy() const { return (bool)packet; } + bool send(EtherInt *sender, EthPacketPtr &packet); +}; + +#endif // __ETHERBUS_H__ diff --git a/src/dev/etherdump.cc b/src/dev/etherdump.cc new file mode 100644 index 000000000..cb5f0b70e --- /dev/null +++ b/src/dev/etherdump.cc @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* @file + * Simple object for creating a simple pcap style packet trace + */ + +#include <sys/time.h> + +#include <algorithm> +#include <string> + +#include "base/misc.hh" +#include "base/output.hh" +#include "dev/etherdump.hh" +#include "sim/builder.hh" +#include "sim/root.hh" + +using std::string; + +EtherDump::EtherDump(const string &name, const string &file, int max) + : SimObject(name), stream(file.c_str()), maxlen(max) +{ +} + +#define DLT_EN10MB 1 // Ethernet (10Mb) +#define TCPDUMP_MAGIC 0xa1b2c3d4 +#define PCAP_VERSION_MAJOR 2 +#define PCAP_VERSION_MINOR 4 + +struct pcap_file_header { + uint32_t magic; + uint16_t version_major; + uint16_t version_minor; + int32_t thiszone; // gmt to local correction + uint32_t sigfigs; // accuracy of timestamps + uint32_t snaplen; // max length saved portion of each pkt + uint32_t linktype; // data link type (DLT_*) +}; + +struct pcap_pkthdr { + uint32_t seconds; + uint32_t microseconds; + uint32_t caplen; // length of portion present + uint32_t len; // length this packet (off wire) +}; + +void +EtherDump::init() +{ + curtime = time(NULL); + struct pcap_file_header hdr; + hdr.magic = TCPDUMP_MAGIC; + hdr.version_major = PCAP_VERSION_MAJOR; + hdr.version_minor = PCAP_VERSION_MINOR; + + hdr.thiszone = -5 * 3600; + hdr.snaplen = 1500; + hdr.sigfigs = 0; + hdr.linktype = DLT_EN10MB; + + stream.write(reinterpret_cast<char *>(&hdr), sizeof(hdr)); + + /* + * output an empty packet with the current time so that we know + * when the simulation began. This allows us to correlate packets + * to sim_cycles. + */ + pcap_pkthdr pkthdr; + pkthdr.seconds = curtime; + pkthdr.microseconds = 0; + pkthdr.caplen = 0; + pkthdr.len = 0; + stream.write(reinterpret_cast<char *>(&pkthdr), sizeof(pkthdr)); + + stream.flush(); +} + +void +EtherDump::dumpPacket(EthPacketPtr &packet) +{ + pcap_pkthdr pkthdr; + pkthdr.seconds = curtime + (curTick / Clock::Int::s); + pkthdr.microseconds = (curTick / Clock::Int::us) % ULL(1000000); + pkthdr.caplen = std::min(packet->length, maxlen); + pkthdr.len = packet->length; + stream.write(reinterpret_cast<char *>(&pkthdr), sizeof(pkthdr)); + stream.write(reinterpret_cast<char *>(packet->data), pkthdr.caplen); + stream.flush(); +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherDump) + + Param<string> file; + Param<int> maxlen; + +END_DECLARE_SIM_OBJECT_PARAMS(EtherDump) + +BEGIN_INIT_SIM_OBJECT_PARAMS(EtherDump) + + INIT_PARAM(file, "file to dump packets to"), + INIT_PARAM(maxlen, "max portion of packet data to dump") + +END_INIT_SIM_OBJECT_PARAMS(EtherDump) + +CREATE_SIM_OBJECT(EtherDump) +{ + return new EtherDump(getInstanceName(), simout.resolve(file), maxlen); +} + +REGISTER_SIM_OBJECT("EtherDump", EtherDump) diff --git a/src/dev/etherdump.hh b/src/dev/etherdump.hh new file mode 100644 index 000000000..8bba073fe --- /dev/null +++ b/src/dev/etherdump.hh @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* @file + * Simple object for creating a simple pcap style packet trace + */ + +#ifndef __ETHERDUMP_H__ +#define __ETHERDUMP_H__ + +#include <fstream> +#include "dev/etherpkt.hh" +#include "sim/sim_object.hh" + +/* + * Simple object for creating a simple pcap style packet trace + */ +class EtherDump : public SimObject +{ + private: + std::ofstream stream; + const int maxlen; + void dumpPacket(EthPacketPtr &packet); + void init(); + + Tick curtime; + + public: + EtherDump(const std::string &name, const std::string &file, int max); + + inline void dump(EthPacketPtr &pkt) { dumpPacket(pkt); } +}; + +#endif // __ETHERDUMP_H__ diff --git a/dev/etherint.cc b/src/dev/etherint.cc index 8fb047373..8fb047373 100644 --- a/dev/etherint.cc +++ b/src/dev/etherint.cc diff --git a/src/dev/etherint.hh b/src/dev/etherint.hh new file mode 100644 index 000000000..1f641fadb --- /dev/null +++ b/src/dev/etherint.hh @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* @file + * Class representing the actual interface between two ethernet + * components. + */ + +#ifndef __DEV_ETHERINT_HH__ +#define __DEV_ETHERINT_HH__ + +#include <string> + +#include "dev/etherpkt.hh" +#include "sim/sim_object.hh" + +/* + * Class representing the actual interface between two ethernet + * components. These components are intended to attach to another + * ethernet interface on one side and whatever device on the other. + */ +class EtherInt : public SimObject +{ + protected: + EtherInt *peer; + + public: + EtherInt(const std::string &name) : SimObject(name), peer(NULL) {} + virtual ~EtherInt() {} + + void setPeer(EtherInt *p); + + void recvDone() { peer->sendDone(); } + virtual void sendDone() = 0; + + bool sendPacket(EthPacketPtr packet) + { return peer ? peer->recvPacket(packet) : true; } + virtual bool recvPacket(EthPacketPtr packet) = 0; +}; + +#endif // __DEV_ETHERINT_HH__ diff --git a/src/dev/etherlink.cc b/src/dev/etherlink.cc new file mode 100644 index 000000000..5b6531c2e --- /dev/null +++ b/src/dev/etherlink.cc @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* @file + * Device module for modelling a fixed bandwidth full duplex ethernet link + */ + +#include <cmath> +#include <deque> +#include <string> +#include <vector> + +#include "base/random.hh" +#include "base/trace.hh" +#include "dev/etherdump.hh" +#include "dev/etherint.hh" +#include "dev/etherlink.hh" +#include "dev/etherpkt.hh" +#include "sim/builder.hh" +#include "sim/serialize.hh" +#include "sim/system.hh" +#include "sim/root.hh" + +using namespace std; + +EtherLink::EtherLink(const string &name, EtherInt *peer0, EtherInt *peer1, + double rate, Tick delay, Tick delayVar, EtherDump *dump) + : SimObject(name) +{ + link[0] = new Link(name + ".link0", this, 0, rate, delay, delayVar, dump); + link[1] = new Link(name + ".link1", this, 1, rate, delay, delayVar, dump); + + interface[0] = new Interface(name + ".int0", link[0], link[1]); + interface[1] = new Interface(name + ".int1", link[1], link[0]); + + interface[0]->setPeer(peer0); + peer0->setPeer(interface[0]); + interface[1]->setPeer(peer1); + peer1->setPeer(interface[1]); +} + +EtherLink::~EtherLink() +{ + delete link[0]; + delete link[1]; + + delete interface[0]; + delete interface[1]; +} + +EtherLink::Interface::Interface(const string &name, Link *tx, Link *rx) + : EtherInt(name), txlink(tx) +{ + tx->setTxInt(this); + rx->setRxInt(this); +} + +EtherLink::Link::Link(const string &name, EtherLink *p, int num, + double rate, Tick delay, Tick delay_var, EtherDump *d) + : objName(name), parent(p), number(num), txint(NULL), rxint(NULL), + ticksPerByte(rate), linkDelay(delay), delayVar(delay_var), dump(d), + doneEvent(this) +{ } + +void +EtherLink::serialize(ostream &os) +{ + link[0]->serialize("link0", os); + link[1]->serialize("link1", os); +} + +void +EtherLink::unserialize(Checkpoint *cp, const string §ion) +{ + link[0]->unserialize("link0", cp, section); + link[1]->unserialize("link1", cp, section); +} + +void +EtherLink::Link::txComplete(EthPacketPtr packet) +{ + DPRINTF(Ethernet, "packet received: len=%d\n", packet->length); + DDUMP(EthernetData, packet->data, packet->length); + rxint->sendPacket(packet); +} + +class LinkDelayEvent : public Event +{ + protected: + EtherLink::Link *link; + EthPacketPtr packet; + + public: + // non-scheduling version for createForUnserialize() + LinkDelayEvent(); + LinkDelayEvent(EtherLink::Link *link, EthPacketPtr pkt, Tick when); + + void process(); + + virtual void serialize(ostream &os); + virtual void unserialize(Checkpoint *cp, const string §ion); + static Serializable *createForUnserialize(Checkpoint *cp, + const string §ion); +}; + +void +EtherLink::Link::txDone() +{ + if (dump) + dump->dump(packet); + + if (linkDelay > 0) { + DPRINTF(Ethernet, "packet delayed: delay=%d\n", linkDelay); + new LinkDelayEvent(this, packet, curTick + linkDelay); + } else { + txComplete(packet); + } + + packet = 0; + assert(!busy()); + + txint->sendDone(); +} + +bool +EtherLink::Link::transmit(EthPacketPtr pkt) +{ + if (busy()) { + DPRINTF(Ethernet, "packet not sent, link busy\n"); + return false; + } + + DPRINTF(Ethernet, "packet sent: len=%d\n", pkt->length); + DDUMP(EthernetData, pkt->data, pkt->length); + + packet = pkt; + Tick delay = (Tick)ceil(((double)pkt->length * ticksPerByte) + 1.0); + if (delayVar != 0) { + Random<Tick> var; + delay += var.uniform(0, delayVar); + } + DPRINTF(Ethernet, "scheduling packet: delay=%d, (rate=%f)\n", + delay, ticksPerByte); + doneEvent.schedule(curTick + delay); + + return true; +} + +void +EtherLink::Link::serialize(const string &base, ostream &os) +{ + bool packet_exists = packet; + paramOut(os, base + ".packet_exists", packet_exists); + if (packet_exists) + packet->serialize(base + ".packet", os); + + bool event_scheduled = doneEvent.scheduled(); + paramOut(os, base + ".event_scheduled", event_scheduled); + if (event_scheduled) { + Tick event_time = doneEvent.when(); + paramOut(os, base + ".event_time", event_time); + } + +} + +void +EtherLink::Link::unserialize(const string &base, Checkpoint *cp, + const string §ion) +{ + bool packet_exists; + paramIn(cp, section, base + ".packet_exists", packet_exists); + if (packet_exists) { + packet = new EthPacketData(16384); + packet->unserialize(base + ".packet", cp, section); + } + + bool event_scheduled; + paramIn(cp, section, base + ".event_scheduled", event_scheduled); + if (event_scheduled) { + Tick event_time; + paramIn(cp, section, base + ".event_time", event_time); + doneEvent.schedule(event_time); + } +} + +LinkDelayEvent::LinkDelayEvent() + : Event(&mainEventQueue), link(NULL) +{ + setFlags(AutoSerialize); + setFlags(AutoDelete); +} + +LinkDelayEvent::LinkDelayEvent(EtherLink::Link *l, EthPacketPtr p, Tick when) + : Event(&mainEventQueue), link(l), packet(p) +{ + setFlags(AutoSerialize); + setFlags(AutoDelete); + schedule(when); +} + +void +LinkDelayEvent::process() +{ + link->txComplete(packet); +} + +void +LinkDelayEvent::serialize(ostream &os) +{ + paramOut(os, "type", string("LinkDelayEvent")); + Event::serialize(os); + + EtherLink *parent = link->parent; + bool number = link->number; + SERIALIZE_OBJPTR(parent); + SERIALIZE_SCALAR(number); + + packet->serialize("packet", os); +} + + +void +LinkDelayEvent::unserialize(Checkpoint *cp, const string §ion) +{ + Event::unserialize(cp, section); + + EtherLink *parent; + bool number; + UNSERIALIZE_OBJPTR(parent); + UNSERIALIZE_SCALAR(number); + + link = parent->link[number]; + + packet = new EthPacketData(16384); + packet->unserialize("packet", cp, section); +} + + +Serializable * +LinkDelayEvent::createForUnserialize(Checkpoint *cp, const string §ion) +{ + return new LinkDelayEvent(); +} + +REGISTER_SERIALIZEABLE("LinkDelayEvent", LinkDelayEvent) + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherLink) + + SimObjectParam<EtherInt *> int1; + SimObjectParam<EtherInt *> int2; + Param<double> speed; + Param<Tick> delay; + Param<Tick> delay_var; + SimObjectParam<EtherDump *> dump; + +END_DECLARE_SIM_OBJECT_PARAMS(EtherLink) + +BEGIN_INIT_SIM_OBJECT_PARAMS(EtherLink) + + INIT_PARAM(int1, "interface 1"), + INIT_PARAM(int2, "interface 2"), + INIT_PARAM(speed, "link speed in bits per second"), + INIT_PARAM(delay, "transmit delay of packets in us"), + INIT_PARAM(delay_var, "Difference in amount of time to traverse wire"), + INIT_PARAM(dump, "object to dump network packets to") + +END_INIT_SIM_OBJECT_PARAMS(EtherLink) + +CREATE_SIM_OBJECT(EtherLink) +{ + return new EtherLink(getInstanceName(), int1, int2, speed, delay, delay_var, + dump); +} + +REGISTER_SIM_OBJECT("EtherLink", EtherLink) diff --git a/src/dev/etherlink.hh b/src/dev/etherlink.hh new file mode 100644 index 000000000..570444e1b --- /dev/null +++ b/src/dev/etherlink.hh @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* @file + * Device module for modelling a fixed bandwidth full duplex ethernet link + */ + +#ifndef __DEV_ETHERLINK_HH__ +#define __DEV_ETHERLINK_HH__ + +#include "dev/etherint.hh" +#include "dev/etherpkt.hh" +#include "sim/eventq.hh" +#include "sim/host.hh" +#include "sim/sim_object.hh" + +class EtherDump; +class Checkpoint; +/* + * Model for a fixed bandwidth full duplex ethernet link + */ +class EtherLink : public SimObject +{ + protected: + class Interface; + + friend class LinkDelayEvent; + /* + * Model for a single uni-directional link + */ + class Link + { + protected: + std::string objName; + + EtherLink *parent; + int number; + + Interface *txint; + Interface *rxint; + + double ticksPerByte; + Tick linkDelay; + Tick delayVar; + EtherDump *dump; + + protected: + /* + * Transfer is complete + */ + EthPacketPtr packet; + void txDone(); + typedef EventWrapper<Link, &Link::txDone> DoneEvent; + friend void DoneEvent::process(); + DoneEvent doneEvent; + + friend class LinkDelayEvent; + void txComplete(EthPacketPtr packet); + + public: + Link(const std::string &name, EtherLink *p, int num, + double rate, Tick delay, Tick delay_var, EtherDump *dump); + ~Link() {} + + const std::string name() const { return objName; } + + bool busy() const { return (bool)packet; } + bool transmit(EthPacketPtr packet); + + void setTxInt(Interface *i) { assert(!txint); txint = i; } + void setRxInt(Interface *i) { assert(!rxint); rxint = i; } + + void serialize(const std::string &base, std::ostream &os); + void unserialize(const std::string &base, Checkpoint *cp, + const std::string §ion); + }; + + /* + * Interface at each end of the link + */ + class Interface : public EtherInt + { + private: + Link *txlink; + + public: + Interface(const std::string &name, Link *txlink, Link *rxlink); + bool recvPacket(EthPacketPtr packet) { return txlink->transmit(packet); } + void sendDone() { peer->sendDone(); } + }; + + Link *link[2]; + EtherInt *interface[2]; + + public: + EtherLink(const std::string &name, EtherInt *peer0, EtherInt *peer1, + double rate, Tick delay, Tick delayVar, EtherDump *dump); + virtual ~EtherLink(); + + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); + +}; + +#endif // __ETHERLINK_HH__ diff --git a/src/dev/etherpkt.cc b/src/dev/etherpkt.cc new file mode 100644 index 000000000..85e18e981 --- /dev/null +++ b/src/dev/etherpkt.cc @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <iostream> + +#include "base/misc.hh" +#include "dev/etherpkt.hh" +#include "sim/serialize.hh" + +using namespace std; + +void +EthPacketData::serialize(const string &base, ostream &os) +{ + paramOut(os, base + ".length", length); + paramOut(os, base + ".slack", slack); + arrayParamOut(os, base + ".data", data, length); +} + +void +EthPacketData::unserialize(const string &base, Checkpoint *cp, + const string §ion) +{ + paramIn(cp, section, base + ".length", length); + paramIn(cp, section, base + ".slack", slack); + if (length) + arrayParamIn(cp, section, base + ".data", data, length); +} diff --git a/src/dev/etherpkt.hh b/src/dev/etherpkt.hh new file mode 100644 index 000000000..01741b3d5 --- /dev/null +++ b/src/dev/etherpkt.hh @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* @file + * Reference counted class containing ethernet packet data + */ + +#ifndef __ETHERPKT_HH__ +#define __ETHERPKT_HH__ + +#include <iosfwd> +#include <memory> +#include <assert.h> + +#include "base/refcnt.hh" +#include "sim/host.hh" + +/* + * Reference counted class containing ethernet packet data + */ +class Checkpoint; +class EthPacketData : public RefCounted +{ + public: + /* + * Pointer to packet data will be deleted + */ + uint8_t *data; + + /* + * Length of the current packet + */ + int length; + + /* + * Extra space taken up by the packet in whatever data structure + * it is in. + * + * NOTE: This can only be use by *one* data structure at a time! + */ + int slack; + + public: + EthPacketData() : data(NULL), length(0), slack(0) { } + explicit EthPacketData(size_t size) + : data(new uint8_t[size]), length(0), slack(0) { } + EthPacketData(std::auto_ptr<uint8_t> d, int l, int s = 0) + : data(d.release()), length(l), slack(s) { } + ~EthPacketData() { if (data) delete [] data; } + + public: + void serialize(const std::string &base, std::ostream &os); + void unserialize(const std::string &base, Checkpoint *cp, + const std::string §ion); +}; + +typedef RefCountingPtr<EthPacketData> EthPacketPtr; + +#endif // __ETHERPKT_HH__ diff --git a/src/dev/ethertap.cc b/src/dev/ethertap.cc new file mode 100644 index 000000000..b5abb1d62 --- /dev/null +++ b/src/dev/ethertap.cc @@ -0,0 +1,345 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* @file + * Interface to connect a simulated ethernet device to the real world + */ + +#if defined(__OpenBSD__) || defined(__APPLE__) +#include <sys/param.h> +#endif +#include <netinet/in.h> + +#include <unistd.h> + +#include <deque> +#include <string> + +#include "base/misc.hh" +#include "base/pollevent.hh" +#include "base/socket.hh" +#include "base/trace.hh" +#include "dev/etherdump.hh" +#include "dev/etherint.hh" +#include "dev/etherpkt.hh" +#include "dev/ethertap.hh" +#include "sim/builder.hh" + +using namespace std; + +/** + */ +class TapListener +{ + protected: + /** + */ + class Event : public PollEvent + { + protected: + TapListener *listener; + + public: + Event(TapListener *l, int fd, int e) + : PollEvent(fd, e), listener(l) {} + + virtual void process(int revent) { listener->accept(); } + }; + + friend class Event; + Event *event; + + protected: + ListenSocket listener; + EtherTap *tap; + int port; + + public: + TapListener(EtherTap *t, int p) + : event(NULL), tap(t), port(p) {} + ~TapListener() { if (event) delete event; } + + void accept(); + void listen(); +}; + +void +TapListener::listen() +{ + while (!listener.listen(port, true)) { + DPRINTF(Ethernet, "TapListener(listen): Can't bind port %d\n", port); + port++; + } + + ccprintf(cerr, "Listening for tap connection on port %d\n", port); + event = new Event(this, listener.getfd(), POLLIN|POLLERR); + pollQueue.schedule(event); +} + +void +TapListener::accept() +{ + if (!listener.islistening()) + panic("TapListener(accept): cannot accept if we're not listening!"); + + int sfd = listener.accept(true); + if (sfd != -1) + tap->attach(sfd); +} + +/** + */ +class TapEvent : public PollEvent +{ + protected: + EtherTap *tap; + + public: + TapEvent(EtherTap *_tap, int fd, int e) + : PollEvent(fd, e), tap(_tap) {} + virtual void process(int revent) { tap->process(revent); } +}; + +EtherTap::EtherTap(const string &name, EtherDump *d, int port, int bufsz) + : EtherInt(name), event(NULL), socket(-1), buflen(bufsz), dump(d), + txEvent(this) +{ + buffer = new char[buflen]; + listener = new TapListener(this, port); + listener->listen(); +} + +EtherTap::~EtherTap() +{ + if (event) + delete event; + if (buffer) + delete [] buffer; + + delete listener; +} + +void +EtherTap::attach(int fd) +{ + if (socket != -1) + close(fd); + + buffer_offset = 0; + data_len = 0; + socket = fd; + DPRINTF(Ethernet, "EtherTap attached\n"); + event = new TapEvent(this, socket, POLLIN|POLLERR); + pollQueue.schedule(event); +} + +void +EtherTap::detach() +{ + DPRINTF(Ethernet, "EtherTap detached\n"); + delete event; + event = 0; + close(socket); + socket = -1; +} + +bool +EtherTap::recvPacket(EthPacketPtr packet) +{ + if (dump) + dump->dump(packet); + + DPRINTF(Ethernet, "EtherTap output len=%d\n", packet->length); + DDUMP(EthernetData, packet->data, packet->length); + u_int32_t len = htonl(packet->length); + write(socket, &len, sizeof(len)); + write(socket, packet->data, packet->length); + + recvDone(); + + return true; +} + +void +EtherTap::sendDone() +{} + +void +EtherTap::process(int revent) +{ + if (revent & POLLERR) { + detach(); + return; + } + + char *data = buffer + sizeof(u_int32_t); + if (!(revent & POLLIN)) + return; + + if (buffer_offset < data_len + sizeof(u_int32_t)) { + int len = read(socket, buffer + buffer_offset, buflen - buffer_offset); + if (len == 0) { + detach(); + return; + } + + buffer_offset += len; + + if (data_len == 0) + data_len = ntohl(*(u_int32_t *)buffer); + + DPRINTF(Ethernet, "Received data from peer: len=%d buffer_offset=%d " + "data_len=%d\n", len, buffer_offset, data_len); + } + + while (data_len != 0 && buffer_offset >= data_len + sizeof(u_int32_t)) { + EthPacketPtr packet; + packet = new EthPacketData(data_len); + packet->length = data_len; + memcpy(packet->data, data, data_len); + + buffer_offset -= data_len + sizeof(u_int32_t); + assert(buffer_offset >= 0); + if (buffer_offset > 0) { + memmove(buffer, data + data_len, buffer_offset); + data_len = ntohl(*(u_int32_t *)buffer); + } else + data_len = 0; + + DPRINTF(Ethernet, "EtherTap input len=%d\n", packet->length); + DDUMP(EthernetData, packet->data, packet->length); + if (!sendPacket(packet)) { + DPRINTF(Ethernet, "bus busy...buffer for retransmission\n"); + packetBuffer.push(packet); + if (!txEvent.scheduled()) + txEvent.schedule(curTick + retryTime); + } else if (dump) { + dump->dump(packet); + } + } +} + +void +EtherTap::retransmit() +{ + if (packetBuffer.empty()) + return; + + EthPacketPtr packet = packetBuffer.front(); + if (sendPacket(packet)) { + if (dump) + dump->dump(packet); + DPRINTF(Ethernet, "EtherTap retransmit\n"); + packetBuffer.front() = NULL; + packetBuffer.pop(); + } + + if (!packetBuffer.empty() && !txEvent.scheduled()) + txEvent.schedule(curTick + retryTime); +} + +//===================================================================== + +void +EtherTap::serialize(ostream &os) +{ + SERIALIZE_SCALAR(socket); + SERIALIZE_SCALAR(buflen); + uint8_t *buffer = (uint8_t *)this->buffer; + SERIALIZE_ARRAY(buffer, buflen); + SERIALIZE_SCALAR(buffer_offset); + SERIALIZE_SCALAR(data_len); + + bool tapevent_present = false; + if (event) { + tapevent_present = true; + SERIALIZE_SCALAR(tapevent_present); + event->serialize(os); + } + else { + SERIALIZE_SCALAR(tapevent_present); + } +} + +void +EtherTap::unserialize(Checkpoint *cp, const std::string §ion) +{ + UNSERIALIZE_SCALAR(socket); + UNSERIALIZE_SCALAR(buflen); + uint8_t *buffer = (uint8_t *)this->buffer; + UNSERIALIZE_ARRAY(buffer, buflen); + UNSERIALIZE_SCALAR(buffer_offset); + UNSERIALIZE_SCALAR(data_len); + + bool tapevent_present; + UNSERIALIZE_SCALAR(tapevent_present); + if (tapevent_present) { + event = new TapEvent(this, socket, POLLIN|POLLERR); + + event->unserialize(cp,section); + + if (event->queued()) { + pollQueue.schedule(event); + } + } +} + +//===================================================================== + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherTap) + + SimObjectParam<EtherInt *> peer; + SimObjectParam<EtherDump *> dump; + Param<unsigned> port; + Param<unsigned> bufsz; + +END_DECLARE_SIM_OBJECT_PARAMS(EtherTap) + +BEGIN_INIT_SIM_OBJECT_PARAMS(EtherTap) + + INIT_PARAM_DFLT(peer, "peer interface", NULL), + INIT_PARAM_DFLT(dump, "object to dump network packets to", NULL), + INIT_PARAM_DFLT(port, "tap port", 3500), + INIT_PARAM_DFLT(bufsz, "tap buffer size", 10000) + +END_INIT_SIM_OBJECT_PARAMS(EtherTap) + + +CREATE_SIM_OBJECT(EtherTap) +{ + EtherTap *tap = new EtherTap(getInstanceName(), dump, port, bufsz); + + if (peer) { + tap->setPeer(peer); + peer->setPeer(tap); + } + + return tap; +} + +REGISTER_SIM_OBJECT("EtherTap", EtherTap) diff --git a/src/dev/ethertap.hh b/src/dev/ethertap.hh new file mode 100644 index 000000000..40ce6af0b --- /dev/null +++ b/src/dev/ethertap.hh @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* @file + * Interface to connect a simulated ethernet device to the real world + */ + +#ifndef __ETHERTAP_HH__ +#define __ETHERTAP_HH__ + +#include <queue> +#include <string> + +#include "dev/etherint.hh" +#include "dev/etherpkt.hh" +#include "sim/eventq.hh" +#include "base/pollevent.hh" +#include "sim/sim_object.hh" + +class TapEvent; +class TapListener; + +/* + * Interface to connect a simulated ethernet device to the real world + */ +class EtherTap : public EtherInt +{ + protected: + friend class TapEvent; + TapEvent *event; + + protected: + friend class TapListener; + TapListener *listener; + int socket; + char *buffer; + int buflen; + int32_t buffer_offset; + int32_t data_len; + + EtherDump *dump; + + void attach(int fd); + void detach(); + + protected: + std::string device; + std::queue<EthPacketPtr> packetBuffer; + + void process(int revent); + void enqueue(EthPacketData *packet); + void retransmit(); + + /* + */ + class TxEvent : public Event + { + protected: + EtherTap *tap; + + public: + TxEvent(EtherTap *_tap) + : Event(&mainEventQueue), tap(_tap) {} + void process() { tap->retransmit(); } + virtual const char *description() { return "retransmit event"; } + }; + + friend class TxEvent; + TxEvent txEvent; + + public: + EtherTap(const std::string &name, EtherDump *dump, int port, int bufsz); + virtual ~EtherTap(); + + virtual bool recvPacket(EthPacketPtr packet); + virtual void sendDone(); + + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); +}; + +#endif // __ETHERTAP_HH__ diff --git a/dev/ide_atareg.h b/src/dev/ide_atareg.h index 5320529c8..5320529c8 100644 --- a/dev/ide_atareg.h +++ b/src/dev/ide_atareg.h diff --git a/src/dev/ide_ctrl.cc b/src/dev/ide_ctrl.cc new file mode 100644 index 000000000..eb03d5db8 --- /dev/null +++ b/src/dev/ide_ctrl.cc @@ -0,0 +1,814 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <cstddef> +#include <cstdlib> +#include <string> +#include <vector> + +#include "base/trace.hh" +#include "cpu/intr_control.hh" +#include "dev/ide_ctrl.hh" +#include "dev/ide_disk.hh" +#include "dev/pciconfigall.hh" +#include "dev/pcireg.h" +#include "dev/platform.hh" +#include "mem/packet.hh" +#include "sim/builder.hh" +#include "sim/sim_object.hh" +#include "sim/byteswap.hh" + +using namespace std; + +//// +// Initialization and destruction +//// + +IdeController::IdeController(Params *p) + : PciDev(p) +{ + // initialize the PIO interface addresses + pri_cmd_addr = 0; + pri_cmd_size = BARSize[0]; + + pri_ctrl_addr = 0; + pri_ctrl_size = BARSize[1]; + + sec_cmd_addr = 0; + sec_cmd_size = BARSize[2]; + + sec_ctrl_addr = 0; + sec_ctrl_size = BARSize[3]; + + // initialize the bus master interface (BMI) address to be configured + // via PCI + bmi_addr = 0; + bmi_size = BARSize[4]; + + // zero out all of the registers + memset(bmi_regs.data, 0, sizeof(bmi_regs)); + memset(config_regs.data, 0, sizeof(config_regs.data)); + + // setup initial values + // enable both channels + config_regs.idetim0 = htole((uint16_t)IDETIM_DECODE_EN); + config_regs.idetim1 = htole((uint16_t)IDETIM_DECODE_EN); + bmi_regs.bmis0 = DMA1CAP | DMA0CAP; + bmi_regs.bmis1 = DMA1CAP | DMA0CAP; + + // reset all internal variables + io_enabled = false; + bm_enabled = false; + memset(cmd_in_progress, 0, sizeof(cmd_in_progress)); + + // setup the disks attached to controller + memset(disks, 0, sizeof(disks)); + dev[0] = 0; + dev[1] = 0; + + if (params()->disks.size() > 3) + panic("IDE controllers support a maximum of 4 devices attached!\n"); + + for (int i = 0; i < params()->disks.size(); i++) { + disks[i] = params()->disks[i]; + disks[i]->setController(this); + } +} + +IdeController::~IdeController() +{ + for (int i = 0; i < 4; i++) + if (disks[i]) + delete disks[i]; +} + +//// +// Utility functions +/// + +void +IdeController::parseAddr(const Addr &addr, Addr &offset, IdeChannel &channel, + IdeRegType ®_type) +{ + offset = addr; + + if (addr >= pri_cmd_addr && addr < (pri_cmd_addr + pri_cmd_size)) { + offset -= pri_cmd_addr; + reg_type = COMMAND_BLOCK; + channel = PRIMARY; + } else if (addr >= pri_ctrl_addr && + addr < (pri_ctrl_addr + pri_ctrl_size)) { + offset -= pri_ctrl_addr; + reg_type = CONTROL_BLOCK; + channel = PRIMARY; + } else if (addr >= sec_cmd_addr && + addr < (sec_cmd_addr + sec_cmd_size)) { + offset -= sec_cmd_addr; + reg_type = COMMAND_BLOCK; + channel = SECONDARY; + } else if (addr >= sec_ctrl_addr && + addr < (sec_ctrl_addr + sec_ctrl_size)) { + offset -= sec_ctrl_addr; + reg_type = CONTROL_BLOCK; + channel = SECONDARY; + } else if (addr >= bmi_addr && addr < (bmi_addr + bmi_size)) { + offset -= bmi_addr; + reg_type = BMI_BLOCK; + channel = (offset < BMIC1) ? PRIMARY : SECONDARY; + } else { + panic("IDE controller access to invalid address: %#x\n", addr); + } +} + +int +IdeController::getDisk(IdeChannel channel) +{ + int disk = 0; + uint8_t *devBit = &dev[0]; + + if (channel == SECONDARY) { + disk += 2; + devBit = &dev[1]; + } + + disk += *devBit; + + assert(*devBit == 0 || *devBit == 1); + + return disk; +} + +int +IdeController::getDisk(IdeDisk *diskPtr) +{ + for (int i = 0; i < 4; i++) { + if ((long)diskPtr == (long)disks[i]) + return i; + } + return -1; +} + +bool +IdeController::isDiskSelected(IdeDisk *diskPtr) +{ + for (int i = 0; i < 4; i++) { + if ((long)diskPtr == (long)disks[i]) { + // is disk is on primary or secondary channel + int channel = i/2; + // is disk the master or slave + int devID = i%2; + + return (dev[channel] == devID); + } + } + panic("Unable to find disk by pointer!!\n"); +} + +//// +// Command completion +//// + +void +IdeController::setDmaComplete(IdeDisk *disk) +{ + int diskNum = getDisk(disk); + + if (diskNum < 0) + panic("Unable to find disk based on pointer %#x\n", disk); + + if (diskNum < 2) { + // clear the start/stop bit in the command register + bmi_regs.bmic0 &= ~SSBM; + // clear the bus master active bit in the status register + bmi_regs.bmis0 &= ~BMIDEA; + // set the interrupt bit + bmi_regs.bmis0 |= IDEINTS; + } else { + // clear the start/stop bit in the command register + bmi_regs.bmic1 &= ~SSBM; + // clear the bus master active bit in the status register + bmi_regs.bmis1 &= ~BMIDEA; + // set the interrupt bit + bmi_regs.bmis1 |= IDEINTS; + } +} + + +//// +// Read and write handling +//// + +void +IdeController::readConfig(int offset, uint8_t *data) +{ + if (offset < PCI_DEVICE_SPECIFIC) { + PciDev::readConfig(offset, data); + } else if (offset >= IDE_CTRL_CONF_START && + (offset + 1) <= IDE_CTRL_CONF_END) { + + switch (offset) { + case IDE_CTRL_CONF_DEV_TIMING: + *data = config_regs.sidetim; + break; + case IDE_CTRL_CONF_UDMA_CNTRL: + *data = config_regs.udmactl; + break; + case IDE_CTRL_CONF_PRIM_TIMING+1: + *data = htole(config_regs.idetim0) >> 8; + break; + case IDE_CTRL_CONF_SEC_TIMING+1: + *data = htole(config_regs.idetim1) >> 8; + break; + case IDE_CTRL_CONF_IDE_CONFIG: + *data = htole(config_regs.ideconfig) & 0xFF; + break; + case IDE_CTRL_CONF_IDE_CONFIG+1: + *data = htole(config_regs.ideconfig) >> 8; + break; + default: + panic("Invalid PCI configuration read for size 1 at offset: %#x!\n", + offset); + } + + } else { + panic("Read of unimplemented PCI config. register: %x\n", offset); + } + DPRINTF(IdeCtrl, "PCI read offset: %#x size: 1 data: %#x\n", + offset, (uint32_t)*data); +} + +void +IdeController::readConfig(int offset, uint16_t *data) +{ + if (offset < PCI_DEVICE_SPECIFIC) { + PciDev::readConfig(offset, data); + } else if (offset >= IDE_CTRL_CONF_START && + (offset + 2) <= IDE_CTRL_CONF_END) { + + switch (offset) { + case IDE_CTRL_CONF_PRIM_TIMING: + *data = config_regs.idetim0; + break; + case IDE_CTRL_CONF_SEC_TIMING: + *data = config_regs.idetim1; + break; + case IDE_CTRL_CONF_UDMA_TIMING: + *data = config_regs.udmatim; + break; + case IDE_CTRL_CONF_IDE_CONFIG: + *data = config_regs.ideconfig; + break; + default: + panic("Invalid PCI configuration read for size 2 offset: %#x!\n", + offset); + } + + } else { + panic("Read of unimplemented PCI config. register: %x\n", offset); + } + DPRINTF(IdeCtrl, "PCI read offset: %#x size: 2 data: %#x\n", offset, *data); +} + +void +IdeController::readConfig(int offset, uint32_t *data) +{ + if (offset < PCI_DEVICE_SPECIFIC) { + PciDev::readConfig(offset, data); + } else { + panic("Read of unimplemented PCI config. register: %x\n", offset); + } + DPRINTF(IdeCtrl, "PCI read offset: %#x size: 4 data: %#x\n", offset, *data); +} +void +IdeController::writeConfig(int offset, const uint8_t data) +{ + if (offset < PCI_DEVICE_SPECIFIC) { + PciDev::writeConfig(offset, data); + } else if (offset >= IDE_CTRL_CONF_START && + (offset + 1) <= IDE_CTRL_CONF_END) { + + switch (offset) { + case IDE_CTRL_CONF_DEV_TIMING: + config_regs.sidetim = data; + break; + case IDE_CTRL_CONF_UDMA_CNTRL: + config_regs.udmactl = data; + break; + case IDE_CTRL_CONF_IDE_CONFIG: + config_regs.ideconfig = (config_regs.ideconfig & 0xFF00) | (data); + break; + case IDE_CTRL_CONF_IDE_CONFIG+1: + config_regs.ideconfig = (config_regs.ideconfig & 0x00FF) | data << 8; + break; + default: + panic("Invalid PCI configuration write for size 1 offset: %#x!\n", + offset); + } + + } else { + panic("Read of unimplemented PCI config. register: %x\n", offset); + } + DPRINTF(IdeCtrl, "PCI write offset: %#x size: 1 data: %#x\n", + offset, (uint32_t)data); +} + +void +IdeController::writeConfig(int offset, const uint16_t data) +{ + if (offset < PCI_DEVICE_SPECIFIC) { + PciDev::writeConfig(offset, data); + } else if (offset >= IDE_CTRL_CONF_START && + (offset + 2) <= IDE_CTRL_CONF_END) { + + switch (offset) { + case IDE_CTRL_CONF_PRIM_TIMING: + config_regs.idetim0 = data; + break; + case IDE_CTRL_CONF_SEC_TIMING: + config_regs.idetim1 = data; + break; + case IDE_CTRL_CONF_UDMA_TIMING: + config_regs.udmatim = data; + break; + case IDE_CTRL_CONF_IDE_CONFIG: + config_regs.ideconfig = data; + break; + default: + panic("Invalid PCI configuration write for size 2 offset: %#x!\n", + offset); + } + + } else { + panic("Write of unimplemented PCI config. register: %x\n", offset); + } + DPRINTF(IdeCtrl, "PCI write offset: %#x size: 2 data: %#x\n", offset, data); + + /* Trap command register writes and enable IO/BM as appropriate. */ + if (offset == PCI_COMMAND) { + if (letoh(config.command) & PCI_CMD_IOSE) + io_enabled = true; + else + io_enabled = false; + + if (letoh(config.command) & PCI_CMD_BME) + bm_enabled = true; + else + bm_enabled = false; + } + +} + +void +IdeController::writeConfig(int offset, const uint32_t data) +{ + if (offset < PCI_DEVICE_SPECIFIC) { + PciDev::writeConfig(offset, data); + } else { + panic("Read of unimplemented PCI config. register: %x\n", offset); + } + + DPRINTF(IdeCtrl, "PCI write offset: %#x size: 4 data: %#x\n", offset, data); + + switch(offset) { + case PCI0_BASE_ADDR0: + if (BARAddrs[0] != 0) + pri_cmd_addr = BARAddrs[0]; + break; + + case PCI0_BASE_ADDR1: + if (BARAddrs[1] != 0) + pri_ctrl_addr = BARAddrs[1]; + break; + + case PCI0_BASE_ADDR2: + if (BARAddrs[2] != 0) + sec_cmd_addr = BARAddrs[2]; + break; + + case PCI0_BASE_ADDR3: + if (BARAddrs[3] != 0) + sec_ctrl_addr = BARAddrs[3]; + break; + + case PCI0_BASE_ADDR4: + if (BARAddrs[4] != 0) + bmi_addr = BARAddrs[4]; + break; + } +} + +Tick +IdeController::read(Packet *pkt) +{ + Addr offset; + IdeChannel channel; + IdeRegType reg_type; + int disk; + + pkt->time += pioDelay; + pkt->allocate(); + if (pkt->getSize() != 1 && pkt->getSize() != 2 && pkt->getSize() !=4) + panic("Bad IDE read size: %d\n", pkt->getSize()); + + parseAddr(pkt->getAddr(), offset, channel, reg_type); + + if (!io_enabled) { + pkt->result = Packet::Success; + return pioDelay; + } + + switch (reg_type) { + case BMI_BLOCK: + switch (pkt->getSize()) { + case sizeof(uint8_t): + pkt->set(bmi_regs.data[offset]); + break; + case sizeof(uint16_t): + pkt->set(*(uint16_t*)&bmi_regs.data[offset]); + break; + case sizeof(uint32_t): + pkt->set(*(uint32_t*)&bmi_regs.data[offset]); + break; + default: + panic("IDE read of BMI reg invalid size: %#x\n", pkt->getSize()); + } + break; + + case COMMAND_BLOCK: + case CONTROL_BLOCK: + disk = getDisk(channel); + + if (disks[disk] == NULL) { + pkt->set<uint8_t>(0); + break; + } + + switch (offset) { + case DATA_OFFSET: + switch (pkt->getSize()) { + case sizeof(uint16_t): + disks[disk]->read(offset, reg_type, pkt->getPtr<uint8_t>()); + break; + + case sizeof(uint32_t): + disks[disk]->read(offset, reg_type, pkt->getPtr<uint8_t>()); + disks[disk]->read(offset, reg_type, + pkt->getPtr<uint8_t>() + sizeof(uint16_t)); + break; + + default: + panic("IDE read of data reg invalid size: %#x\n", pkt->getSize()); + } + break; + default: + if (pkt->getSize() == sizeof(uint8_t)) { + disks[disk]->read(offset, reg_type, pkt->getPtr<uint8_t>()); + } else + panic("IDE read of command reg of invalid size: %#x\n", pkt->getSize()); + } + break; + default: + panic("IDE controller read of unknown register block type!\n"); + } + if (pkt->getSize() == 1) + DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n", + offset, pkt->getSize(), (uint32_t)pkt->get<uint8_t>()); + else if (pkt->getSize() == 2) + DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n", + offset, pkt->getSize(), pkt->get<uint16_t>()); + else + DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n", + offset, pkt->getSize(), pkt->get<uint32_t>()); + + pkt->result = Packet::Success; + return pioDelay; +} + +Tick +IdeController::write(Packet *pkt) +{ + Addr offset; + IdeChannel channel; + IdeRegType reg_type; + int disk; + uint8_t oldVal, newVal; + + pkt->time += pioDelay; + + parseAddr(pkt->getAddr(), offset, channel, reg_type); + + if (!io_enabled) { + pkt->result = Packet::Success; + DPRINTF(IdeCtrl, "io not enabled\n"); + return pioDelay; + } + + switch (reg_type) { + case BMI_BLOCK: + if (!bm_enabled) { + pkt->result = Packet::Success; + return pioDelay; + } + + switch (offset) { + // Bus master IDE command register + case BMIC1: + case BMIC0: + if (pkt->getSize() != sizeof(uint8_t)) + panic("Invalid BMIC write size: %x\n", pkt->getSize()); + + // select the current disk based on DEV bit + disk = getDisk(channel); + + oldVal = bmi_regs.chan[channel].bmic; + newVal = pkt->get<uint8_t>(); + + // if a DMA transfer is in progress, R/W control cannot change + if (oldVal & SSBM) { + if ((oldVal & RWCON) ^ (newVal & RWCON)) { + (oldVal & RWCON) ? newVal |= RWCON : newVal &= ~RWCON; + } + } + + // see if the start/stop bit is being changed + if ((oldVal & SSBM) ^ (newVal & SSBM)) { + if (oldVal & SSBM) { + // stopping DMA transfer + DPRINTF(IdeCtrl, "Stopping DMA transfer\n"); + + // clear the BMIDEA bit + bmi_regs.chan[channel].bmis = + bmi_regs.chan[channel].bmis & ~BMIDEA; + + if (disks[disk] == NULL) + panic("DMA stop for disk %d which does not exist\n", + disk); + + // inform the disk of the DMA transfer abort + disks[disk]->abortDma(); + } else { + // starting DMA transfer + DPRINTF(IdeCtrl, "Starting DMA transfer\n"); + + // set the BMIDEA bit + bmi_regs.chan[channel].bmis = + bmi_regs.chan[channel].bmis | BMIDEA; + + if (disks[disk] == NULL) + panic("DMA start for disk %d which does not exist\n", + disk); + + // inform the disk of the DMA transfer start + disks[disk]->startDma(letoh(bmi_regs.chan[channel].bmidtp)); + } + } + + // update the register value + bmi_regs.chan[channel].bmic = newVal; + break; + + // Bus master IDE status register + case BMIS0: + case BMIS1: + if (pkt->getSize() != sizeof(uint8_t)) + panic("Invalid BMIS write size: %x\n", pkt->getSize()); + + oldVal = bmi_regs.chan[channel].bmis; + newVal = pkt->get<uint8_t>(); + + // the BMIDEA bit is RO + newVal |= (oldVal & BMIDEA); + + // to reset (set 0) IDEINTS and IDEDMAE, write 1 to each + if ((oldVal & IDEINTS) && (newVal & IDEINTS)) + newVal &= ~IDEINTS; // clear the interrupt? + else + (oldVal & IDEINTS) ? newVal |= IDEINTS : newVal &= ~IDEINTS; + + if ((oldVal & IDEDMAE) && (newVal & IDEDMAE)) + newVal &= ~IDEDMAE; + else + (oldVal & IDEDMAE) ? newVal |= IDEDMAE : newVal &= ~IDEDMAE; + + bmi_regs.chan[channel].bmis = newVal; + break; + + // Bus master IDE descriptor table pointer register + case BMIDTP0: + case BMIDTP1: + { + if (pkt->getSize() != sizeof(uint32_t)) + panic("Invalid BMIDTP write size: %x\n", pkt->getSize()); + + bmi_regs.chan[channel].bmidtp = htole(pkt->get<uint32_t>() & ~0x3); + } + break; + + default: + if (pkt->getSize() != sizeof(uint8_t) && + pkt->getSize() != sizeof(uint16_t) && + pkt->getSize() != sizeof(uint32_t)) + panic("IDE controller write of invalid write size: %x\n", + pkt->getSize()); + + // do a default copy of data into the registers + memcpy(&bmi_regs.data[offset], pkt->getPtr<uint8_t>(), pkt->getSize()); + } + break; + case COMMAND_BLOCK: + if (offset == IDE_SELECT_OFFSET) { + uint8_t *devBit = &dev[channel]; + *devBit = (letoh(pkt->get<uint8_t>()) & IDE_SELECT_DEV_BIT) ? 1 : 0; + } + // fall-through ok! + case CONTROL_BLOCK: + disk = getDisk(channel); + + if (disks[disk] == NULL) + break; + + switch (offset) { + case DATA_OFFSET: + switch (pkt->getSize()) { + case sizeof(uint16_t): + disks[disk]->write(offset, reg_type, pkt->getPtr<uint8_t>()); + break; + + case sizeof(uint32_t): + disks[disk]->write(offset, reg_type, pkt->getPtr<uint8_t>()); + disks[disk]->write(offset, reg_type, pkt->getPtr<uint8_t>() + + sizeof(uint16_t)); + break; + default: + panic("IDE write of data reg invalid size: %#x\n", pkt->getSize()); + } + break; + default: + if (pkt->getSize() == sizeof(uint8_t)) { + disks[disk]->write(offset, reg_type, pkt->getPtr<uint8_t>()); + } else + panic("IDE write of command reg of invalid size: %#x\n", pkt->getSize()); + } + break; + default: + panic("IDE controller write of unknown register block type!\n"); + } + + if (pkt->getSize() == 1) + DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n", + offset, pkt->getSize(), (uint32_t)pkt->get<uint8_t>()); + else if (pkt->getSize() == 2) + DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n", + offset, pkt->getSize(), pkt->get<uint16_t>()); + else + DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n", + offset, pkt->getSize(), pkt->get<uint32_t>()); + + + pkt->result = Packet::Success; + return pioDelay; +} + +//// +// Serialization +//// + +void +IdeController::serialize(std::ostream &os) +{ + // Serialize the PciDev base class + PciDev::serialize(os); + + // Serialize register addresses and sizes + SERIALIZE_SCALAR(pri_cmd_addr); + SERIALIZE_SCALAR(pri_cmd_size); + SERIALIZE_SCALAR(pri_ctrl_addr); + SERIALIZE_SCALAR(pri_ctrl_size); + SERIALIZE_SCALAR(sec_cmd_addr); + SERIALIZE_SCALAR(sec_cmd_size); + SERIALIZE_SCALAR(sec_ctrl_addr); + SERIALIZE_SCALAR(sec_ctrl_size); + SERIALIZE_SCALAR(bmi_addr); + SERIALIZE_SCALAR(bmi_size); + + // Serialize registers + SERIALIZE_ARRAY(bmi_regs.data, + sizeof(bmi_regs.data) / sizeof(bmi_regs.data[0])); + SERIALIZE_ARRAY(dev, sizeof(dev) / sizeof(dev[0])); + SERIALIZE_ARRAY(config_regs.data, + sizeof(config_regs.data) / sizeof(config_regs.data[0])); + + // Serialize internal state + SERIALIZE_SCALAR(io_enabled); + SERIALIZE_SCALAR(bm_enabled); + SERIALIZE_ARRAY(cmd_in_progress, + sizeof(cmd_in_progress) / sizeof(cmd_in_progress[0])); +} + +void +IdeController::unserialize(Checkpoint *cp, const std::string §ion) +{ + // Unserialize the PciDev base class + PciDev::unserialize(cp, section); + + // Unserialize register addresses and sizes + UNSERIALIZE_SCALAR(pri_cmd_addr); + UNSERIALIZE_SCALAR(pri_cmd_size); + UNSERIALIZE_SCALAR(pri_ctrl_addr); + UNSERIALIZE_SCALAR(pri_ctrl_size); + UNSERIALIZE_SCALAR(sec_cmd_addr); + UNSERIALIZE_SCALAR(sec_cmd_size); + UNSERIALIZE_SCALAR(sec_ctrl_addr); + UNSERIALIZE_SCALAR(sec_ctrl_size); + UNSERIALIZE_SCALAR(bmi_addr); + UNSERIALIZE_SCALAR(bmi_size); + + // Unserialize registers + UNSERIALIZE_ARRAY(bmi_regs.data, + sizeof(bmi_regs.data) / sizeof(bmi_regs.data[0])); + UNSERIALIZE_ARRAY(dev, sizeof(dev) / sizeof(dev[0])); + UNSERIALIZE_ARRAY(config_regs.data, + sizeof(config_regs.data) / sizeof(config_regs.data[0])); + + // Unserialize internal state + UNSERIALIZE_SCALAR(io_enabled); + UNSERIALIZE_SCALAR(bm_enabled); + UNSERIALIZE_ARRAY(cmd_in_progress, + sizeof(cmd_in_progress) / sizeof(cmd_in_progress[0])); + pioPort->sendStatusChange(Port::RangeChange); +} + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(IdeController) + + SimObjectParam<System *> system; + SimObjectParam<Platform *> platform; + SimObjectParam<PciConfigAll *> configspace; + SimObjectParam<PciConfigData *> configdata; + Param<uint32_t> pci_bus; + Param<uint32_t> pci_dev; + Param<uint32_t> pci_func; + Param<Tick> pio_latency; + SimObjectVectorParam<IdeDisk *> disks; + +END_DECLARE_SIM_OBJECT_PARAMS(IdeController) + +BEGIN_INIT_SIM_OBJECT_PARAMS(IdeController) + + INIT_PARAM(system, "System pointer"), + INIT_PARAM(platform, "Platform pointer"), + INIT_PARAM(configspace, "PCI Configspace"), + INIT_PARAM(configdata, "PCI Config data"), + INIT_PARAM(pci_bus, "PCI bus ID"), + INIT_PARAM(pci_dev, "PCI device number"), + INIT_PARAM(pci_func, "PCI function code"), + INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1), + INIT_PARAM(disks, "IDE disks attached to this controller") + +END_INIT_SIM_OBJECT_PARAMS(IdeController) + +CREATE_SIM_OBJECT(IdeController) +{ + IdeController::Params *params = new IdeController::Params; + params->name = getInstanceName(); + params->platform = platform; + params->system = system; + params->configSpace = configspace; + params->configData = configdata; + params->busNum = pci_bus; + params->deviceNum = pci_dev; + params->functionNum = pci_func; + params->pio_delay = pio_latency; + params->disks = disks; + return new IdeController(params); +} + +REGISTER_SIM_OBJECT("IdeController", IdeController) + +#endif //DOXYGEN_SHOULD_SKIP_THIS diff --git a/src/dev/ide_ctrl.hh b/src/dev/ide_ctrl.hh new file mode 100644 index 000000000..dda2cbb66 --- /dev/null +++ b/src/dev/ide_ctrl.hh @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file + * Simple PCI IDE controller with bus mastering capability and UDMA + * modeled after controller in the Intel PIIX4 chip + */ + +#ifndef __IDE_CTRL_HH__ +#define __IDE_CTRL_HH__ + +#include "dev/pcidev.hh" +#include "dev/pcireg.h" +#include "dev/io_device.hh" + +#define BMIC0 0x0 // Bus master IDE command register +#define BMIS0 0x2 // Bus master IDE status register +#define BMIDTP0 0x4 // Bus master IDE descriptor table pointer register +#define BMIC1 0x8 // Bus master IDE command register +#define BMIS1 0xa // Bus master IDE status register +#define BMIDTP1 0xc // Bus master IDE descriptor table pointer register + +// Bus master IDE command register bit fields +#define RWCON 0x08 // Bus master read/write control +#define SSBM 0x01 // Start/stop bus master + +// Bus master IDE status register bit fields +#define DMA1CAP 0x40 // Drive 1 DMA capable +#define DMA0CAP 0x20 // Drive 0 DMA capable +#define IDEINTS 0x04 // IDE Interrupt Status +#define IDEDMAE 0x02 // IDE DMA error +#define BMIDEA 0x01 // Bus master IDE active + +// IDE Command byte fields +#define IDE_SELECT_OFFSET (6) +#define IDE_SELECT_DEV_BIT 0x10 + +#define IDE_FEATURE_OFFSET IDE_ERROR_OFFSET +#define IDE_COMMAND_OFFSET IDE_STATUS_OFFSET + +// IDE Timing Register bit fields +#define IDETIM_DECODE_EN 0x8000 + +// PCI device specific register byte offsets +#define IDE_CTRL_CONF_START 0x40 +#define IDE_CTRL_CONF_END ((IDE_CTRL_CONF_START) + sizeof(config_regs)) + +#define IDE_CTRL_CONF_PRIM_TIMING 0x40 +#define IDE_CTRL_CONF_SEC_TIMING 0x42 +#define IDE_CTRL_CONF_DEV_TIMING 0x44 +#define IDE_CTRL_CONF_UDMA_CNTRL 0x48 +#define IDE_CTRL_CONF_UDMA_TIMING 0x4A +#define IDE_CTRL_CONF_IDE_CONFIG 0x54 + + +enum IdeRegType { + COMMAND_BLOCK, + CONTROL_BLOCK, + BMI_BLOCK +}; + +class IdeDisk; +class IntrControl; +class PciConfigAll; +class Platform; + +/** + * Device model for an Intel PIIX4 IDE controller + */ + +class IdeController : public PciDev +{ + friend class IdeDisk; + + enum IdeChannel { + PRIMARY = 0, + SECONDARY = 1 + }; + + private: + /** Primary command block registers */ + Addr pri_cmd_addr; + Addr pri_cmd_size; + /** Primary control block registers */ + Addr pri_ctrl_addr; + Addr pri_ctrl_size; + /** Secondary command block registers */ + Addr sec_cmd_addr; + Addr sec_cmd_size; + /** Secondary control block registers */ + Addr sec_ctrl_addr; + Addr sec_ctrl_size; + /** Bus master interface (BMI) registers */ + Addr bmi_addr; + Addr bmi_size; + + private: + /** Registers used for bus master interface */ + union { + uint8_t data[16]; + + struct { + uint8_t bmic0; + uint8_t reserved_0; + uint8_t bmis0; + uint8_t reserved_1; + uint32_t bmidtp0; + uint8_t bmic1; + uint8_t reserved_2; + uint8_t bmis1; + uint8_t reserved_3; + uint32_t bmidtp1; + }; + + struct { + uint8_t bmic; + uint8_t reserved_4; + uint8_t bmis; + uint8_t reserved_5; + uint32_t bmidtp; + } chan[2]; + + } bmi_regs; + /** Shadows of the device select bit */ + uint8_t dev[2]; + /** Registers used in device specific PCI configuration */ + union { + uint8_t data[22]; + + struct { + uint16_t idetim0; + uint16_t idetim1; + uint8_t sidetim; + uint8_t reserved_0[3]; + uint8_t udmactl; + uint8_t reserved_1; + uint16_t udmatim; + uint8_t reserved_2[8]; + uint16_t ideconfig; + }; + } config_regs; + + // Internal management variables + bool io_enabled; + bool bm_enabled; + bool cmd_in_progress[4]; + + private: + /** IDE disks connected to controller */ + IdeDisk *disks[4]; + + private: + /** Parse the access address to pass on to device */ + void parseAddr(const Addr &addr, Addr &offset, IdeChannel &channel, + IdeRegType ®_type); + + /** Select the disk based on the channel and device bit */ + int getDisk(IdeChannel channel); + + /** Select the disk based on a pointer */ + int getDisk(IdeDisk *diskPtr); + + public: + /** See if a disk is selected based on its pointer */ + bool isDiskSelected(IdeDisk *diskPtr); + + public: + struct Params : public PciDev::Params + { + /** Array of disk objects */ + std::vector<IdeDisk *> disks; + }; + const Params *params() const { return (const Params *)_params; } + + public: + IdeController(Params *p); + ~IdeController(); + + virtual void writeConfig(int offset, const uint8_t data); + virtual void writeConfig(int offset, const uint16_t data); + virtual void writeConfig(int offset, const uint32_t data); + virtual void readConfig(int offset, uint8_t *data); + virtual void readConfig(int offset, uint16_t *data); + virtual void readConfig(int offset, uint32_t *data); + + void setDmaComplete(IdeDisk *disk); + + /** + * Read a done field for a given target. + * @param pkt Packet describing what is to be read + * @return The amount of time to complete this request + */ + virtual Tick read(Packet *pkt); + + /** + * Write a done field for a given target. + * @param pkt Packet describing what is to be written + * @return The amount of time to complete this request + */ + virtual Tick write(Packet *pkt); + + /** + * Serialize this object to the given output stream. + * @param os The stream to serialize to. + */ + virtual void serialize(std::ostream &os); + + /** + * Reconstruct the state of this object from a checkpoint. + * @param cp The checkpoint use. + * @param section The section name of this object + */ + virtual void unserialize(Checkpoint *cp, const std::string §ion); + +}; +#endif // __IDE_CTRL_HH_ diff --git a/src/dev/ide_disk.cc b/src/dev/ide_disk.cc new file mode 100644 index 000000000..909f35c60 --- /dev/null +++ b/src/dev/ide_disk.cc @@ -0,0 +1,1146 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file + * Device model implementation for an IDE disk + */ + +#include <cerrno> +#include <cstring> +#include <deque> +#include <string> + +#include "base/chunk_generator.hh" +#include "base/cprintf.hh" // csprintf +#include "base/trace.hh" +#include "dev/disk_image.hh" +#include "dev/ide_disk.hh" +#include "dev/ide_ctrl.hh" +#include "dev/tsunami.hh" +#include "dev/tsunami_pchip.hh" +#include "sim/builder.hh" +#include "sim/sim_object.hh" +#include "sim/root.hh" +#include "arch/isa_traits.hh" + +using namespace std; +using namespace TheISA; + +IdeDisk::IdeDisk(const string &name, DiskImage *img, + int id, Tick delay) + : SimObject(name), ctrl(NULL), image(img), diskDelay(delay), + dmaTransferEvent(this), dmaReadCG(NULL), dmaReadWaitEvent(this), + dmaWriteCG(NULL), dmaWriteWaitEvent(this), dmaPrdReadEvent(this), + dmaReadEvent(this), dmaWriteEvent(this) +{ + // Reset the device state + reset(id); + + // fill out the drive ID structure + memset(&driveID, 0, sizeof(struct ataparams)); + + // Calculate LBA and C/H/S values + uint16_t cylinders; + uint8_t heads; + uint8_t sectors; + + uint32_t lba_size = image->size(); + if (lba_size >= 16383*16*63) { + cylinders = 16383; + heads = 16; + sectors = 63; + } else { + if (lba_size >= 63) + sectors = 63; + else + sectors = lba_size; + + if ((lba_size / sectors) >= 16) + heads = 16; + else + heads = (lba_size / sectors); + + cylinders = lba_size / (heads * sectors); + } + + // Setup the model name + strncpy((char *)driveID.atap_model, "5MI EDD si k", + sizeof(driveID.atap_model)); + // Set the maximum multisector transfer size + driveID.atap_multi = MAX_MULTSECT; + // IORDY supported, IORDY disabled, LBA enabled, DMA enabled + driveID.atap_capabilities1 = 0x7; + // UDMA support, EIDE support + driveID.atap_extensions = 0x6; + // Setup default C/H/S settings + driveID.atap_cylinders = cylinders; + driveID.atap_sectors = sectors; + driveID.atap_heads = heads; + // Setup the current multisector transfer size + driveID.atap_curmulti = MAX_MULTSECT; + driveID.atap_curmulti_valid = 0x1; + // Number of sectors on disk + driveID.atap_capacity = lba_size; + // Multiword DMA mode 2 and below supported + driveID.atap_dmamode_supp = 0x400; + // Set PIO mode 4 and 3 supported + driveID.atap_piomode_supp = 0x3; + // Set DMA mode 4 and below supported + driveID.atap_udmamode_supp = 0x1f; + // Statically set hardware config word + driveID.atap_hwreset_res = 0x4001; + + //arbitrary for now... + driveID.atap_ata_major = WDC_VER_ATA7; +} + +IdeDisk::~IdeDisk() +{ + // destroy the data buffer + delete [] dataBuffer; +} + +void +IdeDisk::reset(int id) +{ + // initialize the data buffer and shadow registers + dataBuffer = new uint8_t[MAX_DMA_SIZE]; + + memset(dataBuffer, 0, MAX_DMA_SIZE); + memset(&cmdReg, 0, sizeof(CommandReg_t)); + memset(&curPrd.entry, 0, sizeof(PrdEntry_t)); + + curPrdAddr = 0; + curSector = 0; + cmdBytes = 0; + cmdBytesLeft = 0; + drqBytesLeft = 0; + dmaRead = false; + intrPending = false; + + // set the device state to idle + dmaState = Dma_Idle; + + if (id == DEV0) { + devState = Device_Idle_S; + devID = DEV0; + } else if (id == DEV1) { + devState = Device_Idle_NS; + devID = DEV1; + } else { + panic("Invalid device ID: %#x\n", id); + } + + // set the device ready bit + status = STATUS_DRDY_BIT; + + /* The error register must be set to 0x1 on start-up to + indicate that no diagnostic error was detected */ + cmdReg.error = 0x1; +} + +//// +// Utility functions +//// + +bool +IdeDisk::isDEVSelect() +{ + return ctrl->isDiskSelected(this); +} + +Addr +IdeDisk::pciToDma(Addr pciAddr) +{ + if (ctrl) + return ctrl->plat->pciToDma(pciAddr); + else + panic("Access to unset controller!\n"); +} + +//// +// Device registers read/write +//// + +void +IdeDisk::read(const Addr &offset, IdeRegType reg_type, uint8_t *data) +{ + DevAction_t action = ACT_NONE; + + switch (reg_type) { + case COMMAND_BLOCK: + switch (offset) { + // Data transfers occur two bytes at a time + case DATA_OFFSET: + *(uint16_t*)data = cmdReg.data; + action = ACT_DATA_READ_SHORT; + break; + case ERROR_OFFSET: + *data = cmdReg.error; + break; + case NSECTOR_OFFSET: + *data = cmdReg.sec_count; + break; + case SECTOR_OFFSET: + *data = cmdReg.sec_num; + break; + case LCYL_OFFSET: + *data = cmdReg.cyl_low; + break; + case HCYL_OFFSET: + *data = cmdReg.cyl_high; + break; + case DRIVE_OFFSET: + *data = cmdReg.drive; + break; + case STATUS_OFFSET: + *data = status; + action = ACT_STAT_READ; + break; + default: + panic("Invalid IDE command register offset: %#x\n", offset); + } + break; + case CONTROL_BLOCK: + if (offset == ALTSTAT_OFFSET) + *data = status; + else + panic("Invalid IDE control register offset: %#x\n", offset); + break; + default: + panic("Unknown register block!\n"); + } + DPRINTF(IdeDisk, "Read to disk at offset: %#x data %#x\n", offset, + (uint32_t)*data); + + if (action != ACT_NONE) + updateState(action); +} + +void +IdeDisk::write(const Addr &offset, IdeRegType reg_type, const uint8_t *data) +{ + DevAction_t action = ACT_NONE; + + switch (reg_type) { + case COMMAND_BLOCK: + switch (offset) { + case DATA_OFFSET: + cmdReg.data = *(uint16_t*)data; + action = ACT_DATA_WRITE_SHORT; + break; + case FEATURES_OFFSET: + break; + case NSECTOR_OFFSET: + cmdReg.sec_count = *data; + break; + case SECTOR_OFFSET: + cmdReg.sec_num = *data; + break; + case LCYL_OFFSET: + cmdReg.cyl_low = *data; + break; + case HCYL_OFFSET: + cmdReg.cyl_high = *data; + break; + case DRIVE_OFFSET: + cmdReg.drive = *data; + action = ACT_SELECT_WRITE; + break; + case COMMAND_OFFSET: + cmdReg.command = *data; + action = ACT_CMD_WRITE; + break; + default: + panic("Invalid IDE command register offset: %#x\n", offset); + } + break; + case CONTROL_BLOCK: + if (offset == CONTROL_OFFSET) { + if (*data & CONTROL_RST_BIT) { + // force the device into the reset state + devState = Device_Srst; + action = ACT_SRST_SET; + } else if (devState == Device_Srst && !(*data & CONTROL_RST_BIT)) + action = ACT_SRST_CLEAR; + + nIENBit = (*data & CONTROL_IEN_BIT) ? true : false; + } + else + panic("Invalid IDE control register offset: %#x\n", offset); + break; + default: + panic("Unknown register block!\n"); + } + + DPRINTF(IdeDisk, "Write to disk at offset: %#x data %#x\n", offset, + (uint32_t)*data); + if (action != ACT_NONE) + updateState(action); +} + +//// +// Perform DMA transactions +//// + +void +IdeDisk::doDmaTransfer() +{ + if (dmaState != Dma_Transfer || devState != Transfer_Data_Dma) + panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n", + dmaState, devState); + + if (ctrl->dmaPending()) { + dmaTransferEvent.schedule(curTick + DMA_BACKOFF_PERIOD); + return; + } else + ctrl->dmaRead(curPrdAddr, sizeof(PrdEntry_t), &dmaPrdReadEvent, + (uint8_t*)&curPrd.entry); +} + +void +IdeDisk::dmaPrdReadDone() +{ + DPRINTF(IdeDisk, + "PRD: baseAddr:%#x (%#x) byteCount:%d (%d) eot:%#x sector:%d\n", + curPrd.getBaseAddr(), pciToDma(curPrd.getBaseAddr()), + curPrd.getByteCount(), (cmdBytesLeft/SectorSize), + curPrd.getEOT(), curSector); + + // the prd pointer has already been translated, so just do an increment + curPrdAddr = curPrdAddr + sizeof(PrdEntry_t); + + if (dmaRead) + doDmaDataRead(); + else + doDmaDataWrite(); +} + +void +IdeDisk::doDmaDataRead() +{ + /** @todo we need to figure out what the delay actually will be */ + Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize); + + DPRINTF(IdeDisk, "doDmaRead, diskDelay: %d totalDiskDelay: %d\n", + diskDelay, totalDiskDelay); + + dmaReadWaitEvent.schedule(curTick + totalDiskDelay); +} + +void +IdeDisk::regStats() +{ + using namespace Stats; + dmaReadFullPages + .name(name() + ".dma_read_full_pages") + .desc("Number of full page size DMA reads (not PRD).") + ; + dmaReadBytes + .name(name() + ".dma_read_bytes") + .desc("Number of bytes transfered via DMA reads (not PRD).") + ; + dmaReadTxs + .name(name() + ".dma_read_txs") + .desc("Number of DMA read transactions (not PRD).") + ; + + dmaWriteFullPages + .name(name() + ".dma_write_full_pages") + .desc("Number of full page size DMA writes.") + ; + dmaWriteBytes + .name(name() + ".dma_write_bytes") + .desc("Number of bytes transfered via DMA writes.") + ; + dmaWriteTxs + .name(name() + ".dma_write_txs") + .desc("Number of DMA write transactions.") + ; +} + +void +IdeDisk::doDmaRead() +{ + + if (!dmaReadCG) { + // clear out the data buffer + memset(dataBuffer, 0, MAX_DMA_SIZE); + dmaReadCG = new ChunkGenerator(curPrd.getBaseAddr(), + curPrd.getByteCount(), TheISA::PageBytes); + + } + if (ctrl->dmaPending()) { + panic("shouldn't be reentant??"); + dmaReadWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD); + return; + } else if (!dmaReadCG->done()) { + assert(dmaReadCG->complete() < MAX_DMA_SIZE); + ctrl->dmaRead(pciToDma(dmaReadCG->addr()), dmaReadCG->size(), + &dmaReadWaitEvent, dataBuffer + dmaReadCG->complete()); + dmaReadBytes += dmaReadCG->size(); + dmaReadTxs++; + if (dmaReadCG->size() == TheISA::PageBytes) + dmaReadFullPages++; + dmaReadCG->next(); + } else { + assert(dmaReadCG->done()); + delete dmaReadCG; + dmaReadCG = NULL; + dmaReadDone(); + } +} + +void +IdeDisk::dmaReadDone() +{ + + uint32_t bytesWritten = 0; + + + // write the data to the disk image + for (bytesWritten = 0; bytesWritten < curPrd.getByteCount(); + bytesWritten += SectorSize) { + + cmdBytesLeft -= SectorSize; + writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten)); + } + + // check for the EOT + if (curPrd.getEOT()) { + assert(cmdBytesLeft == 0); + dmaState = Dma_Idle; + updateState(ACT_DMA_DONE); + } else { + doDmaTransfer(); + } +} + +void +IdeDisk::doDmaDataWrite() +{ + /** @todo we need to figure out what the delay actually will be */ + Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize); + uint32_t bytesRead = 0; + + DPRINTF(IdeDisk, "doDmaWrite, diskDelay: %d totalDiskDelay: %d\n", + diskDelay, totalDiskDelay); + + memset(dataBuffer, 0, MAX_DMA_SIZE); + assert(cmdBytesLeft <= MAX_DMA_SIZE); + while (bytesRead < curPrd.getByteCount()) { + readDisk(curSector++, (uint8_t *)(dataBuffer + bytesRead)); + bytesRead += SectorSize; + cmdBytesLeft -= SectorSize; + } + + dmaWriteWaitEvent.schedule(curTick + totalDiskDelay); +} + +void +IdeDisk::doDmaWrite() +{ + + if (!dmaWriteCG) { + // clear out the data buffer + dmaWriteCG = new ChunkGenerator(curPrd.getBaseAddr(), + curPrd.getByteCount(), TheISA::PageBytes); + } + if (ctrl->dmaPending()) { + panic("shouldn't be reentant??"); + dmaWriteWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD); + return; + } else if (!dmaWriteCG->done()) { + assert(dmaWriteCG->complete() < MAX_DMA_SIZE); + ctrl->dmaWrite(pciToDma(dmaWriteCG->addr()), dmaWriteCG->size(), + &dmaWriteWaitEvent, dataBuffer + dmaWriteCG->complete()); + dmaWriteBytes += dmaWriteCG->size(); + dmaWriteTxs++; + if (dmaWriteCG->size() == TheISA::PageBytes) + dmaWriteFullPages++; + dmaWriteCG->next(); + } else { + assert(dmaWriteCG->done()); + delete dmaWriteCG; + dmaWriteCG = NULL; + dmaWriteDone(); + } +} + +void +IdeDisk::dmaWriteDone() +{ + // check for the EOT + if (curPrd.getEOT()) { + assert(cmdBytesLeft == 0); + dmaState = Dma_Idle; + updateState(ACT_DMA_DONE); + } else { + doDmaTransfer(); + } +} + +//// +// Disk utility routines +/// + +void +IdeDisk::readDisk(uint32_t sector, uint8_t *data) +{ + uint32_t bytesRead = image->read(data, sector); + + if (bytesRead != SectorSize) + panic("Can't read from %s. Only %d of %d read. errno=%d\n", + name(), bytesRead, SectorSize, errno); +} + +void +IdeDisk::writeDisk(uint32_t sector, uint8_t *data) +{ + uint32_t bytesWritten = image->write(data, sector); + + if (bytesWritten != SectorSize) + panic("Can't write to %s. Only %d of %d written. errno=%d\n", + name(), bytesWritten, SectorSize, errno); +} + +//// +// Setup and handle commands +//// + +void +IdeDisk::startDma(const uint32_t &prdTableBase) +{ + if (dmaState != Dma_Start) + panic("Inconsistent DMA state, should be in Dma_Start!\n"); + + if (devState != Transfer_Data_Dma) + panic("Inconsistent device state for DMA start!\n"); + + // PRD base address is given by bits 31:2 + curPrdAddr = pciToDma((Addr)(prdTableBase & ~ULL(0x3))); + + dmaState = Dma_Transfer; + + // schedule dma transfer (doDmaTransfer) + dmaTransferEvent.schedule(curTick + 1); +} + +void +IdeDisk::abortDma() +{ + if (dmaState == Dma_Idle) + panic("Inconsistent DMA state, should be Start or Transfer!"); + + if (devState != Transfer_Data_Dma && devState != Prepare_Data_Dma) + panic("Inconsistent device state, should be Transfer or Prepare!\n"); + + updateState(ACT_CMD_ERROR); +} + +void +IdeDisk::startCommand() +{ + DevAction_t action = ACT_NONE; + uint32_t size = 0; + dmaRead = false; + + // Decode commands + switch (cmdReg.command) { + // Supported non-data commands + case WDSF_READ_NATIVE_MAX: + size = image->size() - 1; + cmdReg.sec_num = (size & 0xff); + cmdReg.cyl_low = ((size & 0xff00) >> 8); + cmdReg.cyl_high = ((size & 0xff0000) >> 16); + cmdReg.head = ((size & 0xf000000) >> 24); + + devState = Command_Execution; + action = ACT_CMD_COMPLETE; + break; + + case WDCC_RECAL: + case WDCC_IDP: + case WDCC_STANDBY_IMMED: + case WDCC_FLUSHCACHE: + case WDSF_VERIFY: + case WDSF_SEEK: + case SET_FEATURES: + case WDCC_SETMULTI: + devState = Command_Execution; + action = ACT_CMD_COMPLETE; + break; + + // Supported PIO data-in commands + case WDCC_IDENTIFY: + cmdBytes = cmdBytesLeft = sizeof(struct ataparams); + devState = Prepare_Data_In; + action = ACT_DATA_READY; + break; + + case WDCC_READMULTI: + case WDCC_READ: + if (!(cmdReg.drive & DRIVE_LBA_BIT)) + panic("Attempt to perform CHS access, only supports LBA\n"); + + if (cmdReg.sec_count == 0) + cmdBytes = cmdBytesLeft = (256 * SectorSize); + else + cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize); + + curSector = getLBABase(); + + /** @todo make this a scheduled event to simulate disk delay */ + devState = Prepare_Data_In; + action = ACT_DATA_READY; + break; + + // Supported PIO data-out commands + case WDCC_WRITEMULTI: + case WDCC_WRITE: + if (!(cmdReg.drive & DRIVE_LBA_BIT)) + panic("Attempt to perform CHS access, only supports LBA\n"); + + if (cmdReg.sec_count == 0) + cmdBytes = cmdBytesLeft = (256 * SectorSize); + else + cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize); + + curSector = getLBABase(); + + devState = Prepare_Data_Out; + action = ACT_DATA_READY; + break; + + // Supported DMA commands + case WDCC_WRITEDMA: + dmaRead = true; // a write to the disk is a DMA read from memory + case WDCC_READDMA: + if (!(cmdReg.drive & DRIVE_LBA_BIT)) + panic("Attempt to perform CHS access, only supports LBA\n"); + + if (cmdReg.sec_count == 0) + cmdBytes = cmdBytesLeft = (256 * SectorSize); + else + cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize); + + curSector = getLBABase(); + + devState = Prepare_Data_Dma; + action = ACT_DMA_READY; + break; + + default: + panic("Unsupported ATA command: %#x\n", cmdReg.command); + } + + if (action != ACT_NONE) { + // set the BSY bit + status |= STATUS_BSY_BIT; + // clear the DRQ bit + status &= ~STATUS_DRQ_BIT; + // clear the DF bit + status &= ~STATUS_DF_BIT; + + updateState(action); + } +} + +//// +// Handle setting and clearing interrupts +//// + +void +IdeDisk::intrPost() +{ + DPRINTF(IdeDisk, "Posting Interrupt\n"); + if (intrPending) + panic("Attempt to post an interrupt with one pending\n"); + + intrPending = true; + + // talk to controller to set interrupt + if (ctrl) { + ctrl->bmi_regs.bmis0 |= IDEINTS; + ctrl->intrPost(); + } +} + +void +IdeDisk::intrClear() +{ + DPRINTF(IdeDisk, "Clearing Interrupt\n"); + if (!intrPending) + panic("Attempt to clear a non-pending interrupt\n"); + + intrPending = false; + + // talk to controller to clear interrupt + if (ctrl) + ctrl->intrClear(); +} + +//// +// Manage the device internal state machine +//// + +void +IdeDisk::updateState(DevAction_t action) +{ + switch (devState) { + case Device_Srst: + if (action == ACT_SRST_SET) { + // set the BSY bit + status |= STATUS_BSY_BIT; + } else if (action == ACT_SRST_CLEAR) { + // clear the BSY bit + status &= ~STATUS_BSY_BIT; + + // reset the device state + reset(devID); + } + break; + + case Device_Idle_S: + if (action == ACT_SELECT_WRITE && !isDEVSelect()) { + devState = Device_Idle_NS; + } else if (action == ACT_CMD_WRITE) { + startCommand(); + } + + break; + + case Device_Idle_SI: + if (action == ACT_SELECT_WRITE && !isDEVSelect()) { + devState = Device_Idle_NS; + intrClear(); + } else if (action == ACT_STAT_READ || isIENSet()) { + devState = Device_Idle_S; + intrClear(); + } else if (action == ACT_CMD_WRITE) { + intrClear(); + startCommand(); + } + + break; + + case Device_Idle_NS: + if (action == ACT_SELECT_WRITE && isDEVSelect()) { + if (!isIENSet() && intrPending) { + devState = Device_Idle_SI; + intrPost(); + } + if (isIENSet() || !intrPending) { + devState = Device_Idle_S; + } + } + break; + + case Command_Execution: + if (action == ACT_CMD_COMPLETE) { + // clear the BSY bit + setComplete(); + + if (!isIENSet()) { + devState = Device_Idle_SI; + intrPost(); + } else { + devState = Device_Idle_S; + } + } + break; + + case Prepare_Data_In: + if (action == ACT_CMD_ERROR) { + // clear the BSY bit + setComplete(); + + if (!isIENSet()) { + devState = Device_Idle_SI; + intrPost(); + } else { + devState = Device_Idle_S; + } + } else if (action == ACT_DATA_READY) { + // clear the BSY bit + status &= ~STATUS_BSY_BIT; + // set the DRQ bit + status |= STATUS_DRQ_BIT; + + // copy the data into the data buffer + if (cmdReg.command == WDCC_IDENTIFY) { + // Reset the drqBytes for this block + drqBytesLeft = sizeof(struct ataparams); + + memcpy((void *)dataBuffer, (void *)&driveID, + sizeof(struct ataparams)); + } else { + // Reset the drqBytes for this block + drqBytesLeft = SectorSize; + + readDisk(curSector++, dataBuffer); + } + + // put the first two bytes into the data register + memcpy((void *)&cmdReg.data, (void *)dataBuffer, + sizeof(uint16_t)); + + if (!isIENSet()) { + devState = Data_Ready_INTRQ_In; + intrPost(); + } else { + devState = Transfer_Data_In; + } + } + break; + + case Data_Ready_INTRQ_In: + if (action == ACT_STAT_READ) { + devState = Transfer_Data_In; + intrClear(); + } + break; + + case Transfer_Data_In: + if (action == ACT_DATA_READ_BYTE || action == ACT_DATA_READ_SHORT) { + if (action == ACT_DATA_READ_BYTE) { + panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n"); + } else { + drqBytesLeft -= 2; + cmdBytesLeft -= 2; + + // copy next short into data registers + if (drqBytesLeft) + memcpy((void *)&cmdReg.data, + (void *)&dataBuffer[SectorSize - drqBytesLeft], + sizeof(uint16_t)); + } + + if (drqBytesLeft == 0) { + if (cmdBytesLeft == 0) { + // Clear the BSY bit + setComplete(); + devState = Device_Idle_S; + } else { + devState = Prepare_Data_In; + // set the BSY_BIT + status |= STATUS_BSY_BIT; + // clear the DRQ_BIT + status &= ~STATUS_DRQ_BIT; + + /** @todo change this to a scheduled event to simulate + disk delay */ + updateState(ACT_DATA_READY); + } + } + } + break; + + case Prepare_Data_Out: + if (action == ACT_CMD_ERROR || cmdBytesLeft == 0) { + // clear the BSY bit + setComplete(); + + if (!isIENSet()) { + devState = Device_Idle_SI; + intrPost(); + } else { + devState = Device_Idle_S; + } + } else if (action == ACT_DATA_READY && cmdBytesLeft != 0) { + // clear the BSY bit + status &= ~STATUS_BSY_BIT; + // set the DRQ bit + status |= STATUS_DRQ_BIT; + + // clear the data buffer to get it ready for writes + memset(dataBuffer, 0, MAX_DMA_SIZE); + + // reset the drqBytes for this block + drqBytesLeft = SectorSize; + + if (cmdBytesLeft == cmdBytes || isIENSet()) { + devState = Transfer_Data_Out; + } else { + devState = Data_Ready_INTRQ_Out; + intrPost(); + } + } + break; + + case Data_Ready_INTRQ_Out: + if (action == ACT_STAT_READ) { + devState = Transfer_Data_Out; + intrClear(); + } + break; + + case Transfer_Data_Out: + if (action == ACT_DATA_WRITE_BYTE || + action == ACT_DATA_WRITE_SHORT) { + + if (action == ACT_DATA_READ_BYTE) { + panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n"); + } else { + // copy the latest short into the data buffer + memcpy((void *)&dataBuffer[SectorSize - drqBytesLeft], + (void *)&cmdReg.data, + sizeof(uint16_t)); + + drqBytesLeft -= 2; + cmdBytesLeft -= 2; + } + + if (drqBytesLeft == 0) { + // copy the block to the disk + writeDisk(curSector++, dataBuffer); + + // set the BSY bit + status |= STATUS_BSY_BIT; + // set the seek bit + status |= STATUS_SEEK_BIT; + // clear the DRQ bit + status &= ~STATUS_DRQ_BIT; + + devState = Prepare_Data_Out; + + /** @todo change this to a scheduled event to simulate + disk delay */ + updateState(ACT_DATA_READY); + } + } + break; + + case Prepare_Data_Dma: + if (action == ACT_CMD_ERROR) { + // clear the BSY bit + setComplete(); + + if (!isIENSet()) { + devState = Device_Idle_SI; + intrPost(); + } else { + devState = Device_Idle_S; + } + } else if (action == ACT_DMA_READY) { + // clear the BSY bit + status &= ~STATUS_BSY_BIT; + // set the DRQ bit + status |= STATUS_DRQ_BIT; + + devState = Transfer_Data_Dma; + + if (dmaState != Dma_Idle) + panic("Inconsistent DMA state, should be Dma_Idle\n"); + + dmaState = Dma_Start; + // wait for the write to the DMA start bit + } + break; + + case Transfer_Data_Dma: + if (action == ACT_CMD_ERROR || action == ACT_DMA_DONE) { + // clear the BSY bit + setComplete(); + // set the seek bit + status |= STATUS_SEEK_BIT; + // clear the controller state for DMA transfer + ctrl->setDmaComplete(this); + + if (!isIENSet()) { + devState = Device_Idle_SI; + intrPost(); + } else { + devState = Device_Idle_S; + } + } + break; + + default: + panic("Unknown IDE device state: %#x\n", devState); + } +} + +void +IdeDisk::serialize(ostream &os) +{ + // Check all outstanding events to see if they are scheduled + // these are all mutually exclusive + Tick reschedule = 0; + Events_t event = None; + + int eventCount = 0; + + if (dmaTransferEvent.scheduled()) { + reschedule = dmaTransferEvent.when(); + event = Transfer; + eventCount++; + } + if (dmaReadWaitEvent.scheduled()) { + reschedule = dmaReadWaitEvent.when(); + event = ReadWait; + eventCount++; + } + if (dmaWriteWaitEvent.scheduled()) { + reschedule = dmaWriteWaitEvent.when(); + event = WriteWait; + eventCount++; + } + if (dmaPrdReadEvent.scheduled()) { + reschedule = dmaPrdReadEvent.when(); + event = PrdRead; + eventCount++; + } + if (dmaReadEvent.scheduled()) { + reschedule = dmaReadEvent.when(); + event = DmaRead; + eventCount++; + } + if (dmaWriteEvent.scheduled()) { + reschedule = dmaWriteEvent.when(); + event = DmaWrite; + eventCount++; + } + + assert(eventCount <= 1); + + SERIALIZE_SCALAR(reschedule); + SERIALIZE_ENUM(event); + + // Serialize device registers + SERIALIZE_SCALAR(cmdReg.data); + SERIALIZE_SCALAR(cmdReg.sec_count); + SERIALIZE_SCALAR(cmdReg.sec_num); + SERIALIZE_SCALAR(cmdReg.cyl_low); + SERIALIZE_SCALAR(cmdReg.cyl_high); + SERIALIZE_SCALAR(cmdReg.drive); + SERIALIZE_SCALAR(cmdReg.command); + SERIALIZE_SCALAR(status); + SERIALIZE_SCALAR(nIENBit); + SERIALIZE_SCALAR(devID); + + // Serialize the PRD related information + SERIALIZE_SCALAR(curPrd.entry.baseAddr); + SERIALIZE_SCALAR(curPrd.entry.byteCount); + SERIALIZE_SCALAR(curPrd.entry.endOfTable); + SERIALIZE_SCALAR(curPrdAddr); + + /** @todo need to serialized chunk generator stuff!! */ + // Serialize current transfer related information + SERIALIZE_SCALAR(cmdBytesLeft); + SERIALIZE_SCALAR(cmdBytes); + SERIALIZE_SCALAR(drqBytesLeft); + SERIALIZE_SCALAR(curSector); + SERIALIZE_SCALAR(dmaRead); + SERIALIZE_SCALAR(intrPending); + SERIALIZE_ENUM(devState); + SERIALIZE_ENUM(dmaState); + SERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE); +} + +void +IdeDisk::unserialize(Checkpoint *cp, const string §ion) +{ + // Reschedule events that were outstanding + // these are all mutually exclusive + Tick reschedule = 0; + Events_t event = None; + + UNSERIALIZE_SCALAR(reschedule); + UNSERIALIZE_ENUM(event); + + switch (event) { + case None : break; + case Transfer : dmaTransferEvent.schedule(reschedule); break; + case ReadWait : dmaReadWaitEvent.schedule(reschedule); break; + case WriteWait : dmaWriteWaitEvent.schedule(reschedule); break; + case PrdRead : dmaPrdReadEvent.schedule(reschedule); break; + case DmaRead : dmaReadEvent.schedule(reschedule); break; + case DmaWrite : dmaWriteEvent.schedule(reschedule); break; + } + + // Unserialize device registers + UNSERIALIZE_SCALAR(cmdReg.data); + UNSERIALIZE_SCALAR(cmdReg.sec_count); + UNSERIALIZE_SCALAR(cmdReg.sec_num); + UNSERIALIZE_SCALAR(cmdReg.cyl_low); + UNSERIALIZE_SCALAR(cmdReg.cyl_high); + UNSERIALIZE_SCALAR(cmdReg.drive); + UNSERIALIZE_SCALAR(cmdReg.command); + UNSERIALIZE_SCALAR(status); + UNSERIALIZE_SCALAR(nIENBit); + UNSERIALIZE_SCALAR(devID); + + // Unserialize the PRD related information + UNSERIALIZE_SCALAR(curPrd.entry.baseAddr); + UNSERIALIZE_SCALAR(curPrd.entry.byteCount); + UNSERIALIZE_SCALAR(curPrd.entry.endOfTable); + UNSERIALIZE_SCALAR(curPrdAddr); + + /** @todo need to serialized chunk generator stuff!! */ + // Unserialize current transfer related information + UNSERIALIZE_SCALAR(cmdBytes); + UNSERIALIZE_SCALAR(cmdBytesLeft); + UNSERIALIZE_SCALAR(drqBytesLeft); + UNSERIALIZE_SCALAR(curSector); + UNSERIALIZE_SCALAR(dmaRead); + UNSERIALIZE_SCALAR(intrPending); + UNSERIALIZE_ENUM(devState); + UNSERIALIZE_ENUM(dmaState); + UNSERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE); +} + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +enum DriveID { master, slave }; +static const char *DriveID_strings[] = { "master", "slave" }; +BEGIN_DECLARE_SIM_OBJECT_PARAMS(IdeDisk) + + SimObjectParam<DiskImage *> image; + SimpleEnumParam<DriveID> driveID; + Param<int> delay; + +END_DECLARE_SIM_OBJECT_PARAMS(IdeDisk) + +BEGIN_INIT_SIM_OBJECT_PARAMS(IdeDisk) + + INIT_PARAM(image, "Disk image"), + INIT_ENUM_PARAM(driveID, "Drive ID (0=master 1=slave)", DriveID_strings), + INIT_PARAM_DFLT(delay, "Fixed disk delay in microseconds", 1) + +END_INIT_SIM_OBJECT_PARAMS(IdeDisk) + + +CREATE_SIM_OBJECT(IdeDisk) +{ + return new IdeDisk(getInstanceName(), image, driveID, delay); +} + +REGISTER_SIM_OBJECT("IdeDisk", IdeDisk) + +#endif //DOXYGEN_SHOULD_SKIP_THIS diff --git a/src/dev/ide_disk.hh b/src/dev/ide_disk.hh new file mode 100644 index 000000000..5379e5e73 --- /dev/null +++ b/src/dev/ide_disk.hh @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file + * Device model for an IDE disk + */ + +#ifndef __IDE_DISK_HH__ +#define __IDE_DISK_HH__ + +#include "base/statistics.hh" +#include "dev/disk_image.hh" +#include "dev/ide_atareg.h" +#include "dev/ide_ctrl.hh" +#include "dev/ide_wdcreg.h" +#include "dev/io_device.hh" +#include "sim/eventq.hh" + +#define DMA_BACKOFF_PERIOD 200 + +#define MAX_DMA_SIZE (131072) // 128K +#define MAX_MULTSECT (128) + +#define PRD_BASE_MASK 0xfffffffe +#define PRD_COUNT_MASK 0xfffe +#define PRD_EOT_MASK 0x8000 + +typedef struct PrdEntry { + uint32_t baseAddr; + uint16_t byteCount; + uint16_t endOfTable; +} PrdEntry_t; + +class PrdTableEntry { + public: + PrdEntry_t entry; + + uint32_t getBaseAddr() + { + return (entry.baseAddr & PRD_BASE_MASK); + } + + uint32_t getByteCount() + { + return ((entry.byteCount == 0) ? MAX_DMA_SIZE : + (entry.byteCount & PRD_COUNT_MASK)); + } + + uint16_t getEOT() + { + return (entry.endOfTable & PRD_EOT_MASK); + } +}; + +#define DATA_OFFSET (0) +#define ERROR_OFFSET (1) +#define FEATURES_OFFSET (1) +#define NSECTOR_OFFSET (2) +#define SECTOR_OFFSET (3) +#define LCYL_OFFSET (4) +#define HCYL_OFFSET (5) +#define SELECT_OFFSET (6) +#define DRIVE_OFFSET (6) +#define STATUS_OFFSET (7) +#define COMMAND_OFFSET (7) + +#define CONTROL_OFFSET (2) +#define ALTSTAT_OFFSET (2) + +#define SELECT_DEV_BIT 0x10 +#define CONTROL_RST_BIT 0x04 +#define CONTROL_IEN_BIT 0x02 +#define STATUS_BSY_BIT 0x80 +#define STATUS_DRDY_BIT 0x40 +#define STATUS_DRQ_BIT 0x08 +#define STATUS_SEEK_BIT 0x10 +#define STATUS_DF_BIT 0x20 +#define DRIVE_LBA_BIT 0x40 + +#define DEV0 (0) +#define DEV1 (1) + +typedef struct CommandReg { + uint16_t data; + uint8_t error; + uint8_t sec_count; + uint8_t sec_num; + uint8_t cyl_low; + uint8_t cyl_high; + union { + uint8_t drive; + uint8_t head; + }; + uint8_t command; +} CommandReg_t; + +typedef enum Events { + None = 0, + Transfer, + ReadWait, + WriteWait, + PrdRead, + DmaRead, + DmaWrite +} Events_t; + +typedef enum DevAction { + ACT_NONE = 0, + ACT_CMD_WRITE, + ACT_CMD_COMPLETE, + ACT_CMD_ERROR, + ACT_SELECT_WRITE, + ACT_STAT_READ, + ACT_DATA_READY, + ACT_DATA_READ_BYTE, + ACT_DATA_READ_SHORT, + ACT_DATA_WRITE_BYTE, + ACT_DATA_WRITE_SHORT, + ACT_DMA_READY, + ACT_DMA_DONE, + ACT_SRST_SET, + ACT_SRST_CLEAR +} DevAction_t; + +typedef enum DevState { + // Device idle + Device_Idle_S = 0, + Device_Idle_SI, + Device_Idle_NS, + + // Software reset + Device_Srst, + + // Non-data commands + Command_Execution, + + // PIO data-in (data to host) + Prepare_Data_In, + Data_Ready_INTRQ_In, + Transfer_Data_In, + + // PIO data-out (data from host) + Prepare_Data_Out, + Data_Ready_INTRQ_Out, + Transfer_Data_Out, + + // DMA protocol + Prepare_Data_Dma, + Transfer_Data_Dma +} DevState_t; + +typedef enum DmaState { + Dma_Idle = 0, + Dma_Start, + Dma_Transfer +} DmaState_t; + +class PhysicalMemory; +class IdeController; + +/** + * IDE Disk device model + */ +class IdeDisk : public SimObject +{ + protected: + /** The IDE controller for this disk. */ + IdeController *ctrl; + /** The image that contains the data of this disk. */ + DiskImage *image; + + protected: + /** The disk delay in microseconds. */ + int diskDelay; + + private: + /** Drive identification structure for this disk */ + struct ataparams driveID; + /** Data buffer for transfers */ + uint8_t *dataBuffer; + /** Number of bytes in command data transfer */ + uint32_t cmdBytes; + /** Number of bytes left in command data transfer */ + uint32_t cmdBytesLeft; + /** Number of bytes left in DRQ block */ + uint32_t drqBytesLeft; + /** Current sector in access */ + uint32_t curSector; + /** Command block registers */ + CommandReg_t cmdReg; + /** Status register */ + uint8_t status; + /** Interrupt enable bit */ + bool nIENBit; + /** Device state */ + DevState_t devState; + /** Dma state */ + DmaState_t dmaState; + /** Dma transaction is a read */ + bool dmaRead; + /** PRD table base address */ + uint32_t curPrdAddr; + /** PRD entry */ + PrdTableEntry curPrd; + /** Device ID (master=0/slave=1) */ + int devID; + /** Interrupt pending */ + bool intrPending; + + Stats::Scalar<> dmaReadFullPages; + Stats::Scalar<> dmaReadBytes; + Stats::Scalar<> dmaReadTxs; + Stats::Scalar<> dmaWriteFullPages; + Stats::Scalar<> dmaWriteBytes; + Stats::Scalar<> dmaWriteTxs; + + public: + /** + * Create and initialize this Disk. + * @param name The name of this disk. + * @param img The disk image of this disk. + * @param id The disk ID (master=0/slave=1) + * @param disk_delay The disk delay in milliseconds + */ + IdeDisk(const std::string &name, DiskImage *img, int id, Tick disk_delay); + + /** + * Delete the data buffer. + */ + ~IdeDisk(); + + /** + * Reset the device state + */ + void reset(int id); + + /** + * Register Statistics + */ + void regStats(); + + /** + * Set the controller for this device + * @param c The IDE controller + */ + void setController(IdeController *c) { + if (ctrl) panic("Cannot change the controller once set!\n"); + ctrl = c; + } + + // Device register read/write + void read(const Addr &offset, IdeRegType regtype, uint8_t *data); + void write(const Addr &offset, IdeRegType regtype, const uint8_t *data); + + // Start/abort functions + void startDma(const uint32_t &prdTableBase); + void abortDma(); + + private: + void startCommand(); + + // Interrupt management + void intrPost(); + void intrClear(); + + // DMA stuff + void doDmaTransfer(); + friend class EventWrapper<IdeDisk, &IdeDisk::doDmaTransfer>; + EventWrapper<IdeDisk, &IdeDisk::doDmaTransfer> dmaTransferEvent; + + void doDmaDataRead(); + + void doDmaRead(); + ChunkGenerator *dmaReadCG; + friend class EventWrapper<IdeDisk, &IdeDisk::doDmaRead>; + EventWrapper<IdeDisk, &IdeDisk::doDmaRead> dmaReadWaitEvent; + + void doDmaDataWrite(); + + void doDmaWrite(); + ChunkGenerator *dmaWriteCG; + friend class EventWrapper<IdeDisk, &IdeDisk::doDmaWrite>; + EventWrapper<IdeDisk, &IdeDisk::doDmaWrite> dmaWriteWaitEvent; + + void dmaPrdReadDone(); + friend class EventWrapper<IdeDisk, &IdeDisk::dmaPrdReadDone>; + EventWrapper<IdeDisk, &IdeDisk::dmaPrdReadDone> dmaPrdReadEvent; + + void dmaReadDone(); + friend class EventWrapper<IdeDisk, &IdeDisk::dmaReadDone>; + EventWrapper<IdeDisk, &IdeDisk::dmaReadDone> dmaReadEvent; + + void dmaWriteDone(); + friend class EventWrapper<IdeDisk, &IdeDisk::dmaWriteDone>; + EventWrapper<IdeDisk, &IdeDisk::dmaWriteDone> dmaWriteEvent; + + // Disk image read/write + void readDisk(uint32_t sector, uint8_t *data); + void writeDisk(uint32_t sector, uint8_t *data); + + // State machine management + void updateState(DevAction_t action); + + // Utility functions + bool isBSYSet() { return (status & STATUS_BSY_BIT); } + bool isIENSet() { return nIENBit; } + bool isDEVSelect(); + + void setComplete() + { + // clear out the status byte + status = 0; + // set the DRDY bit + status |= STATUS_DRDY_BIT; + // set the SEEK bit + status |= STATUS_SEEK_BIT; + } + + uint32_t getLBABase() + { + return (Addr)(((cmdReg.head & 0xf) << 24) | (cmdReg.cyl_high << 16) | + (cmdReg.cyl_low << 8) | (cmdReg.sec_num)); + } + + inline Addr pciToDma(Addr pciAddr); + + /** + * Serialize this object to the given output stream. + * @param os The stream to serialize to. + */ + void serialize(std::ostream &os); + + /** + * Reconstruct the state of this object from a checkpoint. + * @param cp The checkpoint to use. + * @param section The section name describing this object. + */ + void unserialize(Checkpoint *cp, const std::string §ion); +}; + + +#endif // __IDE_DISK_HH__ diff --git a/dev/ide_wdcreg.h b/src/dev/ide_wdcreg.h index ed7475ec8..ed7475ec8 100644 --- a/dev/ide_wdcreg.h +++ b/src/dev/ide_wdcreg.h diff --git a/src/dev/io_device.cc b/src/dev/io_device.cc new file mode 100644 index 000000000..87fdbb765 --- /dev/null +++ b/src/dev/io_device.cc @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "dev/io_device.hh" +#include "sim/builder.hh" + + +PioPort::PioPort(PioDevice *dev, Platform *p) + : Port(dev->name() + "-pioport"), device(dev), platform(p) +{ } + + +Tick +PioPort::recvAtomic(Packet *pkt) +{ + return device->recvAtomic(pkt); +} + +void +PioPort::recvFunctional(Packet *pkt) +{ + device->recvAtomic(pkt); +} + +void +PioPort::getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop) +{ + snoop.clear(); + device->addressRanges(resp); +} + + +Packet * +PioPort::recvRetry() +{ + Packet* pkt = transmitList.front(); + transmitList.pop_front(); + return pkt; +} + + +void +PioPort::SendEvent::process() +{ + if (port->Port::sendTiming(packet)) + return; + + port->transmitList.push_back(packet); +} + + +bool +PioPort::recvTiming(Packet *pkt) +{ + device->recvAtomic(pkt); + // turn packet around to go back to requester + pkt->makeTimingResponse(); + sendTiming(pkt, pkt->time - pkt->req->getTime()); + return true; +} + +PioDevice::~PioDevice() +{ + if (pioPort) + delete pioPort; +} + +void +PioDevice::init() +{ + if (!pioPort) + panic("Pio port not connected to anything!"); + pioPort->sendStatusChange(Port::RangeChange); +} + +void +BasicPioDevice::addressRanges(AddrRangeList &range_list) +{ + assert(pioSize != 0); + range_list.clear(); + range_list.push_back(RangeSize(pioAddr, pioSize)); +} + + +DmaPort::DmaPort(DmaDevice *dev, Platform *p) + : Port(dev->name() + "-dmaport"), device(dev), platform(p), pendingCount(0) +{ } + +bool +DmaPort::recvTiming(Packet *pkt) +{ + if (pkt->senderState) { + DmaReqState *state; + state = dynamic_cast<DmaReqState*>(pkt->senderState); + state->completionEvent->schedule(pkt->time - pkt->req->getTime()); + delete pkt->req; + delete pkt; + } else { + delete pkt->req; + delete pkt; + } + + return Packet::Success; +} + +DmaDevice::DmaDevice(Params *p) + : PioDevice(p), dmaPort(NULL) +{ } + +void +DmaPort::SendEvent::process() +{ + if (port->Port::sendTiming(packet)) + return; + + port->transmitList.push_back(packet); +} + +Packet * +DmaPort::recvRetry() +{ + Packet* pkt = transmitList.front(); + transmitList.pop_front(); + return pkt; +} + + +void +DmaPort::dmaAction(Packet::Command cmd, Addr addr, int size, Event *event, + uint8_t *data) +{ + assert(event); + + int prevSize = 0; + + for (ChunkGenerator gen(addr, size, peerBlockSize()); + !gen.done(); gen.next()) { + Request *req = new Request(false); + req->setPaddr(gen.addr()); + req->setSize(gen.size()); + req->setTime(curTick); + Packet *pkt = new Packet(req, cmd, Packet::Broadcast); + + // Increment the data pointer on a write + if (data) + pkt->dataStatic(data + prevSize) ; + + prevSize += gen.size(); + + // Set the last bit of the dma as the final packet for this dma + // and set it's completion event. + if (prevSize == size) { + pkt->senderState = new DmaReqState(event, true); + } + assert(pendingCount >= 0); + pendingCount++; + sendDma(pkt); + } +} + + +void +DmaPort::sendDma(Packet *pkt) +{ + // some kind of selction between access methods + // more work is going to have to be done to make + // switching actually work + /* MemState state = device->platform->system->memState; + + if (state == Timing) { + if (!sendTiming(pkt)) + transmitList.push_back(&packet); + } else if (state == Atomic) {*/ + sendAtomic(pkt); + if (pkt->senderState) { + DmaReqState *state = dynamic_cast<DmaReqState*>(pkt->senderState); + state->completionEvent->schedule(curTick + (pkt->time - pkt->req->getTime()) +1); + } + pendingCount--; + assert(pendingCount >= 0); + delete pkt->req; + delete pkt; + +/* } else if (state == Functional) { + sendFunctional(pkt); + // Is this correct??? + completionEvent->schedule(pkt->req->responseTime - pkt->req->requestTime); + completionEvent == NULL; + } else + panic("Unknown memory command state."); + */ +} + +DmaDevice::~DmaDevice() +{ + if (dmaPort) + delete dmaPort; +} + + diff --git a/src/dev/io_device.hh b/src/dev/io_device.hh new file mode 100644 index 000000000..74730ad92 --- /dev/null +++ b/src/dev/io_device.hh @@ -0,0 +1,335 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __DEV_IO_DEVICE_HH__ +#define __DEV_IO_DEVICE_HH__ + +#include "base/chunk_generator.hh" +#include "mem/mem_object.hh" +#include "mem/packet_impl.hh" +#include "sim/eventq.hh" +#include "sim/sim_object.hh" + +class Platform; +class PioDevice; +class DmaDevice; +class System; + +/** + * The PioPort class is a programmed i/o port that all devices that are + * sensitive to an address range use. The port takes all the memory + * access types and roles them into one read() and write() call that the device + * must respond to. The device must also provide the addressRanges() function + * with which it returns the address ranges it is interested in. An extra + * sendTiming() function is implemented which takes an delay. In this way the + * device can immediatly call sendTiming(pkt, time) after processing a request + * and the request will be handled by the port even if the port bus the device + * connects to is blocked. + */ +class PioPort : public Port +{ + protected: + /** The device that this port serves. */ + PioDevice *device; + + /** The platform that device/port are in. This is used to select which mode + * we are currently operating in. */ + Platform *platform; + + /** A list of outgoing timing response packets that haven't been serviced + * yet. */ + std::list<Packet*> transmitList; + + /** The current status of the peer(bus) that we are connected to. */ + Status peerStatus; + + virtual bool recvTiming(Packet *pkt); + + virtual Tick recvAtomic(Packet *pkt); + + virtual void recvFunctional(Packet *pkt) ; + + virtual void recvStatusChange(Status status) + { peerStatus = status; } + + virtual void getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop); + + /** + * This class is used to implemented sendTiming() with a delay. When a delay + * is requested a new event is created. When the event time expires it + * attempts to send the packet. If it cannot, the packet is pushed onto the + * transmit list to be sent when recvRetry() is called. */ + class SendEvent : public Event + { + PioPort *port; + Packet *packet; + + SendEvent(PioPort *p, Packet *pkt, Tick t) + : Event(&mainEventQueue), port(p), packet(pkt) + { schedule(curTick + t); } + + virtual void process(); + + virtual const char *description() + { return "Future scheduled sendTiming event"; } + + friend class PioPort; + }; + + /** Schedule a sendTiming() event to be called in the future. */ + void sendTiming(Packet *pkt, Tick time) + { new PioPort::SendEvent(this, pkt, time); } + + /** This function pops the last element off the transmit list and sends it.*/ + virtual Packet *recvRetry(); + + public: + PioPort(PioDevice *dev, Platform *p); + + friend class PioPort::SendEvent; +}; + + +struct DmaReqState : public Packet::SenderState +{ + Event *completionEvent; + bool final; + DmaReqState(Event *ce, bool f) + : completionEvent(ce), final(f) + {} +}; + +class DmaPort : public Port +{ + protected: + DmaDevice *device; + std::list<Packet*> transmitList; + + /** The platform that device/port are in. This is used to select which mode + * we are currently operating in. */ + Platform *platform; + + /** Number of outstanding packets the dma port has. */ + int pendingCount; + + virtual bool recvTiming(Packet *pkt); + virtual Tick recvAtomic(Packet *pkt) + { panic("dma port shouldn't be used for pio access."); } + virtual void recvFunctional(Packet *pkt) + { panic("dma port shouldn't be used for pio access."); } + + virtual void recvStatusChange(Status status) + { ; } + + virtual Packet *recvRetry() ; + + virtual void getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop) + { resp.clear(); snoop.clear(); } + + class SendEvent : public Event + { + DmaPort *port; + Packet *packet; + + SendEvent(PioPort *p, Packet *pkt, Tick t) + : Event(&mainEventQueue), packet(pkt) + { schedule(curTick + t); } + + virtual void process(); + + virtual const char *description() + { return "Future scheduled sendTiming event"; } + + friend class DmaPort; + }; + + void sendDma(Packet *pkt); + + public: + DmaPort(DmaDevice *dev, Platform *p); + + void dmaAction(Packet::Command cmd, Addr addr, int size, Event *event, + uint8_t *data = NULL); + + bool dmaPending() { return pendingCount > 0; } + + friend class DmaPort::SendEvent; + +}; + +/** + * This device is the base class which all devices senstive to an address range + * inherit from. There are three pure virtual functions which all devices must + * implement addressRanges(), read(), and write(). The magic do choose which + * mode we are in, etc is handled by the PioPort so the device doesn't have to + * bother. + */ + +class PioDevice : public MemObject +{ + protected: + + /** The platform we are in. This is used to decide what type of memory + * transaction we should perform. */ + Platform *platform; + + /** The pioPort that handles the requests for us and provides us requests + * that it sees. */ + PioPort *pioPort; + + virtual void addressRanges(AddrRangeList &range_list) = 0; + + /** As far as the devices are concerned they only accept atomic transactions + * which are converted to either a write or a read. */ + Tick recvAtomic(Packet *pkt) + { return pkt->isRead() ? this->read(pkt) : this->write(pkt); } + + /** Pure virtual function that the device must implement. Called when a read + * command is recieved by the port. + * @param pkt Packet describing this request + * @return number of ticks it took to complete + */ + virtual Tick read(Packet *pkt) = 0; + + /** Pure virtual function that the device must implement. Called when a + * write command is recieved by the port. + * @param pkt Packet describing this request + * @return number of ticks it took to complete + */ + virtual Tick write(Packet *pkt) = 0; + + public: + /** Params struct which is extended through each device based on the + * parameters it needs. Since we are re-writing everything, we might as well + * start from the bottom this time. */ + + struct Params + { + std::string name; + Platform *platform; + System *system; + }; + + protected: + Params *_params; + + public: + const Params *params() const { return _params; } + + PioDevice(Params *p) + : MemObject(p->name), platform(p->platform), pioPort(NULL), + _params(p) + {} + + virtual ~PioDevice(); + + virtual void init(); + + virtual Port *getPort(const std::string &if_name) + { + if (if_name == "pio") { + if (pioPort != NULL) + panic("pio port already connected to."); + pioPort = new PioPort(this, params()->platform); + return pioPort; + } else + return NULL; + } + friend class PioPort; + +}; + +class BasicPioDevice : public PioDevice +{ + public: + struct Params : public PioDevice::Params + { + Addr pio_addr; + Tick pio_delay; + }; + + protected: + /** Address that the device listens to. */ + Addr pioAddr; + + /** Size that the device's address range. */ + Addr pioSize; + + /** Delay that the device experinces on an access. */ + Tick pioDelay; + + public: + BasicPioDevice(Params *p) + : PioDevice(p), pioAddr(p->pio_addr), pioSize(0), pioDelay(p->pio_delay) + {} + + /** return the address ranges that this device responds to. + * @params range_list range list to populate with ranges + */ + void addressRanges(AddrRangeList &range_list); + +}; + +class DmaDevice : public PioDevice +{ + protected: + DmaPort *dmaPort; + + public: + DmaDevice(Params *p); + virtual ~DmaDevice(); + + void dmaWrite(Addr addr, int size, Event *event, uint8_t *data) + { dmaPort->dmaAction(Packet::WriteReq, addr, size, event, data) ; } + + void dmaRead(Addr addr, int size, Event *event, uint8_t *data = NULL) + { dmaPort->dmaAction(Packet::ReadReq, addr, size, event, data); } + + bool dmaPending() { return dmaPort->dmaPending(); } + + virtual Port *getPort(const std::string &if_name) + { + if (if_name == "pio") { + if (pioPort != NULL) + panic("pio port already connected to."); + pioPort = new PioPort(this, params()->platform); + return pioPort; + } else if (if_name == "dma") { + if (dmaPort != NULL) + panic("dma port already connected to."); + dmaPort = new DmaPort(this, params()->platform); + return dmaPort; + } else + return NULL; + } + + friend class DmaPort; +}; + + +#endif // __DEV_IO_DEVICE_HH__ diff --git a/src/dev/isa_fake.cc b/src/dev/isa_fake.cc new file mode 100644 index 000000000..c303ffc30 --- /dev/null +++ b/src/dev/isa_fake.cc @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file + * Isa Fake Device implementation + */ + +#include <deque> +#include <string> +#include <vector> + +#include "base/trace.hh" +#include "dev/isa_fake.hh" +#include "mem/packet.hh" +#include "sim/builder.hh" +#include "sim/system.hh" + +using namespace std; + +IsaFake::IsaFake(Params *p) + : BasicPioDevice(p) +{ + pioSize = p->pio_size; +} + +Tick +IsaFake::read(Packet *pkt) +{ + assert(pkt->result == Packet::Unknown); + assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); + + pkt->time += pioDelay; + + DPRINTF(Tsunami, "read va=%#x size=%d\n", pkt->getAddr(), pkt->getSize()); + + switch (pkt->getSize()) { + pkt->set(0xFFFFFFFFFFFFFFFFULL); + break; + case sizeof(uint32_t): + pkt->set((uint32_t)0xFFFFFFFF); + break; + case sizeof(uint16_t): + pkt->set((uint16_t)0xFFFF); + break; + case sizeof(uint8_t): + pkt->set((uint8_t)0xFF); + break; + default: + panic("invalid access size(?) for PCI configspace!\n"); + } + pkt->result = Packet::Success; + return pioDelay; +} + +Tick +IsaFake::write(Packet *pkt) +{ + pkt->time += pioDelay; + DPRINTF(Tsunami, "write - va=%#x size=%d \n", pkt->getAddr(), pkt->getSize()); + pkt->result = Packet::Success; + return pioDelay; +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(IsaFake) + + Param<Addr> pio_addr; + Param<Tick> pio_latency; + Param<Addr> pio_size; + SimObjectParam<Platform *> platform; + SimObjectParam<System *> system; + +END_DECLARE_SIM_OBJECT_PARAMS(IsaFake) + +BEGIN_INIT_SIM_OBJECT_PARAMS(IsaFake) + + INIT_PARAM(pio_addr, "Device Address"), + INIT_PARAM(pio_latency, "Programmed IO latency"), + INIT_PARAM(pio_size, "Size of address range"), + INIT_PARAM(platform, "platform"), + INIT_PARAM(system, "system object") + +END_INIT_SIM_OBJECT_PARAMS(IsaFake) + +CREATE_SIM_OBJECT(IsaFake) +{ + IsaFake::Params *p = new IsaFake::Params; + p->name = getInstanceName(); + p->pio_addr = pio_addr; + p->pio_delay = pio_latency; + p->pio_size = pio_size; + p->platform = platform; + p->system = system; + return new IsaFake(p); +} + +REGISTER_SIM_OBJECT("IsaFake", IsaFake) diff --git a/src/dev/isa_fake.hh b/src/dev/isa_fake.hh new file mode 100644 index 000000000..65d44f6a5 --- /dev/null +++ b/src/dev/isa_fake.hh @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file + * Declaration of a fake device. + */ + +#ifndef __ISA_FAKE_HH__ +#define __ISA_FAKE_HH__ + +#include "dev/tsunami.hh" +#include "base/range.hh" +#include "dev/io_device.hh" + +/** + * IsaFake is a device that returns -1 on all reads and + * accepts all writes. It is meant to be placed at an address range + * so that an mcheck doesn't occur when an os probes a piece of hw + * that doesn't exist (e.g. UARTs1-3). + */ +class IsaFake : public BasicPioDevice +{ + public: + struct Params : public BasicPioDevice::Params + { + Addr pio_size; + }; + protected: + const Params *params() const { return (const Params*)_params; } + + public: + /** + * The constructor for Tsunmami Fake just registers itself with the MMU. + * @param p params structure + */ + IsaFake(Params *p); + + /** + * This read always returns -1. + * @param req The memory request. + * @param data Where to put the data. + */ + virtual Tick read(Packet *pkt); + + /** + * All writes are simply ignored. + * @param req The memory request. + * @param data the data to not write. + */ + virtual Tick write(Packet *pkt); +}; + +#endif // __TSUNAMI_FAKE_HH__ diff --git a/src/dev/ns_gige.cc b/src/dev/ns_gige.cc new file mode 100644 index 000000000..963675847 --- /dev/null +++ b/src/dev/ns_gige.cc @@ -0,0 +1,2914 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file + * Device module for modelling the National Semiconductor + * DP83820 ethernet controller. Does not support priority queueing + */ +#include <deque> +#include <string> + +#include "arch/alpha/ev5.hh" +#include "base/inet.hh" +#include "cpu/exec_context.hh" +#include "dev/etherlink.hh" +#include "dev/ns_gige.hh" +#include "dev/pciconfigall.hh" +#include "mem/packet.hh" +#include "sim/builder.hh" +#include "sim/debug.hh" +#include "sim/host.hh" +#include "sim/stats.hh" +#include "sim/system.hh" + +const char *NsRxStateStrings[] = +{ + "rxIdle", + "rxDescRefr", + "rxDescRead", + "rxFifoBlock", + "rxFragWrite", + "rxDescWrite", + "rxAdvance" +}; + +const char *NsTxStateStrings[] = +{ + "txIdle", + "txDescRefr", + "txDescRead", + "txFifoBlock", + "txFragRead", + "txDescWrite", + "txAdvance" +}; + +const char *NsDmaState[] = +{ + "dmaIdle", + "dmaReading", + "dmaWriting", + "dmaReadWaiting", + "dmaWriteWaiting" +}; + +using namespace std; +using namespace Net; +using namespace TheISA; + +/////////////////////////////////////////////////////////////////////// +// +// NSGigE PCI Device +// +NSGigE::NSGigE(Params *p) + : PciDev(p), ioEnable(false), + txFifo(p->tx_fifo_size), rxFifo(p->rx_fifo_size), + txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL), + txXferLen(0), rxXferLen(0), clock(p->clock), + txState(txIdle), txEnable(false), CTDD(false), + txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle), + rxEnable(false), CRDD(false), rxPktBytes(0), + rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false), + eepromState(eepromStart), rxDmaReadEvent(this), rxDmaWriteEvent(this), + txDmaReadEvent(this), txDmaWriteEvent(this), + dmaDescFree(p->dma_desc_free), dmaDataFree(p->dma_data_free), + txDelay(p->tx_delay), rxDelay(p->rx_delay), + rxKickTick(0), rxKickEvent(this), txKickTick(0), txKickEvent(this), + txEvent(this), rxFilterEnable(p->rx_filter), acceptBroadcast(false), + acceptMulticast(false), acceptUnicast(false), + acceptPerfect(false), acceptArp(false), multicastHashEnable(false), + intrTick(0), cpuPendingIntr(false), + intrEvent(0), interface(0) +{ + + intrDelay = p->intr_delay; + dmaReadDelay = p->dma_read_delay; + dmaWriteDelay = p->dma_write_delay; + dmaReadFactor = p->dma_read_factor; + dmaWriteFactor = p->dma_write_factor; + + regsReset(); + memcpy(&rom.perfectMatch, p->eaddr.bytes(), ETH_ADDR_LEN); + + memset(&rxDesc32, 0, sizeof(rxDesc32)); + memset(&txDesc32, 0, sizeof(txDesc32)); + memset(&rxDesc64, 0, sizeof(rxDesc64)); + memset(&txDesc64, 0, sizeof(txDesc64)); +} + +NSGigE::~NSGigE() +{} + +void +NSGigE::regStats() +{ + txBytes + .name(name() + ".txBytes") + .desc("Bytes Transmitted") + .prereq(txBytes) + ; + + rxBytes + .name(name() + ".rxBytes") + .desc("Bytes Received") + .prereq(rxBytes) + ; + + txPackets + .name(name() + ".txPackets") + .desc("Number of Packets Transmitted") + .prereq(txBytes) + ; + + rxPackets + .name(name() + ".rxPackets") + .desc("Number of Packets Received") + .prereq(rxBytes) + ; + + txIpChecksums + .name(name() + ".txIpChecksums") + .desc("Number of tx IP Checksums done by device") + .precision(0) + .prereq(txBytes) + ; + + rxIpChecksums + .name(name() + ".rxIpChecksums") + .desc("Number of rx IP Checksums done by device") + .precision(0) + .prereq(rxBytes) + ; + + txTcpChecksums + .name(name() + ".txTcpChecksums") + .desc("Number of tx TCP Checksums done by device") + .precision(0) + .prereq(txBytes) + ; + + rxTcpChecksums + .name(name() + ".rxTcpChecksums") + .desc("Number of rx TCP Checksums done by device") + .precision(0) + .prereq(rxBytes) + ; + + txUdpChecksums + .name(name() + ".txUdpChecksums") + .desc("Number of tx UDP Checksums done by device") + .precision(0) + .prereq(txBytes) + ; + + rxUdpChecksums + .name(name() + ".rxUdpChecksums") + .desc("Number of rx UDP Checksums done by device") + .precision(0) + .prereq(rxBytes) + ; + + descDmaReads + .name(name() + ".descDMAReads") + .desc("Number of descriptors the device read w/ DMA") + .precision(0) + ; + + descDmaWrites + .name(name() + ".descDMAWrites") + .desc("Number of descriptors the device wrote w/ DMA") + .precision(0) + ; + + descDmaRdBytes + .name(name() + ".descDmaReadBytes") + .desc("number of descriptor bytes read w/ DMA") + .precision(0) + ; + + descDmaWrBytes + .name(name() + ".descDmaWriteBytes") + .desc("number of descriptor bytes write w/ DMA") + .precision(0) + ; + + txBandwidth + .name(name() + ".txBandwidth") + .desc("Transmit Bandwidth (bits/s)") + .precision(0) + .prereq(txBytes) + ; + + rxBandwidth + .name(name() + ".rxBandwidth") + .desc("Receive Bandwidth (bits/s)") + .precision(0) + .prereq(rxBytes) + ; + + totBandwidth + .name(name() + ".totBandwidth") + .desc("Total Bandwidth (bits/s)") + .precision(0) + .prereq(totBytes) + ; + + totPackets + .name(name() + ".totPackets") + .desc("Total Packets") + .precision(0) + .prereq(totBytes) + ; + + totBytes + .name(name() + ".totBytes") + .desc("Total Bytes") + .precision(0) + .prereq(totBytes) + ; + + totPacketRate + .name(name() + ".totPPS") + .desc("Total Tranmission Rate (packets/s)") + .precision(0) + .prereq(totBytes) + ; + + txPacketRate + .name(name() + ".txPPS") + .desc("Packet Tranmission Rate (packets/s)") + .precision(0) + .prereq(txBytes) + ; + + rxPacketRate + .name(name() + ".rxPPS") + .desc("Packet Reception Rate (packets/s)") + .precision(0) + .prereq(rxBytes) + ; + + postedSwi + .name(name() + ".postedSwi") + .desc("number of software interrupts posted to CPU") + .precision(0) + ; + + totalSwi + .name(name() + ".totalSwi") + .desc("total number of Swi written to ISR") + .precision(0) + ; + + coalescedSwi + .name(name() + ".coalescedSwi") + .desc("average number of Swi's coalesced into each post") + .precision(0) + ; + + postedRxIdle + .name(name() + ".postedRxIdle") + .desc("number of rxIdle interrupts posted to CPU") + .precision(0) + ; + + totalRxIdle + .name(name() + ".totalRxIdle") + .desc("total number of RxIdle written to ISR") + .precision(0) + ; + + coalescedRxIdle + .name(name() + ".coalescedRxIdle") + .desc("average number of RxIdle's coalesced into each post") + .precision(0) + ; + + postedRxOk + .name(name() + ".postedRxOk") + .desc("number of RxOk interrupts posted to CPU") + .precision(0) + ; + + totalRxOk + .name(name() + ".totalRxOk") + .desc("total number of RxOk written to ISR") + .precision(0) + ; + + coalescedRxOk + .name(name() + ".coalescedRxOk") + .desc("average number of RxOk's coalesced into each post") + .precision(0) + ; + + postedRxDesc + .name(name() + ".postedRxDesc") + .desc("number of RxDesc interrupts posted to CPU") + .precision(0) + ; + + totalRxDesc + .name(name() + ".totalRxDesc") + .desc("total number of RxDesc written to ISR") + .precision(0) + ; + + coalescedRxDesc + .name(name() + ".coalescedRxDesc") + .desc("average number of RxDesc's coalesced into each post") + .precision(0) + ; + + postedTxOk + .name(name() + ".postedTxOk") + .desc("number of TxOk interrupts posted to CPU") + .precision(0) + ; + + totalTxOk + .name(name() + ".totalTxOk") + .desc("total number of TxOk written to ISR") + .precision(0) + ; + + coalescedTxOk + .name(name() + ".coalescedTxOk") + .desc("average number of TxOk's coalesced into each post") + .precision(0) + ; + + postedTxIdle + .name(name() + ".postedTxIdle") + .desc("number of TxIdle interrupts posted to CPU") + .precision(0) + ; + + totalTxIdle + .name(name() + ".totalTxIdle") + .desc("total number of TxIdle written to ISR") + .precision(0) + ; + + coalescedTxIdle + .name(name() + ".coalescedTxIdle") + .desc("average number of TxIdle's coalesced into each post") + .precision(0) + ; + + postedTxDesc + .name(name() + ".postedTxDesc") + .desc("number of TxDesc interrupts posted to CPU") + .precision(0) + ; + + totalTxDesc + .name(name() + ".totalTxDesc") + .desc("total number of TxDesc written to ISR") + .precision(0) + ; + + coalescedTxDesc + .name(name() + ".coalescedTxDesc") + .desc("average number of TxDesc's coalesced into each post") + .precision(0) + ; + + postedRxOrn + .name(name() + ".postedRxOrn") + .desc("number of RxOrn posted to CPU") + .precision(0) + ; + + totalRxOrn + .name(name() + ".totalRxOrn") + .desc("total number of RxOrn written to ISR") + .precision(0) + ; + + coalescedRxOrn + .name(name() + ".coalescedRxOrn") + .desc("average number of RxOrn's coalesced into each post") + .precision(0) + ; + + coalescedTotal + .name(name() + ".coalescedTotal") + .desc("average number of interrupts coalesced into each post") + .precision(0) + ; + + postedInterrupts + .name(name() + ".postedInterrupts") + .desc("number of posts to CPU") + .precision(0) + ; + + droppedPackets + .name(name() + ".droppedPackets") + .desc("number of packets dropped") + .precision(0) + ; + + coalescedSwi = totalSwi / postedInterrupts; + coalescedRxIdle = totalRxIdle / postedInterrupts; + coalescedRxOk = totalRxOk / postedInterrupts; + coalescedRxDesc = totalRxDesc / postedInterrupts; + coalescedTxOk = totalTxOk / postedInterrupts; + coalescedTxIdle = totalTxIdle / postedInterrupts; + coalescedTxDesc = totalTxDesc / postedInterrupts; + coalescedRxOrn = totalRxOrn / postedInterrupts; + + coalescedTotal = (totalSwi + totalRxIdle + totalRxOk + totalRxDesc + + totalTxOk + totalTxIdle + totalTxDesc + + totalRxOrn) / postedInterrupts; + + txBandwidth = txBytes * Stats::constant(8) / simSeconds; + rxBandwidth = rxBytes * Stats::constant(8) / simSeconds; + totBandwidth = txBandwidth + rxBandwidth; + totBytes = txBytes + rxBytes; + totPackets = txPackets + rxPackets; + + txPacketRate = txPackets / simSeconds; + rxPacketRate = rxPackets / simSeconds; +} + + +/** + * This is to write to the PCI general configuration registers + */ +void +NSGigE::writeConfig(int offset, const uint16_t data) +{ + if (offset < PCI_DEVICE_SPECIFIC) + PciDev::writeConfig(offset, data); + else + panic("Device specific PCI config space not implemented!\n"); + + switch (offset) { + // seems to work fine without all these PCI settings, but i + // put in the IO to double check, an assertion will fail if we + // need to properly implement it + case PCI_COMMAND: + if (config.data[offset] & PCI_CMD_IOSE) + ioEnable = true; + else + ioEnable = false; + break; + } +} + +/** + * This reads the device registers, which are detailed in the NS83820 + * spec sheet + */ +Tick +NSGigE::read(Packet *pkt) +{ + assert(ioEnable); + + pkt->time += pioDelay; + pkt->allocate(); + + //The mask is to give you only the offset into the device register file + Addr daddr = pkt->getAddr() & 0xfff; + DPRINTF(EthernetPIO, "read da=%#x pa=%#x size=%d\n", + daddr, pkt->getAddr(), pkt->getSize()); + + + // there are some reserved registers, you can see ns_gige_reg.h and + // the spec sheet for details + if (daddr > LAST && daddr <= RESERVED) { + panic("Accessing reserved register"); + } else if (daddr > RESERVED && daddr <= 0x3FC) { + if (pkt->getSize() == sizeof(uint8_t)) + readConfig(daddr & 0xff, pkt->getPtr<uint8_t>()); + if (pkt->getSize() == sizeof(uint16_t)) + readConfig(daddr & 0xff, pkt->getPtr<uint16_t>()); + if (pkt->getSize() == sizeof(uint32_t)) + readConfig(daddr & 0xff, pkt->getPtr<uint32_t>()); + pkt->result = Packet::Success; + return pioDelay; + } else if (daddr >= MIB_START && daddr <= MIB_END) { + // don't implement all the MIB's. hopefully the kernel + // doesn't actually DEPEND upon their values + // MIB are just hardware stats keepers + pkt->set<uint32_t>(0); + pkt->result = Packet::Success; + return pioDelay; + } else if (daddr > 0x3FC) + panic("Something is messed up!\n"); + + assert(pkt->getSize() == sizeof(uint32_t)); + uint32_t ® = *pkt->getPtr<uint32_t>(); + uint16_t rfaddr; + + switch (daddr) { + case CR: + reg = regs.command; + //these are supposed to be cleared on a read + reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR); + break; + + case CFGR: + reg = regs.config; + break; + + case MEAR: + reg = regs.mear; + break; + + case PTSCR: + reg = regs.ptscr; + break; + + case ISR: + reg = regs.isr; + devIntrClear(ISR_ALL); + break; + + case IMR: + reg = regs.imr; + break; + + case IER: + reg = regs.ier; + break; + + case IHR: + reg = regs.ihr; + break; + + case TXDP: + reg = regs.txdp; + break; + + case TXDP_HI: + reg = regs.txdp_hi; + break; + + case TX_CFG: + reg = regs.txcfg; + break; + + case GPIOR: + reg = regs.gpior; + break; + + case RXDP: + reg = regs.rxdp; + break; + + case RXDP_HI: + reg = regs.rxdp_hi; + break; + + case RX_CFG: + reg = regs.rxcfg; + break; + + case PQCR: + reg = regs.pqcr; + break; + + case WCSR: + reg = regs.wcsr; + break; + + case PCR: + reg = regs.pcr; + break; + + // see the spec sheet for how RFCR and RFDR work + // basically, you write to RFCR to tell the machine + // what you want to do next, then you act upon RFDR, + // and the device will be prepared b/c of what you + // wrote to RFCR + case RFCR: + reg = regs.rfcr; + break; + + case RFDR: + rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR); + switch (rfaddr) { + // Read from perfect match ROM octets + case 0x000: + reg = rom.perfectMatch[1]; + reg = reg << 8; + reg += rom.perfectMatch[0]; + break; + case 0x002: + reg = rom.perfectMatch[3] << 8; + reg += rom.perfectMatch[2]; + break; + case 0x004: + reg = rom.perfectMatch[5] << 8; + reg += rom.perfectMatch[4]; + break; + default: + // Read filter hash table + if (rfaddr >= FHASH_ADDR && + rfaddr < FHASH_ADDR + FHASH_SIZE) { + + // Only word-aligned reads supported + if (rfaddr % 2) + panic("unaligned read from filter hash table!"); + + reg = rom.filterHash[rfaddr - FHASH_ADDR + 1] << 8; + reg += rom.filterHash[rfaddr - FHASH_ADDR]; + break; + } + + panic("reading RFDR for something other than pattern" + " matching or hashing! %#x\n", rfaddr); + } + break; + + case SRR: + reg = regs.srr; + break; + + case MIBC: + reg = regs.mibc; + reg &= ~(MIBC_MIBS | MIBC_ACLR); + break; + + case VRCR: + reg = regs.vrcr; + break; + + case VTCR: + reg = regs.vtcr; + break; + + case VDR: + reg = regs.vdr; + break; + + case CCSR: + reg = regs.ccsr; + break; + + case TBICR: + reg = regs.tbicr; + break; + + case TBISR: + reg = regs.tbisr; + break; + + case TANAR: + reg = regs.tanar; + break; + + case TANLPAR: + reg = regs.tanlpar; + break; + + case TANER: + reg = regs.taner; + break; + + case TESR: + reg = regs.tesr; + break; + + case M5REG: + reg = 0; + if (params()->rx_thread) + reg |= M5REG_RX_THREAD; + if (params()->tx_thread) + reg |= M5REG_TX_THREAD; + if (params()->rss) + reg |= M5REG_RSS; + break; + + default: + panic("reading unimplemented register: addr=%#x", daddr); + } + + DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n", + daddr, reg, reg); + + pkt->result = Packet::Success; + return pioDelay; +} + +Tick +NSGigE::write(Packet *pkt) +{ + assert(ioEnable); + + Addr daddr = pkt->getAddr() & 0xfff; + DPRINTF(EthernetPIO, "write da=%#x pa=%#x size=%d\n", + daddr, pkt->getAddr(), pkt->getSize()); + + pkt->time += pioDelay; + + if (daddr > LAST && daddr <= RESERVED) { + panic("Accessing reserved register"); + } else if (daddr > RESERVED && daddr <= 0x3FC) { + if (pkt->getSize() == sizeof(uint8_t)) + writeConfig(daddr & 0xff, pkt->get<uint8_t>()); + if (pkt->getSize() == sizeof(uint16_t)) + writeConfig(daddr & 0xff, pkt->get<uint16_t>()); + if (pkt->getSize() == sizeof(uint32_t)) + writeConfig(daddr & 0xff, pkt->get<uint32_t>()); + pkt->result = Packet::Success; + return pioDelay; + } else if (daddr > 0x3FC) + panic("Something is messed up!\n"); + + if (pkt->getSize() == sizeof(uint32_t)) { + uint32_t reg = pkt->get<uint32_t>(); + uint16_t rfaddr; + + DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg); + + switch (daddr) { + case CR: + regs.command = reg; + if (reg & CR_TXD) { + txEnable = false; + } else if (reg & CR_TXE) { + txEnable = true; + + // the kernel is enabling the transmit machine + if (txState == txIdle) + txKick(); + } + + if (reg & CR_RXD) { + rxEnable = false; + } else if (reg & CR_RXE) { + rxEnable = true; + + if (rxState == rxIdle) + rxKick(); + } + + if (reg & CR_TXR) + txReset(); + + if (reg & CR_RXR) + rxReset(); + + if (reg & CR_SWI) + devIntrPost(ISR_SWI); + + if (reg & CR_RST) { + txReset(); + rxReset(); + + regsReset(); + } + break; + + case CFGR: + if (reg & CFGR_LNKSTS || + reg & CFGR_SPDSTS || + reg & CFGR_DUPSTS || + reg & CFGR_RESERVED || + reg & CFGR_T64ADDR || + reg & CFGR_PCI64_DET) + + // First clear all writable bits + regs.config &= CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS | + CFGR_RESERVED | CFGR_T64ADDR | + CFGR_PCI64_DET; + // Now set the appropriate writable bits + regs.config |= reg & ~(CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS | + CFGR_RESERVED | CFGR_T64ADDR | + CFGR_PCI64_DET); + +// all these #if 0's are because i don't THINK the kernel needs to +// have these implemented. if there is a problem relating to one of +// these, you may need to add functionality in. + if (reg & CFGR_TBI_EN) ; + if (reg & CFGR_MODE_1000) ; + + if (reg & CFGR_AUTO_1000) + panic("CFGR_AUTO_1000 not implemented!\n"); + + if (reg & CFGR_PINT_DUPSTS || + reg & CFGR_PINT_LNKSTS || + reg & CFGR_PINT_SPDSTS) + ; + + if (reg & CFGR_TMRTEST) ; + if (reg & CFGR_MRM_DIS) ; + if (reg & CFGR_MWI_DIS) ; + + if (reg & CFGR_T64ADDR) ; + // panic("CFGR_T64ADDR is read only register!\n"); + + if (reg & CFGR_PCI64_DET) + panic("CFGR_PCI64_DET is read only register!\n"); + + if (reg & CFGR_DATA64_EN) ; + if (reg & CFGR_M64ADDR) ; + if (reg & CFGR_PHY_RST) ; + if (reg & CFGR_PHY_DIS) ; + + if (reg & CFGR_EXTSTS_EN) + extstsEnable = true; + else + extstsEnable = false; + + if (reg & CFGR_REQALG) ; + if (reg & CFGR_SB) ; + if (reg & CFGR_POW) ; + if (reg & CFGR_EXD) ; + if (reg & CFGR_PESEL) ; + if (reg & CFGR_BROM_DIS) ; + if (reg & CFGR_EXT_125) ; + if (reg & CFGR_BEM) ; + break; + + case MEAR: + // Clear writable bits + regs.mear &= MEAR_EEDO; + // Set appropriate writable bits + regs.mear |= reg & ~MEAR_EEDO; + + // FreeBSD uses the EEPROM to read PMATCH (for the MAC address) + // even though it could get it through RFDR + if (reg & MEAR_EESEL) { + // Rising edge of clock + if (reg & MEAR_EECLK && !eepromClk) + eepromKick(); + } + else { + eepromState = eepromStart; + regs.mear &= ~MEAR_EEDI; + } + + eepromClk = reg & MEAR_EECLK; + + // since phy is completely faked, MEAR_MD* don't matter + if (reg & MEAR_MDIO) ; + if (reg & MEAR_MDDIR) ; + if (reg & MEAR_MDC) ; + break; + + case PTSCR: + regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY); + // these control BISTs for various parts of chip - we + // don't care or do just fake that the BIST is done + if (reg & PTSCR_RBIST_EN) + regs.ptscr |= PTSCR_RBIST_DONE; + if (reg & PTSCR_EEBIST_EN) + regs.ptscr &= ~PTSCR_EEBIST_EN; + if (reg & PTSCR_EELOAD_EN) + regs.ptscr &= ~PTSCR_EELOAD_EN; + break; + + case ISR: /* writing to the ISR has no effect */ + panic("ISR is a read only register!\n"); + + case IMR: + regs.imr = reg; + devIntrChangeMask(); + break; + + case IER: + regs.ier = reg; + break; + + case IHR: + regs.ihr = reg; + /* not going to implement real interrupt holdoff */ + break; + + case TXDP: + regs.txdp = (reg & 0xFFFFFFFC); + assert(txState == txIdle); + CTDD = false; + break; + + case TXDP_HI: + regs.txdp_hi = reg; + break; + + case TX_CFG: + regs.txcfg = reg; +#if 0 + if (reg & TX_CFG_CSI) ; + if (reg & TX_CFG_HBI) ; + if (reg & TX_CFG_MLB) ; + if (reg & TX_CFG_ATP) ; + if (reg & TX_CFG_ECRETRY) { + /* + * this could easily be implemented, but considering + * the network is just a fake pipe, wouldn't make + * sense to do this + */ + } + + if (reg & TX_CFG_BRST_DIS) ; +#endif + +#if 0 + /* we handle our own DMA, ignore the kernel's exhortations */ + if (reg & TX_CFG_MXDMA) ; +#endif + + // also, we currently don't care about fill/drain + // thresholds though this may change in the future with + // more realistic networks or a driver which changes it + // according to feedback + + break; + + case GPIOR: + // Only write writable bits + regs.gpior &= GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN + | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN; + regs.gpior |= reg & ~(GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN + | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN); + /* these just control general purpose i/o pins, don't matter */ + break; + + case RXDP: + regs.rxdp = reg; + CRDD = false; + break; + + case RXDP_HI: + regs.rxdp_hi = reg; + break; + + case RX_CFG: + regs.rxcfg = reg; +#if 0 + if (reg & RX_CFG_AEP) ; + if (reg & RX_CFG_ARP) ; + if (reg & RX_CFG_STRIPCRC) ; + if (reg & RX_CFG_RX_RD) ; + if (reg & RX_CFG_ALP) ; + if (reg & RX_CFG_AIRL) ; + + /* we handle our own DMA, ignore what kernel says about it */ + if (reg & RX_CFG_MXDMA) ; + + //also, we currently don't care about fill/drain thresholds + //though this may change in the future with more realistic + //networks or a driver which changes it according to feedback + if (reg & (RX_CFG_DRTH | RX_CFG_DRTH0)) ; +#endif + break; + + case PQCR: + /* there is no priority queueing used in the linux 2.6 driver */ + regs.pqcr = reg; + break; + + case WCSR: + /* not going to implement wake on LAN */ + regs.wcsr = reg; + break; + + case PCR: + /* not going to implement pause control */ + regs.pcr = reg; + break; + + case RFCR: + regs.rfcr = reg; + + rxFilterEnable = (reg & RFCR_RFEN) ? true : false; + acceptBroadcast = (reg & RFCR_AAB) ? true : false; + acceptMulticast = (reg & RFCR_AAM) ? true : false; + acceptUnicast = (reg & RFCR_AAU) ? true : false; + acceptPerfect = (reg & RFCR_APM) ? true : false; + acceptArp = (reg & RFCR_AARP) ? true : false; + multicastHashEnable = (reg & RFCR_MHEN) ? true : false; + +#if 0 + if (reg & RFCR_APAT) + panic("RFCR_APAT not implemented!\n"); +#endif + if (reg & RFCR_UHEN) + panic("Unicast hash filtering not used by drivers!\n"); + + if (reg & RFCR_ULM) + panic("RFCR_ULM not implemented!\n"); + + break; + + case RFDR: + rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR); + switch (rfaddr) { + case 0x000: + rom.perfectMatch[0] = (uint8_t)reg; + rom.perfectMatch[1] = (uint8_t)(reg >> 8); + break; + case 0x002: + rom.perfectMatch[2] = (uint8_t)reg; + rom.perfectMatch[3] = (uint8_t)(reg >> 8); + break; + case 0x004: + rom.perfectMatch[4] = (uint8_t)reg; + rom.perfectMatch[5] = (uint8_t)(reg >> 8); + break; + default: + + if (rfaddr >= FHASH_ADDR && + rfaddr < FHASH_ADDR + FHASH_SIZE) { + + // Only word-aligned writes supported + if (rfaddr % 2) + panic("unaligned write to filter hash table!"); + + rom.filterHash[rfaddr - FHASH_ADDR] = (uint8_t)reg; + rom.filterHash[rfaddr - FHASH_ADDR + 1] + = (uint8_t)(reg >> 8); + break; + } + panic("writing RFDR for something other than pattern matching\ + or hashing! %#x\n", rfaddr); + } + + case BRAR: + regs.brar = reg; + break; + + case BRDR: + panic("the driver never uses BRDR, something is wrong!\n"); + + case SRR: + panic("SRR is read only register!\n"); + + case MIBC: + panic("the driver never uses MIBC, something is wrong!\n"); + + case VRCR: + regs.vrcr = reg; + break; + + case VTCR: + regs.vtcr = reg; + break; + + case VDR: + panic("the driver never uses VDR, something is wrong!\n"); + + case CCSR: + /* not going to implement clockrun stuff */ + regs.ccsr = reg; + break; + + case TBICR: + regs.tbicr = reg; + if (reg & TBICR_MR_LOOPBACK) + panic("TBICR_MR_LOOPBACK never used, something wrong!\n"); + + if (reg & TBICR_MR_AN_ENABLE) { + regs.tanlpar = regs.tanar; + regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS); + } + +#if 0 + if (reg & TBICR_MR_RESTART_AN) ; +#endif + + break; + + case TBISR: + panic("TBISR is read only register!\n"); + + case TANAR: + // Only write the writable bits + regs.tanar &= TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED; + regs.tanar |= reg & ~(TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED); + + // Pause capability unimplemented +#if 0 + if (reg & TANAR_PS2) ; + if (reg & TANAR_PS1) ; +#endif + + break; + + case TANLPAR: + panic("this should only be written to by the fake phy!\n"); + + case TANER: + panic("TANER is read only register!\n"); + + case TESR: + regs.tesr = reg; + break; + + default: + panic("invalid register access daddr=%#x", daddr); + } + } else { + panic("Invalid Request Size"); + } + pkt->result = Packet::Success; + return pioDelay; +} + +void +NSGigE::devIntrPost(uint32_t interrupts) +{ + if (interrupts & ISR_RESERVE) + panic("Cannot set a reserved interrupt"); + + if (interrupts & ISR_NOIMPL) + warn("interrupt not implemented %#x\n", interrupts); + + interrupts &= ISR_IMPL; + regs.isr |= interrupts; + + if (interrupts & regs.imr) { + if (interrupts & ISR_SWI) { + totalSwi++; + } + if (interrupts & ISR_RXIDLE) { + totalRxIdle++; + } + if (interrupts & ISR_RXOK) { + totalRxOk++; + } + if (interrupts & ISR_RXDESC) { + totalRxDesc++; + } + if (interrupts & ISR_TXOK) { + totalTxOk++; + } + if (interrupts & ISR_TXIDLE) { + totalTxIdle++; + } + if (interrupts & ISR_TXDESC) { + totalTxDesc++; + } + if (interrupts & ISR_RXORN) { + totalRxOrn++; + } + } + + DPRINTF(EthernetIntr, + "interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n", + interrupts, regs.isr, regs.imr); + + if ((regs.isr & regs.imr)) { + Tick when = curTick; + if ((regs.isr & regs.imr & ISR_NODELAY) == 0) + when += intrDelay; + cpuIntrPost(when); + } +} + +/* writing this interrupt counting stats inside this means that this function + is now limited to being used to clear all interrupts upon the kernel + reading isr and servicing. just telling you in case you were thinking + of expanding use. +*/ +void +NSGigE::devIntrClear(uint32_t interrupts) +{ + if (interrupts & ISR_RESERVE) + panic("Cannot clear a reserved interrupt"); + + if (regs.isr & regs.imr & ISR_SWI) { + postedSwi++; + } + if (regs.isr & regs.imr & ISR_RXIDLE) { + postedRxIdle++; + } + if (regs.isr & regs.imr & ISR_RXOK) { + postedRxOk++; + } + if (regs.isr & regs.imr & ISR_RXDESC) { + postedRxDesc++; + } + if (regs.isr & regs.imr & ISR_TXOK) { + postedTxOk++; + } + if (regs.isr & regs.imr & ISR_TXIDLE) { + postedTxIdle++; + } + if (regs.isr & regs.imr & ISR_TXDESC) { + postedTxDesc++; + } + if (regs.isr & regs.imr & ISR_RXORN) { + postedRxOrn++; + } + + if (regs.isr & regs.imr & ISR_IMPL) + postedInterrupts++; + + interrupts &= ~ISR_NOIMPL; + regs.isr &= ~interrupts; + + DPRINTF(EthernetIntr, + "interrupt cleared from ISR: intr=%x isr=%x imr=%x\n", + interrupts, regs.isr, regs.imr); + + if (!(regs.isr & regs.imr)) + cpuIntrClear(); +} + +void +NSGigE::devIntrChangeMask() +{ + DPRINTF(EthernetIntr, "interrupt mask changed: isr=%x imr=%x masked=%x\n", + regs.isr, regs.imr, regs.isr & regs.imr); + + if (regs.isr & regs.imr) + cpuIntrPost(curTick); + else + cpuIntrClear(); +} + +void +NSGigE::cpuIntrPost(Tick when) +{ + // If the interrupt you want to post is later than an interrupt + // already scheduled, just let it post in the coming one and don't + // schedule another. + // HOWEVER, must be sure that the scheduled intrTick is in the + // future (this was formerly the source of a bug) + /** + * @todo this warning should be removed and the intrTick code should + * be fixed. + */ + assert(when >= curTick); + assert(intrTick >= curTick || intrTick == 0); + if (when > intrTick && intrTick != 0) { + DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n", + intrTick); + return; + } + + intrTick = when; + if (intrTick < curTick) { + debug_break(); + intrTick = curTick; + } + + DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n", + intrTick); + + if (intrEvent) + intrEvent->squash(); + intrEvent = new IntrEvent(this, true); + intrEvent->schedule(intrTick); +} + +void +NSGigE::cpuInterrupt() +{ + assert(intrTick == curTick); + + // Whether or not there's a pending interrupt, we don't care about + // it anymore + intrEvent = 0; + intrTick = 0; + + // Don't send an interrupt if there's already one + if (cpuPendingIntr) { + DPRINTF(EthernetIntr, + "would send an interrupt now, but there's already pending\n"); + } else { + // Send interrupt + cpuPendingIntr = true; + + DPRINTF(EthernetIntr, "posting interrupt\n"); + intrPost(); + } +} + +void +NSGigE::cpuIntrClear() +{ + if (!cpuPendingIntr) + return; + + if (intrEvent) { + intrEvent->squash(); + intrEvent = 0; + } + + intrTick = 0; + + cpuPendingIntr = false; + + DPRINTF(EthernetIntr, "clearing interrupt\n"); + intrClear(); +} + +bool +NSGigE::cpuIntrPending() const +{ return cpuPendingIntr; } + +void +NSGigE::txReset() +{ + + DPRINTF(Ethernet, "transmit reset\n"); + + CTDD = false; + txEnable = false;; + txFragPtr = 0; + assert(txDescCnt == 0); + txFifo.clear(); + txState = txIdle; + assert(txDmaState == dmaIdle); +} + +void +NSGigE::rxReset() +{ + DPRINTF(Ethernet, "receive reset\n"); + + CRDD = false; + assert(rxPktBytes == 0); + rxEnable = false; + rxFragPtr = 0; + assert(rxDescCnt == 0); + assert(rxDmaState == dmaIdle); + rxFifo.clear(); + rxState = rxIdle; +} + +void +NSGigE::regsReset() +{ + memset(®s, 0, sizeof(regs)); + regs.config = (CFGR_LNKSTS | CFGR_TBI_EN | CFGR_MODE_1000); + regs.mear = 0x12; + regs.txcfg = 0x120; // set drain threshold to 1024 bytes and + // fill threshold to 32 bytes + regs.rxcfg = 0x4; // set drain threshold to 16 bytes + regs.srr = 0x0103; // set the silicon revision to rev B or 0x103 + regs.mibc = MIBC_FRZ; + regs.vdr = 0x81; // set the vlan tag type to 802.1q + regs.tesr = 0xc000; // TBI capable of both full and half duplex + regs.brar = 0xffffffff; + + extstsEnable = false; + acceptBroadcast = false; + acceptMulticast = false; + acceptUnicast = false; + acceptPerfect = false; + acceptArp = false; +} + +bool +NSGigE::doRxDmaRead() +{ + assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting); + rxDmaState = dmaReading; + + if (dmaPending()) + rxDmaState = dmaReadWaiting; + else + dmaRead(rxDmaAddr, rxDmaLen, &rxDmaReadEvent, (uint8_t*)rxDmaData); + + return true; +} + +void +NSGigE::rxDmaReadDone() +{ + assert(rxDmaState == dmaReading); + rxDmaState = dmaIdle; + + DPRINTF(EthernetDMA, "rx dma read paddr=%#x len=%d\n", + rxDmaAddr, rxDmaLen); + DDUMP(EthernetDMA, rxDmaData, rxDmaLen); + + // If the transmit state machine has a pending DMA, let it go first + if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) + txKick(); + + rxKick(); +} + +bool +NSGigE::doRxDmaWrite() +{ + assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting); + rxDmaState = dmaWriting; + + if (dmaPending()) + rxDmaState = dmaWriteWaiting; + else + dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaWriteEvent, (uint8_t*)rxDmaData); + return true; +} + +void +NSGigE::rxDmaWriteDone() +{ + assert(rxDmaState == dmaWriting); + rxDmaState = dmaIdle; + + DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n", + rxDmaAddr, rxDmaLen); + DDUMP(EthernetDMA, rxDmaData, rxDmaLen); + + // If the transmit state machine has a pending DMA, let it go first + if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) + txKick(); + + rxKick(); +} + +void +NSGigE::rxKick() +{ + bool is64bit = (bool)(regs.config & CFGR_M64ADDR); + + DPRINTF(EthernetSM, + "receive kick rxState=%s (rxBuf.size=%d) %d-bit\n", + NsRxStateStrings[rxState], rxFifo.size(), is64bit ? 64 : 32); + + Addr link, bufptr; + uint32_t &cmdsts = is64bit ? rxDesc64.cmdsts : rxDesc32.cmdsts; + uint32_t &extsts = is64bit ? rxDesc64.extsts : rxDesc32.extsts; + + next: + if (clock) { + if (rxKickTick > curTick) { + DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n", + rxKickTick); + + goto exit; + } + + // Go to the next state machine clock tick. + rxKickTick = curTick + cycles(1); + } + + switch(rxDmaState) { + case dmaReadWaiting: + if (doRxDmaRead()) + goto exit; + break; + case dmaWriteWaiting: + if (doRxDmaWrite()) + goto exit; + break; + default: + break; + } + + link = is64bit ? (Addr)rxDesc64.link : (Addr)rxDesc32.link; + bufptr = is64bit ? (Addr)rxDesc64.bufptr : (Addr)rxDesc32.bufptr; + + // see state machine from spec for details + // the way this works is, if you finish work on one state and can + // go directly to another, you do that through jumping to the + // label "next". however, if you have intermediate work, like DMA + // so that you can't go to the next state yet, you go to exit and + // exit the loop. however, when the DMA is done it will trigger + // an event and come back to this loop. + switch (rxState) { + case rxIdle: + if (!rxEnable) { + DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n"); + goto exit; + } + + if (CRDD) { + rxState = rxDescRefr; + + rxDmaAddr = regs.rxdp & 0x3fffffff; + rxDmaData = + is64bit ? (void *)&rxDesc64.link : (void *)&rxDesc32.link; + rxDmaLen = is64bit ? sizeof(rxDesc64.link) : sizeof(rxDesc32.link); + rxDmaFree = dmaDescFree; + + descDmaReads++; + descDmaRdBytes += rxDmaLen; + + if (doRxDmaRead()) + goto exit; + } else { + rxState = rxDescRead; + + rxDmaAddr = regs.rxdp & 0x3fffffff; + rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32; + rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32); + rxDmaFree = dmaDescFree; + + descDmaReads++; + descDmaRdBytes += rxDmaLen; + + if (doRxDmaRead()) + goto exit; + } + break; + + case rxDescRefr: + if (rxDmaState != dmaIdle) + goto exit; + + rxState = rxAdvance; + break; + + case rxDescRead: + if (rxDmaState != dmaIdle) + goto exit; + + DPRINTF(EthernetDesc, "rxDesc: addr=%08x read descriptor\n", + regs.rxdp & 0x3fffffff); + DPRINTF(EthernetDesc, + "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n", + link, bufptr, cmdsts, extsts); + + if (cmdsts & CMDSTS_OWN) { + devIntrPost(ISR_RXIDLE); + rxState = rxIdle; + goto exit; + } else { + rxState = rxFifoBlock; + rxFragPtr = bufptr; + rxDescCnt = cmdsts & CMDSTS_LEN_MASK; + } + break; + + case rxFifoBlock: + if (!rxPacket) { + /** + * @todo in reality, we should be able to start processing + * the packet as it arrives, and not have to wait for the + * full packet ot be in the receive fifo. + */ + if (rxFifo.empty()) + goto exit; + + DPRINTF(EthernetSM, "****processing receive of new packet****\n"); + + // If we don't have a packet, grab a new one from the fifo. + rxPacket = rxFifo.front(); + rxPktBytes = rxPacket->length; + rxPacketBufPtr = rxPacket->data; + +#if TRACING_ON + if (DTRACE(Ethernet)) { + IpPtr ip(rxPacket); + if (ip) { + DPRINTF(Ethernet, "ID is %d\n", ip->id()); + TcpPtr tcp(ip); + if (tcp) { + DPRINTF(Ethernet, + "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", + tcp->sport(), tcp->dport(), tcp->seq(), + tcp->ack()); + } + } + } +#endif + + // sanity check - i think the driver behaves like this + assert(rxDescCnt >= rxPktBytes); + rxFifo.pop(); + } + + + // dont' need the && rxDescCnt > 0 if driver sanity check + // above holds + if (rxPktBytes > 0) { + rxState = rxFragWrite; + // don't need min<>(rxPktBytes,rxDescCnt) if above sanity + // check holds + rxXferLen = rxPktBytes; + + rxDmaAddr = rxFragPtr & 0x3fffffff; + rxDmaData = rxPacketBufPtr; + rxDmaLen = rxXferLen; + rxDmaFree = dmaDataFree; + + if (doRxDmaWrite()) + goto exit; + + } else { + rxState = rxDescWrite; + + //if (rxPktBytes == 0) { /* packet is done */ + assert(rxPktBytes == 0); + DPRINTF(EthernetSM, "done with receiving packet\n"); + + cmdsts |= CMDSTS_OWN; + cmdsts &= ~CMDSTS_MORE; + cmdsts |= CMDSTS_OK; + cmdsts &= 0xffff0000; + cmdsts += rxPacket->length; //i.e. set CMDSTS_SIZE + +#if 0 + /* + * all the driver uses these are for its own stats keeping + * which we don't care about, aren't necessary for + * functionality and doing this would just slow us down. + * if they end up using this in a later version for + * functional purposes, just undef + */ + if (rxFilterEnable) { + cmdsts &= ~CMDSTS_DEST_MASK; + const EthAddr &dst = rxFifoFront()->dst(); + if (dst->unicast()) + cmdsts |= CMDSTS_DEST_SELF; + if (dst->multicast()) + cmdsts |= CMDSTS_DEST_MULTI; + if (dst->broadcast()) + cmdsts |= CMDSTS_DEST_MASK; + } +#endif + + IpPtr ip(rxPacket); + if (extstsEnable && ip) { + extsts |= EXTSTS_IPPKT; + rxIpChecksums++; + if (cksum(ip) != 0) { + DPRINTF(EthernetCksum, "Rx IP Checksum Error\n"); + extsts |= EXTSTS_IPERR; + } + TcpPtr tcp(ip); + UdpPtr udp(ip); + if (tcp) { + extsts |= EXTSTS_TCPPKT; + rxTcpChecksums++; + if (cksum(tcp) != 0) { + DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n"); + extsts |= EXTSTS_TCPERR; + + } + } else if (udp) { + extsts |= EXTSTS_UDPPKT; + rxUdpChecksums++; + if (cksum(udp) != 0) { + DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n"); + extsts |= EXTSTS_UDPERR; + } + } + } + rxPacket = 0; + + /* + * the driver seems to always receive into desc buffers + * of size 1514, so you never have a pkt that is split + * into multiple descriptors on the receive side, so + * i don't implement that case, hence the assert above. + */ + + DPRINTF(EthernetDesc, + "rxDesc: addr=%08x writeback cmdsts extsts\n", + regs.rxdp & 0x3fffffff); + DPRINTF(EthernetDesc, + "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n", + link, bufptr, cmdsts, extsts); + + rxDmaAddr = regs.rxdp & 0x3fffffff; + rxDmaData = &cmdsts; + if (is64bit) { + rxDmaAddr += offsetof(ns_desc64, cmdsts); + rxDmaLen = sizeof(rxDesc64.cmdsts) + sizeof(rxDesc64.extsts); + } else { + rxDmaAddr += offsetof(ns_desc32, cmdsts); + rxDmaLen = sizeof(rxDesc32.cmdsts) + sizeof(rxDesc32.extsts); + } + rxDmaFree = dmaDescFree; + + descDmaWrites++; + descDmaWrBytes += rxDmaLen; + + if (doRxDmaWrite()) + goto exit; + } + break; + + case rxFragWrite: + if (rxDmaState != dmaIdle) + goto exit; + + rxPacketBufPtr += rxXferLen; + rxFragPtr += rxXferLen; + rxPktBytes -= rxXferLen; + + rxState = rxFifoBlock; + break; + + case rxDescWrite: + if (rxDmaState != dmaIdle) + goto exit; + + assert(cmdsts & CMDSTS_OWN); + + assert(rxPacket == 0); + devIntrPost(ISR_RXOK); + + if (cmdsts & CMDSTS_INTR) + devIntrPost(ISR_RXDESC); + + if (!rxEnable) { + DPRINTF(EthernetSM, "Halting the RX state machine\n"); + rxState = rxIdle; + goto exit; + } else + rxState = rxAdvance; + break; + + case rxAdvance: + if (link == 0) { + devIntrPost(ISR_RXIDLE); + rxState = rxIdle; + CRDD = true; + goto exit; + } else { + if (rxDmaState != dmaIdle) + goto exit; + rxState = rxDescRead; + regs.rxdp = link; + CRDD = false; + + rxDmaAddr = regs.rxdp & 0x3fffffff; + rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32; + rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32); + rxDmaFree = dmaDescFree; + + if (doRxDmaRead()) + goto exit; + } + break; + + default: + panic("Invalid rxState!"); + } + + DPRINTF(EthernetSM, "entering next rxState=%s\n", + NsRxStateStrings[rxState]); + goto next; + + exit: + /** + * @todo do we want to schedule a future kick? + */ + DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n", + NsRxStateStrings[rxState]); + + if (clock && !rxKickEvent.scheduled()) + rxKickEvent.schedule(rxKickTick); +} + +void +NSGigE::transmit() +{ + if (txFifo.empty()) { + DPRINTF(Ethernet, "nothing to transmit\n"); + return; + } + + DPRINTF(Ethernet, "Attempt Pkt Transmit: txFifo length=%d\n", + txFifo.size()); + if (interface->sendPacket(txFifo.front())) { +#if TRACING_ON + if (DTRACE(Ethernet)) { + IpPtr ip(txFifo.front()); + if (ip) { + DPRINTF(Ethernet, "ID is %d\n", ip->id()); + TcpPtr tcp(ip); + if (tcp) { + DPRINTF(Ethernet, + "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", + tcp->sport(), tcp->dport(), tcp->seq(), + tcp->ack()); + } + } + } +#endif + + DDUMP(EthernetData, txFifo.front()->data, txFifo.front()->length); + txBytes += txFifo.front()->length; + txPackets++; + + DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n", + txFifo.avail()); + txFifo.pop(); + + /* + * normally do a writeback of the descriptor here, and ONLY + * after that is done, send this interrupt. but since our + * stuff never actually fails, just do this interrupt here, + * otherwise the code has to stray from this nice format. + * besides, it's functionally the same. + */ + devIntrPost(ISR_TXOK); + } + + if (!txFifo.empty() && !txEvent.scheduled()) { + DPRINTF(Ethernet, "reschedule transmit\n"); + txEvent.schedule(curTick + retryTime); + } +} + +bool +NSGigE::doTxDmaRead() +{ + assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting); + txDmaState = dmaReading; + + if (dmaPending()) + txDmaState = dmaReadWaiting; + else + dmaRead(txDmaAddr, txDmaLen, &txDmaReadEvent, (uint8_t*)txDmaData); + + return true; +} + +void +NSGigE::txDmaReadDone() +{ + assert(txDmaState == dmaReading); + txDmaState = dmaIdle; + + DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n", + txDmaAddr, txDmaLen); + DDUMP(EthernetDMA, txDmaData, txDmaLen); + + // If the receive state machine has a pending DMA, let it go first + if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) + rxKick(); + + txKick(); +} + +bool +NSGigE::doTxDmaWrite() +{ + assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting); + txDmaState = dmaWriting; + + if (dmaPending()) + txDmaState = dmaWriteWaiting; + else + dmaWrite(txDmaAddr, txDmaLen, &txDmaWriteEvent, (uint8_t*)txDmaData); + return true; +} + +void +NSGigE::txDmaWriteDone() +{ + assert(txDmaState == dmaWriting); + txDmaState = dmaIdle; + + DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n", + txDmaAddr, txDmaLen); + DDUMP(EthernetDMA, txDmaData, txDmaLen); + + // If the receive state machine has a pending DMA, let it go first + if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) + rxKick(); + + txKick(); +} + +void +NSGigE::txKick() +{ + bool is64bit = (bool)(regs.config & CFGR_M64ADDR); + + DPRINTF(EthernetSM, "transmit kick txState=%s %d-bit\n", + NsTxStateStrings[txState], is64bit ? 64 : 32); + + Addr link, bufptr; + uint32_t &cmdsts = is64bit ? txDesc64.cmdsts : txDesc32.cmdsts; + uint32_t &extsts = is64bit ? txDesc64.extsts : txDesc32.extsts; + + next: + if (clock) { + if (txKickTick > curTick) { + DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n", + txKickTick); + goto exit; + } + + // Go to the next state machine clock tick. + txKickTick = curTick + cycles(1); + } + + switch(txDmaState) { + case dmaReadWaiting: + if (doTxDmaRead()) + goto exit; + break; + case dmaWriteWaiting: + if (doTxDmaWrite()) + goto exit; + break; + default: + break; + } + + link = is64bit ? (Addr)txDesc64.link : (Addr)txDesc32.link; + bufptr = is64bit ? (Addr)txDesc64.bufptr : (Addr)txDesc32.bufptr; + switch (txState) { + case txIdle: + if (!txEnable) { + DPRINTF(EthernetSM, "Transmit disabled. Nothing to do.\n"); + goto exit; + } + + if (CTDD) { + txState = txDescRefr; + + txDmaAddr = regs.txdp & 0x3fffffff; + txDmaData = + is64bit ? (void *)&txDesc64.link : (void *)&txDesc32.link; + txDmaLen = is64bit ? sizeof(txDesc64.link) : sizeof(txDesc32.link); + txDmaFree = dmaDescFree; + + descDmaReads++; + descDmaRdBytes += txDmaLen; + + if (doTxDmaRead()) + goto exit; + + } else { + txState = txDescRead; + + txDmaAddr = regs.txdp & 0x3fffffff; + txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32; + txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32); + txDmaFree = dmaDescFree; + + descDmaReads++; + descDmaRdBytes += txDmaLen; + + if (doTxDmaRead()) + goto exit; + } + break; + + case txDescRefr: + if (txDmaState != dmaIdle) + goto exit; + + txState = txAdvance; + break; + + case txDescRead: + if (txDmaState != dmaIdle) + goto exit; + + DPRINTF(EthernetDesc, "txDesc: addr=%08x read descriptor\n", + regs.txdp & 0x3fffffff); + DPRINTF(EthernetDesc, + "txDesc: link=%#x bufptr=%#x cmdsts=%#08x extsts=%#08x\n", + link, bufptr, cmdsts, extsts); + + if (cmdsts & CMDSTS_OWN) { + txState = txFifoBlock; + txFragPtr = bufptr; + txDescCnt = cmdsts & CMDSTS_LEN_MASK; + } else { + devIntrPost(ISR_TXIDLE); + txState = txIdle; + goto exit; + } + break; + + case txFifoBlock: + if (!txPacket) { + DPRINTF(EthernetSM, "****starting the tx of a new packet****\n"); + txPacket = new EthPacketData(16384); + txPacketBufPtr = txPacket->data; + } + + if (txDescCnt == 0) { + DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n"); + if (cmdsts & CMDSTS_MORE) { + DPRINTF(EthernetSM, "there are more descriptors to come\n"); + txState = txDescWrite; + + cmdsts &= ~CMDSTS_OWN; + + txDmaAddr = regs.txdp & 0x3fffffff; + txDmaData = &cmdsts; + if (is64bit) { + txDmaAddr += offsetof(ns_desc64, cmdsts); + txDmaLen = sizeof(txDesc64.cmdsts); + } else { + txDmaAddr += offsetof(ns_desc32, cmdsts); + txDmaLen = sizeof(txDesc32.cmdsts); + } + txDmaFree = dmaDescFree; + + if (doTxDmaWrite()) + goto exit; + + } else { /* this packet is totally done */ + DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n"); + /* deal with the the packet that just finished */ + if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) { + IpPtr ip(txPacket); + if (extsts & EXTSTS_UDPPKT) { + UdpPtr udp(ip); + udp->sum(0); + udp->sum(cksum(udp)); + txUdpChecksums++; + } else if (extsts & EXTSTS_TCPPKT) { + TcpPtr tcp(ip); + tcp->sum(0); + tcp->sum(cksum(tcp)); + txTcpChecksums++; + } + if (extsts & EXTSTS_IPPKT) { + ip->sum(0); + ip->sum(cksum(ip)); + txIpChecksums++; + } + } + + txPacket->length = txPacketBufPtr - txPacket->data; + // this is just because the receive can't handle a + // packet bigger want to make sure + if (txPacket->length > 1514) + panic("transmit packet too large, %s > 1514\n", + txPacket->length); + +#ifndef NDEBUG + bool success = +#endif + txFifo.push(txPacket); + assert(success); + + /* + * this following section is not tqo spec, but + * functionally shouldn't be any different. normally, + * the chip will wait til the transmit has occurred + * before writing back the descriptor because it has + * to wait to see that it was successfully transmitted + * to decide whether to set CMDSTS_OK or not. + * however, in the simulator since it is always + * successfully transmitted, and writing it exactly to + * spec would complicate the code, we just do it here + */ + + cmdsts &= ~CMDSTS_OWN; + cmdsts |= CMDSTS_OK; + + DPRINTF(EthernetDesc, + "txDesc writeback: cmdsts=%08x extsts=%08x\n", + cmdsts, extsts); + + txDmaFree = dmaDescFree; + txDmaAddr = regs.txdp & 0x3fffffff; + txDmaData = &cmdsts; + if (is64bit) { + txDmaAddr += offsetof(ns_desc64, cmdsts); + txDmaLen = + sizeof(txDesc64.cmdsts) + sizeof(txDesc64.extsts); + } else { + txDmaAddr += offsetof(ns_desc32, cmdsts); + txDmaLen = + sizeof(txDesc32.cmdsts) + sizeof(txDesc32.extsts); + } + + descDmaWrites++; + descDmaWrBytes += txDmaLen; + + transmit(); + txPacket = 0; + + if (!txEnable) { + DPRINTF(EthernetSM, "halting TX state machine\n"); + txState = txIdle; + goto exit; + } else + txState = txAdvance; + + if (doTxDmaWrite()) + goto exit; + } + } else { + DPRINTF(EthernetSM, "this descriptor isn't done yet\n"); + if (!txFifo.full()) { + txState = txFragRead; + + /* + * The number of bytes transferred is either whatever + * is left in the descriptor (txDescCnt), or if there + * is not enough room in the fifo, just whatever room + * is left in the fifo + */ + txXferLen = min<uint32_t>(txDescCnt, txFifo.avail()); + + txDmaAddr = txFragPtr & 0x3fffffff; + txDmaData = txPacketBufPtr; + txDmaLen = txXferLen; + txDmaFree = dmaDataFree; + + if (doTxDmaRead()) + goto exit; + } else { + txState = txFifoBlock; + transmit(); + + goto exit; + } + + } + break; + + case txFragRead: + if (txDmaState != dmaIdle) + goto exit; + + txPacketBufPtr += txXferLen; + txFragPtr += txXferLen; + txDescCnt -= txXferLen; + txFifo.reserve(txXferLen); + + txState = txFifoBlock; + break; + + case txDescWrite: + if (txDmaState != dmaIdle) + goto exit; + + if (cmdsts & CMDSTS_INTR) + devIntrPost(ISR_TXDESC); + + if (!txEnable) { + DPRINTF(EthernetSM, "halting TX state machine\n"); + txState = txIdle; + goto exit; + } else + txState = txAdvance; + break; + + case txAdvance: + if (link == 0) { + devIntrPost(ISR_TXIDLE); + txState = txIdle; + goto exit; + } else { + if (txDmaState != dmaIdle) + goto exit; + txState = txDescRead; + regs.txdp = link; + CTDD = false; + + txDmaAddr = link & 0x3fffffff; + txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32; + txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32); + txDmaFree = dmaDescFree; + + if (doTxDmaRead()) + goto exit; + } + break; + + default: + panic("invalid state"); + } + + DPRINTF(EthernetSM, "entering next txState=%s\n", + NsTxStateStrings[txState]); + goto next; + + exit: + /** + * @todo do we want to schedule a future kick? + */ + DPRINTF(EthernetSM, "tx state machine exited txState=%s\n", + NsTxStateStrings[txState]); + + if (clock && !txKickEvent.scheduled()) + txKickEvent.schedule(txKickTick); +} + +/** + * Advance the EEPROM state machine + * Called on rising edge of EEPROM clock bit in MEAR + */ +void +NSGigE::eepromKick() +{ + switch (eepromState) { + + case eepromStart: + + // Wait for start bit + if (regs.mear & MEAR_EEDI) { + // Set up to get 2 opcode bits + eepromState = eepromGetOpcode; + eepromBitsToRx = 2; + eepromOpcode = 0; + } + break; + + case eepromGetOpcode: + eepromOpcode <<= 1; + eepromOpcode += (regs.mear & MEAR_EEDI) ? 1 : 0; + --eepromBitsToRx; + + // Done getting opcode + if (eepromBitsToRx == 0) { + if (eepromOpcode != EEPROM_READ) + panic("only EEPROM reads are implemented!"); + + // Set up to get address + eepromState = eepromGetAddress; + eepromBitsToRx = 6; + eepromAddress = 0; + } + break; + + case eepromGetAddress: + eepromAddress <<= 1; + eepromAddress += (regs.mear & MEAR_EEDI) ? 1 : 0; + --eepromBitsToRx; + + // Done getting address + if (eepromBitsToRx == 0) { + + if (eepromAddress >= EEPROM_SIZE) + panic("EEPROM read access out of range!"); + + switch (eepromAddress) { + + case EEPROM_PMATCH2_ADDR: + eepromData = rom.perfectMatch[5]; + eepromData <<= 8; + eepromData += rom.perfectMatch[4]; + break; + + case EEPROM_PMATCH1_ADDR: + eepromData = rom.perfectMatch[3]; + eepromData <<= 8; + eepromData += rom.perfectMatch[2]; + break; + + case EEPROM_PMATCH0_ADDR: + eepromData = rom.perfectMatch[1]; + eepromData <<= 8; + eepromData += rom.perfectMatch[0]; + break; + + default: + panic("FreeBSD driver only uses EEPROM to read PMATCH!"); + } + // Set up to read data + eepromState = eepromRead; + eepromBitsToRx = 16; + + // Clear data in bit + regs.mear &= ~MEAR_EEDI; + } + break; + + case eepromRead: + // Clear Data Out bit + regs.mear &= ~MEAR_EEDO; + // Set bit to value of current EEPROM bit + regs.mear |= (eepromData & 0x8000) ? MEAR_EEDO : 0x0; + + eepromData <<= 1; + --eepromBitsToRx; + + // All done + if (eepromBitsToRx == 0) { + eepromState = eepromStart; + } + break; + + default: + panic("invalid EEPROM state"); + } + +} + +void +NSGigE::transferDone() +{ + if (txFifo.empty()) { + DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n"); + return; + } + + DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n"); + + if (txEvent.scheduled()) + txEvent.reschedule(curTick + cycles(1)); + else + txEvent.schedule(curTick + cycles(1)); +} + +bool +NSGigE::rxFilter(const EthPacketPtr &packet) +{ + EthPtr eth = packet; + bool drop = true; + string type; + + const EthAddr &dst = eth->dst(); + if (dst.unicast()) { + // If we're accepting all unicast addresses + if (acceptUnicast) + drop = false; + + // If we make a perfect match + if (acceptPerfect && dst == rom.perfectMatch) + drop = false; + + if (acceptArp && eth->type() == ETH_TYPE_ARP) + drop = false; + + } else if (dst.broadcast()) { + // if we're accepting broadcasts + if (acceptBroadcast) + drop = false; + + } else if (dst.multicast()) { + // if we're accepting all multicasts + if (acceptMulticast) + drop = false; + + // Multicast hashing faked - all packets accepted + if (multicastHashEnable) + drop = false; + } + + if (drop) { + DPRINTF(Ethernet, "rxFilter drop\n"); + DDUMP(EthernetData, packet->data, packet->length); + } + + return drop; +} + +bool +NSGigE::recvPacket(EthPacketPtr packet) +{ + rxBytes += packet->length; + rxPackets++; + + DPRINTF(Ethernet, "Receiving packet from wire, rxFifoAvail=%d\n", + rxFifo.avail()); + + if (!rxEnable) { + DPRINTF(Ethernet, "receive disabled...packet dropped\n"); + return true; + } + + if (!rxFilterEnable) { + DPRINTF(Ethernet, + "receive packet filtering disabled . . . packet dropped\n"); + return true; + } + + if (rxFilter(packet)) { + DPRINTF(Ethernet, "packet filtered...dropped\n"); + return true; + } + + if (rxFifo.avail() < packet->length) { +#if TRACING_ON + IpPtr ip(packet); + TcpPtr tcp(ip); + if (ip) { + DPRINTF(Ethernet, + "packet won't fit in receive buffer...pkt ID %d dropped\n", + ip->id()); + if (tcp) { + DPRINTF(Ethernet, "Seq=%d\n", tcp->seq()); + } + } +#endif + droppedPackets++; + devIntrPost(ISR_RXORN); + return false; + } + + rxFifo.push(packet); + + rxKick(); + return true; +} + +//===================================================================== +// +// +void +NSGigE::serialize(ostream &os) +{ + // Serialize the PciDev base class + PciDev::serialize(os); + + /* + * Finalize any DMA events now. + */ + // @todo will mem system save pending dma? + + /* + * Serialize the device registers + */ + SERIALIZE_SCALAR(regs.command); + SERIALIZE_SCALAR(regs.config); + SERIALIZE_SCALAR(regs.mear); + SERIALIZE_SCALAR(regs.ptscr); + SERIALIZE_SCALAR(regs.isr); + SERIALIZE_SCALAR(regs.imr); + SERIALIZE_SCALAR(regs.ier); + SERIALIZE_SCALAR(regs.ihr); + SERIALIZE_SCALAR(regs.txdp); + SERIALIZE_SCALAR(regs.txdp_hi); + SERIALIZE_SCALAR(regs.txcfg); + SERIALIZE_SCALAR(regs.gpior); + SERIALIZE_SCALAR(regs.rxdp); + SERIALIZE_SCALAR(regs.rxdp_hi); + SERIALIZE_SCALAR(regs.rxcfg); + SERIALIZE_SCALAR(regs.pqcr); + SERIALIZE_SCALAR(regs.wcsr); + SERIALIZE_SCALAR(regs.pcr); + SERIALIZE_SCALAR(regs.rfcr); + SERIALIZE_SCALAR(regs.rfdr); + SERIALIZE_SCALAR(regs.brar); + SERIALIZE_SCALAR(regs.brdr); + SERIALIZE_SCALAR(regs.srr); + SERIALIZE_SCALAR(regs.mibc); + SERIALIZE_SCALAR(regs.vrcr); + SERIALIZE_SCALAR(regs.vtcr); + SERIALIZE_SCALAR(regs.vdr); + SERIALIZE_SCALAR(regs.ccsr); + SERIALIZE_SCALAR(regs.tbicr); + SERIALIZE_SCALAR(regs.tbisr); + SERIALIZE_SCALAR(regs.tanar); + SERIALIZE_SCALAR(regs.tanlpar); + SERIALIZE_SCALAR(regs.taner); + SERIALIZE_SCALAR(regs.tesr); + + SERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN); + SERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE); + + SERIALIZE_SCALAR(ioEnable); + + /* + * Serialize the data Fifos + */ + rxFifo.serialize("rxFifo", os); + txFifo.serialize("txFifo", os); + + /* + * Serialize the various helper variables + */ + bool txPacketExists = txPacket; + SERIALIZE_SCALAR(txPacketExists); + if (txPacketExists) { + txPacket->length = txPacketBufPtr - txPacket->data; + txPacket->serialize("txPacket", os); + uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data); + SERIALIZE_SCALAR(txPktBufPtr); + } + + bool rxPacketExists = rxPacket; + SERIALIZE_SCALAR(rxPacketExists); + if (rxPacketExists) { + rxPacket->serialize("rxPacket", os); + uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data); + SERIALIZE_SCALAR(rxPktBufPtr); + } + + SERIALIZE_SCALAR(txXferLen); + SERIALIZE_SCALAR(rxXferLen); + + /* + * Serialize Cached Descriptors + */ + SERIALIZE_SCALAR(rxDesc64.link); + SERIALIZE_SCALAR(rxDesc64.bufptr); + SERIALIZE_SCALAR(rxDesc64.cmdsts); + SERIALIZE_SCALAR(rxDesc64.extsts); + SERIALIZE_SCALAR(txDesc64.link); + SERIALIZE_SCALAR(txDesc64.bufptr); + SERIALIZE_SCALAR(txDesc64.cmdsts); + SERIALIZE_SCALAR(txDesc64.extsts); + SERIALIZE_SCALAR(rxDesc32.link); + SERIALIZE_SCALAR(rxDesc32.bufptr); + SERIALIZE_SCALAR(rxDesc32.cmdsts); + SERIALIZE_SCALAR(rxDesc32.extsts); + SERIALIZE_SCALAR(txDesc32.link); + SERIALIZE_SCALAR(txDesc32.bufptr); + SERIALIZE_SCALAR(txDesc32.cmdsts); + SERIALIZE_SCALAR(txDesc32.extsts); + SERIALIZE_SCALAR(extstsEnable); + + /* + * Serialize tx state machine + */ + int txState = this->txState; + SERIALIZE_SCALAR(txState); + SERIALIZE_SCALAR(txEnable); + SERIALIZE_SCALAR(CTDD); + SERIALIZE_SCALAR(txFragPtr); + SERIALIZE_SCALAR(txDescCnt); + int txDmaState = this->txDmaState; + SERIALIZE_SCALAR(txDmaState); + SERIALIZE_SCALAR(txKickTick); + + /* + * Serialize rx state machine + */ + int rxState = this->rxState; + SERIALIZE_SCALAR(rxState); + SERIALIZE_SCALAR(rxEnable); + SERIALIZE_SCALAR(CRDD); + SERIALIZE_SCALAR(rxPktBytes); + SERIALIZE_SCALAR(rxFragPtr); + SERIALIZE_SCALAR(rxDescCnt); + int rxDmaState = this->rxDmaState; + SERIALIZE_SCALAR(rxDmaState); + SERIALIZE_SCALAR(rxKickTick); + + /* + * Serialize EEPROM state machine + */ + int eepromState = this->eepromState; + SERIALIZE_SCALAR(eepromState); + SERIALIZE_SCALAR(eepromClk); + SERIALIZE_SCALAR(eepromBitsToRx); + SERIALIZE_SCALAR(eepromOpcode); + SERIALIZE_SCALAR(eepromAddress); + SERIALIZE_SCALAR(eepromData); + + /* + * If there's a pending transmit, store the time so we can + * reschedule it later + */ + Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0; + SERIALIZE_SCALAR(transmitTick); + + /* + * receive address filter settings + */ + SERIALIZE_SCALAR(rxFilterEnable); + SERIALIZE_SCALAR(acceptBroadcast); + SERIALIZE_SCALAR(acceptMulticast); + SERIALIZE_SCALAR(acceptUnicast); + SERIALIZE_SCALAR(acceptPerfect); + SERIALIZE_SCALAR(acceptArp); + SERIALIZE_SCALAR(multicastHashEnable); + + /* + * Keep track of pending interrupt status. + */ + SERIALIZE_SCALAR(intrTick); + SERIALIZE_SCALAR(cpuPendingIntr); + Tick intrEventTick = 0; + if (intrEvent) + intrEventTick = intrEvent->when(); + SERIALIZE_SCALAR(intrEventTick); + +} + +void +NSGigE::unserialize(Checkpoint *cp, const std::string §ion) +{ + // Unserialize the PciDev base class + PciDev::unserialize(cp, section); + + UNSERIALIZE_SCALAR(regs.command); + UNSERIALIZE_SCALAR(regs.config); + UNSERIALIZE_SCALAR(regs.mear); + UNSERIALIZE_SCALAR(regs.ptscr); + UNSERIALIZE_SCALAR(regs.isr); + UNSERIALIZE_SCALAR(regs.imr); + UNSERIALIZE_SCALAR(regs.ier); + UNSERIALIZE_SCALAR(regs.ihr); + UNSERIALIZE_SCALAR(regs.txdp); + UNSERIALIZE_SCALAR(regs.txdp_hi); + UNSERIALIZE_SCALAR(regs.txcfg); + UNSERIALIZE_SCALAR(regs.gpior); + UNSERIALIZE_SCALAR(regs.rxdp); + UNSERIALIZE_SCALAR(regs.rxdp_hi); + UNSERIALIZE_SCALAR(regs.rxcfg); + UNSERIALIZE_SCALAR(regs.pqcr); + UNSERIALIZE_SCALAR(regs.wcsr); + UNSERIALIZE_SCALAR(regs.pcr); + UNSERIALIZE_SCALAR(regs.rfcr); + UNSERIALIZE_SCALAR(regs.rfdr); + UNSERIALIZE_SCALAR(regs.brar); + UNSERIALIZE_SCALAR(regs.brdr); + UNSERIALIZE_SCALAR(regs.srr); + UNSERIALIZE_SCALAR(regs.mibc); + UNSERIALIZE_SCALAR(regs.vrcr); + UNSERIALIZE_SCALAR(regs.vtcr); + UNSERIALIZE_SCALAR(regs.vdr); + UNSERIALIZE_SCALAR(regs.ccsr); + UNSERIALIZE_SCALAR(regs.tbicr); + UNSERIALIZE_SCALAR(regs.tbisr); + UNSERIALIZE_SCALAR(regs.tanar); + UNSERIALIZE_SCALAR(regs.tanlpar); + UNSERIALIZE_SCALAR(regs.taner); + UNSERIALIZE_SCALAR(regs.tesr); + + UNSERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN); + UNSERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE); + + UNSERIALIZE_SCALAR(ioEnable); + + /* + * unserialize the data fifos + */ + rxFifo.unserialize("rxFifo", cp, section); + txFifo.unserialize("txFifo", cp, section); + + /* + * unserialize the various helper variables + */ + bool txPacketExists; + UNSERIALIZE_SCALAR(txPacketExists); + if (txPacketExists) { + txPacket = new EthPacketData(16384); + txPacket->unserialize("txPacket", cp, section); + uint32_t txPktBufPtr; + UNSERIALIZE_SCALAR(txPktBufPtr); + txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr; + } else + txPacket = 0; + + bool rxPacketExists; + UNSERIALIZE_SCALAR(rxPacketExists); + rxPacket = 0; + if (rxPacketExists) { + rxPacket = new EthPacketData(16384); + rxPacket->unserialize("rxPacket", cp, section); + uint32_t rxPktBufPtr; + UNSERIALIZE_SCALAR(rxPktBufPtr); + rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr; + } else + rxPacket = 0; + + UNSERIALIZE_SCALAR(txXferLen); + UNSERIALIZE_SCALAR(rxXferLen); + + /* + * Unserialize Cached Descriptors + */ + UNSERIALIZE_SCALAR(rxDesc64.link); + UNSERIALIZE_SCALAR(rxDesc64.bufptr); + UNSERIALIZE_SCALAR(rxDesc64.cmdsts); + UNSERIALIZE_SCALAR(rxDesc64.extsts); + UNSERIALIZE_SCALAR(txDesc64.link); + UNSERIALIZE_SCALAR(txDesc64.bufptr); + UNSERIALIZE_SCALAR(txDesc64.cmdsts); + UNSERIALIZE_SCALAR(txDesc64.extsts); + UNSERIALIZE_SCALAR(rxDesc32.link); + UNSERIALIZE_SCALAR(rxDesc32.bufptr); + UNSERIALIZE_SCALAR(rxDesc32.cmdsts); + UNSERIALIZE_SCALAR(rxDesc32.extsts); + UNSERIALIZE_SCALAR(txDesc32.link); + UNSERIALIZE_SCALAR(txDesc32.bufptr); + UNSERIALIZE_SCALAR(txDesc32.cmdsts); + UNSERIALIZE_SCALAR(txDesc32.extsts); + UNSERIALIZE_SCALAR(extstsEnable); + + /* + * unserialize tx state machine + */ + int txState; + UNSERIALIZE_SCALAR(txState); + this->txState = (TxState) txState; + UNSERIALIZE_SCALAR(txEnable); + UNSERIALIZE_SCALAR(CTDD); + UNSERIALIZE_SCALAR(txFragPtr); + UNSERIALIZE_SCALAR(txDescCnt); + int txDmaState; + UNSERIALIZE_SCALAR(txDmaState); + this->txDmaState = (DmaState) txDmaState; + UNSERIALIZE_SCALAR(txKickTick); + if (txKickTick) + txKickEvent.schedule(txKickTick); + + /* + * unserialize rx state machine + */ + int rxState; + UNSERIALIZE_SCALAR(rxState); + this->rxState = (RxState) rxState; + UNSERIALIZE_SCALAR(rxEnable); + UNSERIALIZE_SCALAR(CRDD); + UNSERIALIZE_SCALAR(rxPktBytes); + UNSERIALIZE_SCALAR(rxFragPtr); + UNSERIALIZE_SCALAR(rxDescCnt); + int rxDmaState; + UNSERIALIZE_SCALAR(rxDmaState); + this->rxDmaState = (DmaState) rxDmaState; + UNSERIALIZE_SCALAR(rxKickTick); + if (rxKickTick) + rxKickEvent.schedule(rxKickTick); + + /* + * Unserialize EEPROM state machine + */ + int eepromState; + UNSERIALIZE_SCALAR(eepromState); + this->eepromState = (EEPROMState) eepromState; + UNSERIALIZE_SCALAR(eepromClk); + UNSERIALIZE_SCALAR(eepromBitsToRx); + UNSERIALIZE_SCALAR(eepromOpcode); + UNSERIALIZE_SCALAR(eepromAddress); + UNSERIALIZE_SCALAR(eepromData); + + /* + * If there's a pending transmit, reschedule it now + */ + Tick transmitTick; + UNSERIALIZE_SCALAR(transmitTick); + if (transmitTick) + txEvent.schedule(curTick + transmitTick); + + /* + * unserialize receive address filter settings + */ + UNSERIALIZE_SCALAR(rxFilterEnable); + UNSERIALIZE_SCALAR(acceptBroadcast); + UNSERIALIZE_SCALAR(acceptMulticast); + UNSERIALIZE_SCALAR(acceptUnicast); + UNSERIALIZE_SCALAR(acceptPerfect); + UNSERIALIZE_SCALAR(acceptArp); + UNSERIALIZE_SCALAR(multicastHashEnable); + + /* + * Keep track of pending interrupt status. + */ + UNSERIALIZE_SCALAR(intrTick); + UNSERIALIZE_SCALAR(cpuPendingIntr); + Tick intrEventTick; + UNSERIALIZE_SCALAR(intrEventTick); + if (intrEventTick) { + intrEvent = new IntrEvent(this, true); + intrEvent->schedule(intrEventTick); + } +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt) + + SimObjectParam<EtherInt *> peer; + SimObjectParam<NSGigE *> device; + +END_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt) + +BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigEInt) + + INIT_PARAM_DFLT(peer, "peer interface", NULL), + INIT_PARAM(device, "Ethernet device of this interface") + +END_INIT_SIM_OBJECT_PARAMS(NSGigEInt) + +CREATE_SIM_OBJECT(NSGigEInt) +{ + NSGigEInt *dev_int = new NSGigEInt(getInstanceName(), device); + + EtherInt *p = (EtherInt *)peer; + if (p) { + dev_int->setPeer(p); + p->setPeer(dev_int); + } + + return dev_int; +} + +REGISTER_SIM_OBJECT("NSGigEInt", NSGigEInt) + + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE) + + SimObjectParam<System *> system; + SimObjectParam<Platform *> platform; + SimObjectParam<PciConfigAll *> configspace; + SimObjectParam<PciConfigData *> configdata; + Param<uint32_t> pci_bus; + Param<uint32_t> pci_dev; + Param<uint32_t> pci_func; + Param<Tick> pio_latency; + + Param<Tick> clock; + Param<bool> dma_desc_free; + Param<bool> dma_data_free; + Param<Tick> dma_read_delay; + Param<Tick> dma_write_delay; + Param<Tick> dma_read_factor; + Param<Tick> dma_write_factor; + Param<bool> dma_no_allocate; + Param<Tick> intr_delay; + + Param<Tick> rx_delay; + Param<Tick> tx_delay; + Param<uint32_t> rx_fifo_size; + Param<uint32_t> tx_fifo_size; + + Param<bool> rx_filter; + Param<string> hardware_address; + Param<bool> rx_thread; + Param<bool> tx_thread; + Param<bool> rss; + +END_DECLARE_SIM_OBJECT_PARAMS(NSGigE) + +BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE) + + INIT_PARAM(system, "System pointer"), + INIT_PARAM(platform, "Platform pointer"), + INIT_PARAM(configspace, "PCI Configspace"), + INIT_PARAM(configdata, "PCI Config data"), + INIT_PARAM(pci_bus, "PCI bus ID"), + INIT_PARAM(pci_dev, "PCI device number"), + INIT_PARAM(pci_func, "PCI function code"), + INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1), + INIT_PARAM(clock, "State machine cycle time"), + + INIT_PARAM(dma_desc_free, "DMA of Descriptors is free"), + INIT_PARAM(dma_data_free, "DMA of Data is free"), + INIT_PARAM(dma_read_delay, "fixed delay for dma reads"), + INIT_PARAM(dma_write_delay, "fixed delay for dma writes"), + INIT_PARAM(dma_read_factor, "multiplier for dma reads"), + INIT_PARAM(dma_write_factor, "multiplier for dma writes"), + INIT_PARAM(dma_no_allocate, "Should DMA reads allocate cache lines"), + INIT_PARAM(intr_delay, "Interrupt Delay in microseconds"), + + INIT_PARAM(rx_delay, "Receive Delay"), + INIT_PARAM(tx_delay, "Transmit Delay"), + INIT_PARAM(rx_fifo_size, "max size in bytes of rxFifo"), + INIT_PARAM(tx_fifo_size, "max size in bytes of txFifo"), + + INIT_PARAM(rx_filter, "Enable Receive Filter"), + INIT_PARAM(hardware_address, "Ethernet Hardware Address"), + INIT_PARAM(rx_thread, ""), + INIT_PARAM(tx_thread, ""), + INIT_PARAM(rss, "") + +END_INIT_SIM_OBJECT_PARAMS(NSGigE) + + +CREATE_SIM_OBJECT(NSGigE) +{ + NSGigE::Params *params = new NSGigE::Params; + + params->name = getInstanceName(); + params->platform = platform; + params->system = system; + params->configSpace = configspace; + params->configData = configdata; + params->busNum = pci_bus; + params->deviceNum = pci_dev; + params->functionNum = pci_func; + params->pio_delay = pio_latency; + + params->clock = clock; + params->dma_desc_free = dma_desc_free; + params->dma_data_free = dma_data_free; + params->dma_read_delay = dma_read_delay; + params->dma_write_delay = dma_write_delay; + params->dma_read_factor = dma_read_factor; + params->dma_write_factor = dma_write_factor; + params->dma_no_allocate = dma_no_allocate; + params->pio_delay = pio_latency; + params->intr_delay = intr_delay; + + params->rx_delay = rx_delay; + params->tx_delay = tx_delay; + params->rx_fifo_size = rx_fifo_size; + params->tx_fifo_size = tx_fifo_size; + + params->rx_filter = rx_filter; + params->eaddr = hardware_address; + params->rx_thread = rx_thread; + params->tx_thread = tx_thread; + params->rss = rss; + + return new NSGigE(params); +} + +REGISTER_SIM_OBJECT("NSGigE", NSGigE) diff --git a/src/dev/ns_gige.hh b/src/dev/ns_gige.hh new file mode 100644 index 000000000..51520fd00 --- /dev/null +++ b/src/dev/ns_gige.hh @@ -0,0 +1,463 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file + * Device module for modelling the National Semiconductor + * DP83820 ethernet controller + */ + +#ifndef __DEV_NS_GIGE_HH__ +#define __DEV_NS_GIGE_HH__ + +#include "base/inet.hh" +#include "base/statistics.hh" +#include "dev/etherint.hh" +#include "dev/etherpkt.hh" +#include "dev/io_device.hh" +#include "dev/ns_gige_reg.h" +#include "dev/pcidev.hh" +#include "dev/pktfifo.hh" +#include "sim/eventq.hh" + +// Hash filtering constants +const uint16_t FHASH_ADDR = 0x100; +const uint16_t FHASH_SIZE = 0x100; + +// EEPROM constants +const uint8_t EEPROM_READ = 0x2; +const uint8_t EEPROM_SIZE = 64; // Size in words of NSC93C46 EEPROM +const uint8_t EEPROM_PMATCH2_ADDR = 0xA; // EEPROM Address of PMATCH word 2 +const uint8_t EEPROM_PMATCH1_ADDR = 0xB; // EEPROM Address of PMATCH word 1 +const uint8_t EEPROM_PMATCH0_ADDR = 0xC; // EEPROM Address of PMATCH word 0 + +/** + * Ethernet device registers + */ +struct dp_regs { + uint32_t command; + uint32_t config; + uint32_t mear; + uint32_t ptscr; + uint32_t isr; + uint32_t imr; + uint32_t ier; + uint32_t ihr; + uint32_t txdp; + uint32_t txdp_hi; + uint32_t txcfg; + uint32_t gpior; + uint32_t rxdp; + uint32_t rxdp_hi; + uint32_t rxcfg; + uint32_t pqcr; + uint32_t wcsr; + uint32_t pcr; + uint32_t rfcr; + uint32_t rfdr; + uint32_t brar; + uint32_t brdr; + uint32_t srr; + uint32_t mibc; + uint32_t vrcr; + uint32_t vtcr; + uint32_t vdr; + uint32_t ccsr; + uint32_t tbicr; + uint32_t tbisr; + uint32_t tanar; + uint32_t tanlpar; + uint32_t taner; + uint32_t tesr; +}; + +struct dp_rom { + /** + * for perfect match memory. + * the linux driver doesn't use any other ROM + */ + uint8_t perfectMatch[ETH_ADDR_LEN]; + + /** + * for hash table memory. + * used by the freebsd driver + */ + uint8_t filterHash[FHASH_SIZE]; +}; + +class NSGigEInt; +class Packet; +class PciConfigAll; + +/** + * NS DP83820 Ethernet device model + */ +class NSGigE : public PciDev +{ + public: + /** Transmit State Machine states */ + enum TxState + { + txIdle, + txDescRefr, + txDescRead, + txFifoBlock, + txFragRead, + txDescWrite, + txAdvance + }; + + /** Receive State Machine States */ + enum RxState + { + rxIdle, + rxDescRefr, + rxDescRead, + rxFifoBlock, + rxFragWrite, + rxDescWrite, + rxAdvance + }; + + enum DmaState + { + dmaIdle, + dmaReading, + dmaWriting, + dmaReadWaiting, + dmaWriteWaiting + }; + + /** EEPROM State Machine States */ + enum EEPROMState + { + eepromStart, + eepromGetOpcode, + eepromGetAddress, + eepromRead + }; + + protected: + /** device register file */ + dp_regs regs; + dp_rom rom; + + /** pci settings */ + bool ioEnable; +#if 0 + bool memEnable; + bool bmEnable; +#endif + + /*** BASIC STRUCTURES FOR TX/RX ***/ + /* Data FIFOs */ + PacketFifo txFifo; + PacketFifo rxFifo; + + /** various helper vars */ + EthPacketPtr txPacket; + EthPacketPtr rxPacket; + uint8_t *txPacketBufPtr; + uint8_t *rxPacketBufPtr; + uint32_t txXferLen; + uint32_t rxXferLen; + bool rxDmaFree; + bool txDmaFree; + + /** DescCaches */ + ns_desc32 txDesc32; + ns_desc32 rxDesc32; + ns_desc64 txDesc64; + ns_desc64 rxDesc64; + + /* state machine cycle time */ + Tick clock; + inline Tick cycles(int numCycles) const { return numCycles * clock; } + + /* tx State Machine */ + TxState txState; + bool txEnable; + + /** Current Transmit Descriptor Done */ + bool CTDD; + /** halt the tx state machine after next packet */ + bool txHalt; + /** ptr to the next byte in the current fragment */ + Addr txFragPtr; + /** count of bytes remaining in the current descriptor */ + uint32_t txDescCnt; + DmaState txDmaState; + + /** rx State Machine */ + RxState rxState; + bool rxEnable; + + /** Current Receive Descriptor Done */ + bool CRDD; + /** num of bytes in the current packet being drained from rxDataFifo */ + uint32_t rxPktBytes; + /** halt the rx state machine after current packet */ + bool rxHalt; + /** ptr to the next byte in current fragment */ + Addr rxFragPtr; + /** count of bytes remaining in the current descriptor */ + uint32_t rxDescCnt; + DmaState rxDmaState; + + bool extstsEnable; + + /** EEPROM State Machine */ + EEPROMState eepromState; + bool eepromClk; + uint8_t eepromBitsToRx; + uint8_t eepromOpcode; + uint8_t eepromAddress; + uint16_t eepromData; + + protected: + Tick dmaReadDelay; + Tick dmaWriteDelay; + + Tick dmaReadFactor; + Tick dmaWriteFactor; + + void *rxDmaData; + Addr rxDmaAddr; + int rxDmaLen; + bool doRxDmaRead(); + bool doRxDmaWrite(); + + void *txDmaData; + Addr txDmaAddr; + int txDmaLen; + bool doTxDmaRead(); + bool doTxDmaWrite(); + + void rxDmaReadDone(); + friend class EventWrapper<NSGigE, &NSGigE::rxDmaReadDone>; + EventWrapper<NSGigE, &NSGigE::rxDmaReadDone> rxDmaReadEvent; + + void rxDmaWriteDone(); + friend class EventWrapper<NSGigE, &NSGigE::rxDmaWriteDone>; + EventWrapper<NSGigE, &NSGigE::rxDmaWriteDone> rxDmaWriteEvent; + + void txDmaReadDone(); + friend class EventWrapper<NSGigE, &NSGigE::txDmaReadDone>; + EventWrapper<NSGigE, &NSGigE::txDmaReadDone> txDmaReadEvent; + + void txDmaWriteDone(); + friend class EventWrapper<NSGigE, &NSGigE::txDmaWriteDone>; + EventWrapper<NSGigE, &NSGigE::txDmaWriteDone> txDmaWriteEvent; + + bool dmaDescFree; + bool dmaDataFree; + + protected: + Tick txDelay; + Tick rxDelay; + + void txReset(); + void rxReset(); + void regsReset(); + + void rxKick(); + Tick rxKickTick; + typedef EventWrapper<NSGigE, &NSGigE::rxKick> RxKickEvent; + friend void RxKickEvent::process(); + RxKickEvent rxKickEvent; + + void txKick(); + Tick txKickTick; + typedef EventWrapper<NSGigE, &NSGigE::txKick> TxKickEvent; + friend void TxKickEvent::process(); + TxKickEvent txKickEvent; + + void eepromKick(); + + /** + * Retransmit event + */ + void transmit(); + void txEventTransmit() + { + transmit(); + if (txState == txFifoBlock) + txKick(); + } + typedef EventWrapper<NSGigE, &NSGigE::txEventTransmit> TxEvent; + friend void TxEvent::process(); + TxEvent txEvent; + + void txDump() const; + void rxDump() const; + + /** + * receive address filter + */ + bool rxFilterEnable; + bool rxFilter(const EthPacketPtr &packet); + bool acceptBroadcast; + bool acceptMulticast; + bool acceptUnicast; + bool acceptPerfect; + bool acceptArp; + bool multicastHashEnable; + + /** + * Interrupt management + */ + void devIntrPost(uint32_t interrupts); + void devIntrClear(uint32_t interrupts); + void devIntrChangeMask(); + + Tick intrDelay; + Tick intrTick; + bool cpuPendingIntr; + void cpuIntrPost(Tick when); + void cpuInterrupt(); + void cpuIntrClear(); + + typedef EventWrapper<NSGigE, &NSGigE::cpuInterrupt> IntrEvent; + friend void IntrEvent::process(); + IntrEvent *intrEvent; + NSGigEInt *interface; + + public: + struct Params : public PciDev::Params + { + Tick clock; + Tick intr_delay; + Tick tx_delay; + Tick rx_delay; + bool dma_desc_free; + bool dma_data_free; + Tick dma_read_delay; + Tick dma_write_delay; + Tick dma_read_factor; + Tick dma_write_factor; + bool rx_filter; + Net::EthAddr eaddr; + uint32_t tx_fifo_size; + uint32_t rx_fifo_size; + bool rx_thread; + bool tx_thread; + bool rss; + bool dma_no_allocate; + }; + + NSGigE(Params *params); + ~NSGigE(); + const Params *params() const { return (const Params *)_params; } + + virtual void writeConfig(int offset, const uint16_t data); + + virtual Tick read(Packet *pkt); + virtual Tick write(Packet *pkt); + + bool cpuIntrPending() const; + void cpuIntrAck() { cpuIntrClear(); } + + bool recvPacket(EthPacketPtr packet); + void transferDone(); + + void setInterface(NSGigEInt *i) { assert(!interface); interface = i; } + + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); + + public: + void regStats(); + + private: + Stats::Scalar<> txBytes; + Stats::Scalar<> rxBytes; + Stats::Scalar<> txPackets; + Stats::Scalar<> rxPackets; + Stats::Scalar<> txIpChecksums; + Stats::Scalar<> rxIpChecksums; + Stats::Scalar<> txTcpChecksums; + Stats::Scalar<> rxTcpChecksums; + Stats::Scalar<> txUdpChecksums; + Stats::Scalar<> rxUdpChecksums; + Stats::Scalar<> descDmaReads; + Stats::Scalar<> descDmaWrites; + Stats::Scalar<> descDmaRdBytes; + Stats::Scalar<> descDmaWrBytes; + Stats::Formula totBandwidth; + Stats::Formula totPackets; + Stats::Formula totBytes; + Stats::Formula totPacketRate; + Stats::Formula txBandwidth; + Stats::Formula rxBandwidth; + Stats::Formula txPacketRate; + Stats::Formula rxPacketRate; + Stats::Scalar<> postedSwi; + Stats::Formula coalescedSwi; + Stats::Scalar<> totalSwi; + Stats::Scalar<> postedRxIdle; + Stats::Formula coalescedRxIdle; + Stats::Scalar<> totalRxIdle; + Stats::Scalar<> postedRxOk; + Stats::Formula coalescedRxOk; + Stats::Scalar<> totalRxOk; + Stats::Scalar<> postedRxDesc; + Stats::Formula coalescedRxDesc; + Stats::Scalar<> totalRxDesc; + Stats::Scalar<> postedTxOk; + Stats::Formula coalescedTxOk; + Stats::Scalar<> totalTxOk; + Stats::Scalar<> postedTxIdle; + Stats::Formula coalescedTxIdle; + Stats::Scalar<> totalTxIdle; + Stats::Scalar<> postedTxDesc; + Stats::Formula coalescedTxDesc; + Stats::Scalar<> totalTxDesc; + Stats::Scalar<> postedRxOrn; + Stats::Formula coalescedRxOrn; + Stats::Scalar<> totalRxOrn; + Stats::Formula coalescedTotal; + Stats::Scalar<> postedInterrupts; + Stats::Scalar<> droppedPackets; +}; + +/* + * Ethernet Interface for an Ethernet Device + */ +class NSGigEInt : public EtherInt +{ + private: + NSGigE *dev; + + public: + NSGigEInt(const std::string &name, NSGigE *d) + : EtherInt(name), dev(d) { dev->setInterface(this); } + + virtual bool recvPacket(EthPacketPtr pkt) { return dev->recvPacket(pkt); } + virtual void sendDone() { dev->transferDone(); } +}; + +#endif // __DEV_NS_GIGE_HH__ diff --git a/dev/ns_gige_reg.h b/src/dev/ns_gige_reg.h index 5f6fa2cc5..5f6fa2cc5 100644 --- a/dev/ns_gige_reg.h +++ b/src/dev/ns_gige_reg.h diff --git a/src/dev/pciconfigall.cc b/src/dev/pciconfigall.cc new file mode 100644 index 000000000..14a28e86d --- /dev/null +++ b/src/dev/pciconfigall.cc @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* @file + * PCI Configspace implementation + */ + +#include <deque> +#include <string> +#include <vector> +#include <bitset> + +#include "base/trace.hh" +#include "dev/pciconfigall.hh" +#include "dev/pcidev.hh" +#include "dev/pcireg.h" +#include "dev/platform.hh" +#include "mem/packet.hh" +#include "sim/builder.hh" +#include "sim/system.hh" + +using namespace std; + +PciConfigAll::PciConfigAll(Params *p) + : BasicPioDevice(p) +{ + pioSize = 0xffffff; + + // Set backpointer for pci config. Really the config stuff should be able to + // automagically do this + p->platform->pciconfig = this; + + // Make all the pointers to devices null + for(int x=0; x < MAX_PCI_DEV; x++) + for(int y=0; y < MAX_PCI_FUNC; y++) + devices[x][y] = NULL; +} + +// If two interrupts share the same line largely bad things will happen. +// Since we don't track how many times an interrupt was set and correspondingly +// cleared two devices on the same interrupt line and assert and deassert each +// others interrupt "line". Interrupts will not work correctly. +void +PciConfigAll::startup() +{ + bitset<256> intLines; + PciDev *tempDev; + uint8_t intline; + + for (int x = 0; x < MAX_PCI_DEV; x++) { + for (int y = 0; y < MAX_PCI_FUNC; y++) { + if (devices[x][y] != NULL) { + tempDev = devices[x][y]; + intline = tempDev->interruptLine(); + if (intLines.test(intline)) + warn("Interrupt line %#X is used multiple times" + "(You probably want to fix this).\n", (uint32_t)intline); + else + intLines.set(intline); + } // devices != NULL + } // PCI_FUNC + } // PCI_DEV + +} + +Tick +PciConfigAll::read(Packet *pkt) +{ + assert(pkt->result == Packet::Unknown); + assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); + + Addr daddr = pkt->getAddr() - pioAddr; + int device = (daddr >> 11) & 0x1F; + int func = (daddr >> 8) & 0x7; + int reg = daddr & 0xFF; + + pkt->time += pioDelay; + pkt->allocate(); + + DPRINTF(PciConfigAll, "read va=%#x da=%#x size=%d\n", pkt->getAddr(), daddr, + pkt->getSize()); + + switch (pkt->getSize()) { + case sizeof(uint32_t): + if (devices[device][func] == NULL) + pkt->set<uint32_t>(0xFFFFFFFF); + else + devices[device][func]->readConfig(reg, pkt->getPtr<uint32_t>()); + break; + case sizeof(uint16_t): + if (devices[device][func] == NULL) + pkt->set<uint16_t>(0xFFFF); + else + devices[device][func]->readConfig(reg, pkt->getPtr<uint16_t>()); + break; + case sizeof(uint8_t): + if (devices[device][func] == NULL) + pkt->set<uint8_t>(0xFF); + else + devices[device][func]->readConfig(reg, pkt->getPtr<uint8_t>()); + break; + default: + panic("invalid access size(?) for PCI configspace!\n"); + } + pkt->result = Packet::Success; + return pioDelay; +} + +Tick +PciConfigAll::write(Packet *pkt) +{ + pkt->time += pioDelay; + + assert(pkt->result == Packet::Unknown); + assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); + assert(pkt->getSize() == sizeof(uint8_t) || pkt->getSize() == sizeof(uint16_t) || + pkt->getSize() == sizeof(uint32_t)); + Addr daddr = pkt->getAddr() - pioAddr; + + int device = (daddr >> 11) & 0x1F; + int func = (daddr >> 8) & 0x7; + int reg = daddr & 0xFF; + + if (devices[device][func] == NULL) + panic("Attempting to write to config space on non-existant device\n"); + + DPRINTF(PciConfigAll, "write - va=%#x size=%d data=%#x\n", + pkt->getAddr(), pkt->getSize(), pkt->get<uint32_t>()); + + switch (pkt->getSize()) { + case sizeof(uint8_t): + devices[device][func]->writeConfig(reg, pkt->get<uint8_t>()); + break; + case sizeof(uint16_t): + devices[device][func]->writeConfig(reg, pkt->get<uint16_t>()); + break; + case sizeof(uint32_t): + devices[device][func]->writeConfig(reg, pkt->get<uint32_t>()); + break; + default: + panic("invalid pci config write size\n"); + } + pkt->result = Packet::Success; + return pioDelay; +} + +void +PciConfigAll::serialize(std::ostream &os) +{ + /* + * There is no state associated with this object that requires + * serialization. The only real state are the device pointers + * which are all setup by the constructor of the PciDev class + */ +} + +void +PciConfigAll::unserialize(Checkpoint *cp, const std::string §ion) +{ + /* + * There is no state associated with this object that requires + * serialization. The only real state are the device pointers + * which are all setup by the constructor of the PciDev class + */ +} + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(PciConfigAll) + + Param<Addr> pio_addr; + Param<Tick> pio_latency; + SimObjectParam<Platform *> platform; + SimObjectParam<System *> system; + +END_DECLARE_SIM_OBJECT_PARAMS(PciConfigAll) + +BEGIN_INIT_SIM_OBJECT_PARAMS(PciConfigAll) + + INIT_PARAM(pio_addr, "Device Address"), + INIT_PARAM(pio_latency, "Programmed IO latency"), + INIT_PARAM(platform, "platform"), + INIT_PARAM(system, "system object") + +END_INIT_SIM_OBJECT_PARAMS(PciConfigAll) + +CREATE_SIM_OBJECT(PciConfigAll) +{ + BasicPioDevice::Params *p = new BasicPioDevice::Params; + p->pio_addr = pio_addr; + p->pio_delay = pio_latency; + p->platform = platform; + p->system = system; + return new PciConfigAll(p); +} + +REGISTER_SIM_OBJECT("PciConfigAll", PciConfigAll) + +#endif // DOXYGEN_SHOULD_SKIP_THIS diff --git a/src/dev/pciconfigall.hh b/src/dev/pciconfigall.hh new file mode 100644 index 000000000..df4eae448 --- /dev/null +++ b/src/dev/pciconfigall.hh @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * @file + * PCI Config space implementation. + */ + +#ifndef __PCICONFIGALL_HH__ +#define __PCICONFIGALL_HH__ + +#include "dev/pcireg.h" +#include "base/range.hh" +#include "dev/io_device.hh" + + +static const uint32_t MAX_PCI_DEV = 32; +static const uint32_t MAX_PCI_FUNC = 8; + +class PciDev; + +/** + * PCI Config Space + * All of PCI config space needs to return -1 on Tsunami, except + * the devices that exist. This device maps the entire bus config + * space and passes the requests on to TsunamiPCIDev devices as + * appropriate. + */ +class PciConfigAll : public BasicPioDevice +{ + private: + /** + * Pointers to all the devices that are registered with this + * particular config space. + */ + PciDev* devices[MAX_PCI_DEV][MAX_PCI_FUNC]; + + public: + /** + * Constructor for PCIConfigAll + * @param p parameters structure + */ + PciConfigAll(Params *p); + + /** + * Check if a device exists. + * @param pcidev PCI device to check + * @param pcifunc PCI function to check + * @return true if device exists, false otherwise + */ + bool deviceExists(uint32_t pcidev, uint32_t pcifunc) + { return devices[pcidev][pcifunc] != NULL ? true : false; } + + /** + * Registers a device with the config space object. + * @param pcidev PCI device to register + * @param pcifunc PCI function to register + * @param device device to register + */ + void registerDevice(uint8_t pcidev, uint8_t pcifunc, PciDev *device) + { devices[pcidev][pcifunc] = device; } + + /** + * Read something in PCI config space. If the device does not exist + * -1 is returned, if the device does exist its PciDev::ReadConfig (or the + * virtual function that overrides) it is called. + * @param pkt Contains the address of the field to read. + * @return Amount of time to do the read + */ + virtual Tick read(Packet *pkt); + + /** + * Write to PCI config spcae. If the device does not exit the simulator + * panics. If it does it is passed on the PciDev::WriteConfig (or the virtual + * function that overrides it). + * @param req Contains the address to write to. + * @param data The data to write. + * @return The fault condition of the access. + */ + + virtual Tick write(Packet *pkt); + + /** + * Start up function to check if more than one person is using an interrupt line + * and print a warning if such a case exists + */ + virtual void startup(); + + /** + * Serialize this object to the given output stream. + * @param os The stream to serialize to. + */ + virtual void serialize(std::ostream &os); + + /** + * Reconstruct the state of this object from a checkpoint. + * @param cp The checkpoint use. + * @param section The section name of this object + */ + virtual void unserialize(Checkpoint *cp, const std::string §ion); +}; + +#endif // __PCICONFIGALL_HH__ diff --git a/src/dev/pcidev.cc b/src/dev/pcidev.cc new file mode 100644 index 000000000..76392ccfe --- /dev/null +++ b/src/dev/pcidev.cc @@ -0,0 +1,386 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* @file + * A single PCI device configuration space entry. + */ + +#include <list> +#include <string> +#include <vector> + +#include "base/inifile.hh" +#include "base/misc.hh" +#include "base/str.hh" // for to_number +#include "base/trace.hh" +#include "dev/pciconfigall.hh" +#include "dev/pcidev.hh" +#include "dev/tsunamireg.h" +#include "mem/packet.hh" +#include "sim/builder.hh" +#include "sim/byteswap.hh" +#include "sim/param.hh" +#include "sim/root.hh" + +using namespace std; + +PciDev::PciDev(Params *p) + : DmaDevice(p), plat(p->platform), configData(p->configData), + pioDelay(p->pio_delay) +{ + // copy the config data from the PciConfigData object + if (configData) { + memcpy(config.data, configData->config.data, sizeof(config.data)); + memcpy(BARSize, configData->BARSize, sizeof(BARSize)); + memcpy(BARAddrs, configData->BARAddrs, sizeof(BARAddrs)); + } else + panic("NULL pointer to configuration data"); + + // Setup pointer in config space to point to this entry + if (p->configSpace->deviceExists(p->deviceNum, p->functionNum)) + panic("Two PCI devices occuping same dev: %#x func: %#x", + p->deviceNum, p->functionNum); + else + p->configSpace->registerDevice(p->deviceNum, p->functionNum, this); +} + +void +PciDev::readConfig(int offset, uint8_t *data) +{ + if (offset >= PCI_DEVICE_SPECIFIC) + panic("Device specific PCI config space not implemented!\n"); + + *data = config.data[offset]; + + DPRINTF(PCIDEV, + "read device: %#x function: %#x register: %#x 1 bytes: data: %#x\n", + params()->deviceNum, params()->functionNum, offset, *data); +} + +void +PciDev::addressRanges(AddrRangeList &range_list) +{ + int x = 0; + range_list.clear(); + for (x = 0; x < 6; x++) + if (BARAddrs[x] != 0) + range_list.push_back(RangeSize(BARAddrs[x],BARSize[x])); +} + +void +PciDev::readConfig(int offset, uint16_t *data) +{ + if (offset >= PCI_DEVICE_SPECIFIC) + panic("Device specific PCI config space not implemented!\n"); + + *data = *(uint16_t*)&config.data[offset]; + + DPRINTF(PCIDEV, + "read device: %#x function: %#x register: %#x 2 bytes: data: %#x\n", + params()->deviceNum, params()->functionNum, offset, *data); +} + +void +PciDev::readConfig(int offset, uint32_t *data) +{ + if (offset >= PCI_DEVICE_SPECIFIC) + panic("Device specific PCI config space not implemented!\n"); + + *data = *(uint32_t*)&config.data[offset]; + + DPRINTF(PCIDEV, + "read device: %#x function: %#x register: %#x 4 bytes: data: %#x\n", + params()->deviceNum, params()->functionNum, offset, *data); +} + + +void +PciDev::writeConfig(int offset, const uint8_t data) +{ + if (offset >= PCI_DEVICE_SPECIFIC) + panic("Device specific PCI config space not implemented!\n"); + + DPRINTF(PCIDEV, + "write device: %#x function: %#x reg: %#x size: 1 data: %#x\n", + params()->deviceNum, params()->functionNum, offset, data); + + switch (offset) { + case PCI0_INTERRUPT_LINE: + config.interruptLine = data; + case PCI_CACHE_LINE_SIZE: + config.cacheLineSize = data; + case PCI_LATENCY_TIMER: + config.latencyTimer = data; + break; + /* Do nothing for these read-only registers */ + case PCI0_INTERRUPT_PIN: + case PCI0_MINIMUM_GRANT: + case PCI0_MAXIMUM_LATENCY: + case PCI_CLASS_CODE: + case PCI_REVISION_ID: + break; + default: + panic("writing to a read only register"); + } +} + +void +PciDev::writeConfig(int offset, const uint16_t data) +{ + if (offset >= PCI_DEVICE_SPECIFIC) + panic("Device specific PCI config space not implemented!\n"); + + DPRINTF(PCIDEV, + "write device: %#x function: %#x reg: %#x size: 2 data: %#x\n", + params()->deviceNum, params()->functionNum, offset, data); + + switch (offset) { + case PCI_COMMAND: + config.command = data; + case PCI_STATUS: + config.status = data; + case PCI_CACHE_LINE_SIZE: + config.cacheLineSize = data; + break; + default: + panic("writing to a read only register"); + } +} + + +void +PciDev::writeConfig(int offset, const uint32_t data) +{ + if (offset >= PCI_DEVICE_SPECIFIC) + panic("Device specific PCI config space not implemented!\n"); + + DPRINTF(PCIDEV, + "write device: %#x function: %#x reg: %#x size: 4 data: %#x\n", + params()->deviceNum, params()->functionNum, offset, data); + + switch (offset) { + case PCI0_BASE_ADDR0: + case PCI0_BASE_ADDR1: + case PCI0_BASE_ADDR2: + case PCI0_BASE_ADDR3: + case PCI0_BASE_ADDR4: + case PCI0_BASE_ADDR5: + + uint32_t barnum, bar_mask; + Addr base_addr, base_size, space_base; + + barnum = BAR_NUMBER(offset); + + if (BAR_IO_SPACE(letoh(config.baseAddr[barnum]))) { + bar_mask = BAR_IO_MASK; + space_base = TSUNAMI_PCI0_IO; + } else { + bar_mask = BAR_MEM_MASK; + space_base = TSUNAMI_PCI0_MEMORY; + } + + // Writing 0xffffffff to a BAR tells the card to set the + // value of the bar to size of memory it needs + if (letoh(data) == 0xffffffff) { + // This is I/O Space, bottom two bits are read only + + config.baseAddr[barnum] = letoh( + (~(BARSize[barnum] - 1) & ~bar_mask) | + (letoh(config.baseAddr[barnum]) & bar_mask)); + } else { + config.baseAddr[barnum] = letoh( + (letoh(data) & ~bar_mask) | + (letoh(config.baseAddr[barnum]) & bar_mask)); + + if (letoh(config.baseAddr[barnum]) & ~bar_mask) { + base_addr = (letoh(data) & ~bar_mask) + space_base; + base_size = BARSize[barnum]; + BARAddrs[barnum] = base_addr; + + pioPort->sendStatusChange(Port::RangeChange); + } + } + break; + + case PCI0_ROM_BASE_ADDR: + if (letoh(data) == 0xfffffffe) + config.expansionROM = htole((uint32_t)0xffffffff); + else + config.expansionROM = data; + break; + + case PCI_COMMAND: + // This could also clear some of the error bits in the Status + // register. However they should never get set, so lets ignore + // it for now + config.command = data; + break; + + default: + DPRINTF(PCIDEV, "Writing to a read only register"); + } +} + +void +PciDev::serialize(ostream &os) +{ + SERIALIZE_ARRAY(BARSize, sizeof(BARSize) / sizeof(BARSize[0])); + SERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs) / sizeof(BARAddrs[0])); + SERIALIZE_ARRAY(config.data, sizeof(config.data) / sizeof(config.data[0])); +} + +void +PciDev::unserialize(Checkpoint *cp, const std::string §ion) +{ + UNSERIALIZE_ARRAY(BARSize, sizeof(BARSize) / sizeof(BARSize[0])); + UNSERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs) / sizeof(BARAddrs[0])); + UNSERIALIZE_ARRAY(config.data, + sizeof(config.data) / sizeof(config.data[0])); +} + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(PciConfigData) + + Param<uint16_t> VendorID; + Param<uint16_t> DeviceID; + Param<uint16_t> Command; + Param<uint16_t> Status; + Param<uint8_t> Revision; + Param<uint8_t> ProgIF; + Param<uint8_t> SubClassCode; + Param<uint8_t> ClassCode; + Param<uint8_t> CacheLineSize; + Param<uint8_t> LatencyTimer; + Param<uint8_t> HeaderType; + Param<uint8_t> BIST; + Param<uint32_t> BAR0; + Param<uint32_t> BAR1; + Param<uint32_t> BAR2; + Param<uint32_t> BAR3; + Param<uint32_t> BAR4; + Param<uint32_t> BAR5; + Param<uint32_t> CardbusCIS; + Param<uint16_t> SubsystemVendorID; + Param<uint16_t> SubsystemID; + Param<uint32_t> ExpansionROM; + Param<uint8_t> InterruptLine; + Param<uint8_t> InterruptPin; + Param<uint8_t> MinimumGrant; + Param<uint8_t> MaximumLatency; + Param<uint32_t> BAR0Size; + Param<uint32_t> BAR1Size; + Param<uint32_t> BAR2Size; + Param<uint32_t> BAR3Size; + Param<uint32_t> BAR4Size; + Param<uint32_t> BAR5Size; + +END_DECLARE_SIM_OBJECT_PARAMS(PciConfigData) + +BEGIN_INIT_SIM_OBJECT_PARAMS(PciConfigData) + + INIT_PARAM(VendorID, "Vendor ID"), + INIT_PARAM(DeviceID, "Device ID"), + INIT_PARAM_DFLT(Command, "Command Register", 0x00), + INIT_PARAM_DFLT(Status, "Status Register", 0x00), + INIT_PARAM_DFLT(Revision, "Device Revision", 0x00), + INIT_PARAM_DFLT(ProgIF, "Programming Interface", 0x00), + INIT_PARAM(SubClassCode, "Sub-Class Code"), + INIT_PARAM(ClassCode, "Class Code"), + INIT_PARAM_DFLT(CacheLineSize, "System Cacheline Size", 0x00), + INIT_PARAM_DFLT(LatencyTimer, "PCI Latency Timer", 0x00), + INIT_PARAM_DFLT(HeaderType, "PCI Header Type", 0x00), + INIT_PARAM_DFLT(BIST, "Built In Self Test", 0x00), + INIT_PARAM_DFLT(BAR0, "Base Address Register 0", 0x00), + INIT_PARAM_DFLT(BAR1, "Base Address Register 1", 0x00), + INIT_PARAM_DFLT(BAR2, "Base Address Register 2", 0x00), + INIT_PARAM_DFLT(BAR3, "Base Address Register 3", 0x00), + INIT_PARAM_DFLT(BAR4, "Base Address Register 4", 0x00), + INIT_PARAM_DFLT(BAR5, "Base Address Register 5", 0x00), + INIT_PARAM_DFLT(CardbusCIS, "Cardbus Card Information Structure", 0x00), + INIT_PARAM_DFLT(SubsystemVendorID, "Subsystem Vendor ID", 0x00), + INIT_PARAM_DFLT(SubsystemID, "Subsystem ID", 0x00), + INIT_PARAM_DFLT(ExpansionROM, "Expansion ROM Base Address Register", 0x00), + INIT_PARAM(InterruptLine, "Interrupt Line Register"), + INIT_PARAM(InterruptPin, "Interrupt Pin Register"), + INIT_PARAM_DFLT(MinimumGrant, "Minimum Grant", 0x00), + INIT_PARAM_DFLT(MaximumLatency, "Maximum Latency", 0x00), + INIT_PARAM_DFLT(BAR0Size, "Base Address Register 0 Size", 0x00), + INIT_PARAM_DFLT(BAR1Size, "Base Address Register 1 Size", 0x00), + INIT_PARAM_DFLT(BAR2Size, "Base Address Register 2 Size", 0x00), + INIT_PARAM_DFLT(BAR3Size, "Base Address Register 3 Size", 0x00), + INIT_PARAM_DFLT(BAR4Size, "Base Address Register 4 Size", 0x00), + INIT_PARAM_DFLT(BAR5Size, "Base Address Register 5 Size", 0x00) + +END_INIT_SIM_OBJECT_PARAMS(PciConfigData) + +CREATE_SIM_OBJECT(PciConfigData) +{ + PciConfigData *data = new PciConfigData(getInstanceName()); + + data->config.vendor = htole(VendorID); + data->config.device = htole(DeviceID); + data->config.command = htole(Command); + data->config.status = htole(Status); + data->config.revision = htole(Revision); + data->config.progIF = htole(ProgIF); + data->config.subClassCode = htole(SubClassCode); + data->config.classCode = htole(ClassCode); + data->config.cacheLineSize = htole(CacheLineSize); + data->config.latencyTimer = htole(LatencyTimer); + data->config.headerType = htole(HeaderType); + data->config.bist = htole(BIST); + + data->config.baseAddr0 = htole(BAR0); + data->config.baseAddr1 = htole(BAR1); + data->config.baseAddr2 = htole(BAR2); + data->config.baseAddr3 = htole(BAR3); + data->config.baseAddr4 = htole(BAR4); + data->config.baseAddr5 = htole(BAR5); + data->config.cardbusCIS = htole(CardbusCIS); + data->config.subsystemVendorID = htole(SubsystemVendorID); + data->config.subsystemID = htole(SubsystemVendorID); + data->config.expansionROM = htole(ExpansionROM); + data->config.interruptLine = htole(InterruptLine); + data->config.interruptPin = htole(InterruptPin); + data->config.minimumGrant = htole(MinimumGrant); + data->config.maximumLatency = htole(MaximumLatency); + + data->BARSize[0] = BAR0Size; + data->BARSize[1] = BAR1Size; + data->BARSize[2] = BAR2Size; + data->BARSize[3] = BAR3Size; + data->BARSize[4] = BAR4Size; + data->BARSize[5] = BAR5Size; + + return data; +} + +REGISTER_SIM_OBJECT("PciConfigData", PciConfigData) + +#endif // DOXYGEN_SHOULD_SKIP_THIS diff --git a/src/dev/pcidev.hh b/src/dev/pcidev.hh new file mode 100644 index 000000000..fc4773908 --- /dev/null +++ b/src/dev/pcidev.hh @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* @file + * Interface for devices using PCI configuration + */ + +#ifndef __DEV_PCIDEV_HH__ +#define __DEV_PCIDEV_HH__ + +#include "dev/io_device.hh" +#include "dev/pcireg.h" +#include "dev/platform.hh" + +#define BAR_IO_MASK 0x3 +#define BAR_MEM_MASK 0xF +#define BAR_IO_SPACE_BIT 0x1 +#define BAR_IO_SPACE(x) ((x) & BAR_IO_SPACE_BIT) +#define BAR_NUMBER(x) (((x) - PCI0_BASE_ADDR0) >> 0x2); + +class PciConfigAll; + + +/** + * This class encapulates the first 64 bytes of a singles PCI + * devices config space that in configured by the configuration file. + */ +class PciConfigData : public SimObject +{ + public: + /** + * Constructor to initialize the devices config space to 0. + */ + PciConfigData(const std::string &name) + : SimObject(name) + { + memset(config.data, 0, sizeof(config.data)); + memset(BARAddrs, 0, sizeof(BARAddrs)); + memset(BARSize, 0, sizeof(BARSize)); + } + + /** The first 64 bytes */ + PCIConfig config; + + /** The size of the BARs */ + uint32_t BARSize[6]; + + /** The addresses of the BARs */ + Addr BARAddrs[6]; +}; + +/** + * PCI device, base implemnation is only config space. + * Each device is connected to a PCIConfigSpace device + * which returns -1 for everything but the pcidevs that + * register with it. This object registers with the PCIConfig space + * object. + */ +class PciDev : public DmaDevice +{ + public: + struct Params : public ::PioDevice::Params + { + /** + * A pointer to the configspace all object that calls us when + * a read comes to this particular device/function. + */ + PciConfigAll *configSpace; + + /** + * A pointer to the object that contains the first 64 bytes of + * config space + */ + PciConfigData *configData; + + /** The bus number we are on */ + uint32_t busNum; + + /** The device number we have */ + uint32_t deviceNum; + + /** The function number */ + uint32_t functionNum; + + /** The latency for pio accesses. */ + Tick pio_delay; + }; + + public: + const Params *params() const { return (const Params *)_params; } + + protected: + /** The current config space. Unlike the PciConfigData this is + * updated during simulation while continues to reflect what was + * in the config file. + */ + PCIConfig config; + + /** The size of the BARs */ + uint32_t BARSize[6]; + + /** The current address mapping of the BARs */ + Addr BARAddrs[6]; + + bool + isBAR(Addr addr, int bar) const + { + assert(bar >= 0 && bar < 6); + return BARAddrs[bar] <= addr && addr < BARAddrs[bar] + BARSize[bar]; + } + + int + getBAR(Addr addr) + { + for (int i = 0; i <= 5; ++i) + if (isBAR(addr, i)) + return i; + + return -1; + } + + bool + getBAR(Addr paddr, Addr &daddr, int &bar) + { + int b = getBAR(paddr); + if (b < 0) + return false; + + daddr = paddr - BARAddrs[b]; + bar = b; + return true; + } + + protected: + Platform *plat; + PciConfigData *configData; + Tick pioDelay; + + public: + Addr pciToDma(Addr pciAddr) const + { return plat->pciToDma(pciAddr); } + + void + intrPost() + { plat->postPciInt(configData->config.interruptLine); } + + void + intrClear() + { plat->clearPciInt(configData->config.interruptLine); } + + uint8_t + interruptLine() + { return configData->config.interruptLine; } + + /** return the address ranges that this device responds to. + * @params range_list range list to populate with ranges + */ + void addressRanges(AddrRangeList &range_list); + + /** + * Constructor for PCI Dev. This function copies data from the + * config file object PCIConfigData and registers the device with + * a PciConfigAll object. + */ + PciDev(Params *params); + + /** + * Write to the PCI config space data that is stored locally. This may be + * overridden by the device but at some point it will eventually call this + * for normal operations that it does not need to override. + * @param offset the offset into config space + * @param size the size of the write + * @param data the data to write + */ + virtual void writeConfig(int offset, const uint8_t data); + virtual void writeConfig(int offset, const uint16_t data); + virtual void writeConfig(int offset, const uint32_t data); + + + /** + * Read from the PCI config space data that is stored locally. This may be + * overridden by the device but at some point it will eventually call this + * for normal operations that it does not need to override. + * @param offset the offset into config space + * @param size the size of the read + * @param data pointer to the location where the read value should be stored + */ + virtual void readConfig(int offset, uint8_t *data); + virtual void readConfig(int offset, uint16_t *data); + virtual void readConfig(int offset, uint32_t *data); + + /** + * Serialize this object to the given output stream. + * @param os The stream to serialize to. + */ + virtual void serialize(std::ostream &os); + + /** + * Reconstruct the state of this object from a checkpoint. + * @param cp The checkpoint use. + * @param section The section name of this object + */ + virtual void unserialize(Checkpoint *cp, const std::string §ion); +}; +#endif // __DEV_PCIDEV_HH__ diff --git a/dev/pcireg.h b/src/dev/pcireg.h index 9d2737c20..9d2737c20 100644 --- a/dev/pcireg.h +++ b/src/dev/pcireg.h diff --git a/dev/pitreg.h b/src/dev/pitreg.h index 5fe1cf03f..5fe1cf03f 100644 --- a/dev/pitreg.h +++ b/src/dev/pitreg.h diff --git a/src/dev/pktfifo.cc b/src/dev/pktfifo.cc new file mode 100644 index 000000000..922a66912 --- /dev/null +++ b/src/dev/pktfifo.cc @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "base/misc.hh" +#include "dev/pktfifo.hh" + +using namespace std; + +bool +PacketFifo::copyout(void *dest, int offset, int len) +{ + char *data = (char *)dest; + if (offset + len >= size()) + return false; + + list<EthPacketPtr>::iterator p = fifo.begin(); + list<EthPacketPtr>::iterator end = fifo.end(); + while (len > 0) { + while (offset >= (*p)->length) { + offset -= (*p)->length; + ++p; + } + + if (p == end) + panic("invalid fifo"); + + int size = min((*p)->length - offset, len); + memcpy(data, (*p)->data, size); + offset = 0; + len -= size; + data += size; + ++p; + } + + return true; +} + + +void +PacketFifo::serialize(const string &base, ostream &os) +{ + paramOut(os, base + ".size", _size); + paramOut(os, base + ".maxsize", _maxsize); + paramOut(os, base + ".reserved", _reserved); + paramOut(os, base + ".packets", fifo.size()); + + int i = 0; + list<EthPacketPtr>::iterator p = fifo.begin(); + list<EthPacketPtr>::iterator end = fifo.end(); + while (p != end) { + (*p)->serialize(csprintf("%s.packet%d", base, i), os); + ++p; + ++i; + } +} + +void +PacketFifo::unserialize(const string &base, Checkpoint *cp, + const string §ion) +{ + paramIn(cp, section, base + ".size", _size); +// paramIn(cp, section, base + ".maxsize", _maxsize); + paramIn(cp, section, base + ".reserved", _reserved); + int fifosize; + paramIn(cp, section, base + ".packets", fifosize); + + fifo.clear(); + + for (int i = 0; i < fifosize; ++i) { + EthPacketPtr p = new EthPacketData(16384); + p->unserialize(csprintf("%s.packet%d", base, i), cp, section); + fifo.push_back(p); + } +} diff --git a/src/dev/pktfifo.hh b/src/dev/pktfifo.hh new file mode 100644 index 000000000..336da22d8 --- /dev/null +++ b/src/dev/pktfifo.hh @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __DEV_PKTFIFO_HH__ +#define __DEV_PKTFIFO_HH__ + +#include <iosfwd> +#include <list> +#include <string> + +#include "dev/etherpkt.hh" +#include "sim/serialize.hh" + +class Checkpoint; +class PacketFifo +{ + public: + typedef std::list<EthPacketPtr> fifo_list; + typedef fifo_list::iterator iterator; + + protected: + std::list<EthPacketPtr> fifo; + int _maxsize; + int _size; + int _reserved; + + public: + explicit PacketFifo(int max) : _maxsize(max), _size(0), _reserved(0) {} + virtual ~PacketFifo() {} + + int packets() const { return fifo.size(); } + int maxsize() const { return _maxsize; } + int size() const { return _size; } + int reserved() const { return _reserved; } + int avail() const { return _maxsize - _size - _reserved; } + bool empty() const { return size() <= 0; } + bool full() const { return avail() <= 0; } + + int reserve(int len = 0) + { + _reserved += len; + assert(avail() >= 0); + return _reserved; + } + + iterator begin() { return fifo.begin(); } + iterator end() { return fifo.end(); } + + EthPacketPtr front() { return fifo.front(); } + + bool push(EthPacketPtr ptr) + { + assert(ptr->length); + assert(_reserved <= ptr->length); + assert(ptr->slack == 0); + if (avail() < ptr->length - _reserved) + return false; + + _size += ptr->length; + fifo.push_back(ptr); + _reserved = 0; + return true; + } + + void pop() + { + if (empty()) + return; + + EthPacketPtr &packet = fifo.front(); + _size -= packet->length; + _size -= packet->slack; + packet->slack = 0; + packet = NULL; + fifo.pop_front(); + } + + void clear() + { + for (iterator i = begin(); i != end(); ++i) + (*i)->slack = 0; + fifo.clear(); + _size = 0; + _reserved = 0; + } + + void remove(iterator i) + { + EthPacketPtr &packet = *i; + if (i != fifo.begin()) { + iterator prev = i; + --prev; + assert(prev != fifo.end()); + (*prev)->slack += packet->length; + } else { + _size -= packet->length; + _size -= packet->slack; + } + + packet->slack = 0; + packet = NULL; + fifo.erase(i); + } + + bool copyout(void *dest, int offset, int len); + + int countPacketsBefore(iterator end) + { + iterator i = fifo.begin(); + int count = 0; + + while (i != end) { + ++count; + ++i; + } + + return count; + } + + int countPacketsAfter(iterator i) + { + iterator end = fifo.end(); + int count = 0; + + while (i != end) { + ++count; + ++i; + } + + return count; + } + + +/** + * Serialization stuff + */ + public: + void serialize(const std::string &base, std::ostream &os); + void unserialize(const std::string &base, + Checkpoint *cp, const std::string §ion); +}; + +#endif // __DEV_PKTFIFO_HH__ diff --git a/src/dev/platform.cc b/src/dev/platform.cc new file mode 100644 index 000000000..9d10e0828 --- /dev/null +++ b/src/dev/platform.cc @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "dev/platform.hh" +#include "sim/builder.hh" +#include "sim/sim_exit.hh" + +using namespace std; +using namespace TheISA; + +Platform::Platform(const string &name, IntrControl *intctrl) + : SimObject(name), intrctrl(intctrl) +{ +} + +Platform::~Platform() +{ +} + +void +Platform::postPciInt(int line) +{ + panic("No PCI interrupt support in platform."); +} + +void +Platform::clearPciInt(int line) +{ + panic("No PCI interrupt support in platform."); +} + +Addr +Platform::pciToDma(Addr pciAddr) const +{ + panic("No PCI dma support in platform."); +} + +DEFINE_SIM_OBJECT_CLASS_NAME("Platform", Platform) + diff --git a/src/dev/platform.hh b/src/dev/platform.hh new file mode 100644 index 000000000..f149ca2fb --- /dev/null +++ b/src/dev/platform.hh @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * Generic interface for platforms + */ + +#ifndef __DEV_PLATFORM_HH__ +#define __DEV_PLATFORM_HH__ + +#include "sim/sim_object.hh" +#include "arch/isa_traits.hh" + +class PciConfigAll; +class IntrControl; +class SimConsole; +class Uart; +class System; + +class Platform : public SimObject +{ + public: + /** Pointer to the interrupt controller */ + IntrControl *intrctrl; + + /** Pointer to the PCI configuration space */ + PciConfigAll *pciconfig; + + /** Pointer to the UART, set by the uart */ + Uart *uart; + + /** Pointer to the system for info about the memory system. */ + System *system; + + public: + Platform(const std::string &name, IntrControl *intctrl); + virtual ~Platform(); + virtual void init() { if (pciconfig == NULL) panic("PCI Config not set"); } + virtual void postConsoleInt() = 0; + virtual void clearConsoleInt() = 0; + virtual Tick intrFrequency() = 0; + virtual void postPciInt(int line); + virtual void clearPciInt(int line); + virtual Addr pciToDma(Addr pciAddr) const; +}; + +#endif // __DEV_PLATFORM_HH__ diff --git a/dev/rtcreg.h b/src/dev/rtcreg.h index 5025a0e95..5025a0e95 100644 --- a/dev/rtcreg.h +++ b/src/dev/rtcreg.h diff --git a/src/dev/simconsole.cc b/src/dev/simconsole.cc new file mode 100644 index 000000000..e33fa18b5 --- /dev/null +++ b/src/dev/simconsole.cc @@ -0,0 +1,413 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* @file + * Implements the user interface to a serial console + */ + +#include <sys/ioctl.h> +#include <sys/termios.h> +#include <sys/types.h> +#include <errno.h> +#include <poll.h> +#include <unistd.h> + +#include <iostream> +#include <fstream> +#include <sstream> +#include <string> + +#include "base/misc.hh" +#include "base/output.hh" +#include "base/socket.hh" +#include "base/trace.hh" +#include "dev/platform.hh" +#include "dev/simconsole.hh" +#include "dev/uart.hh" +#include "sim/builder.hh" + +using namespace std; + +//////////////////////////////////////////////////////////////////////// +// +// + +SimConsole::Event::Event(SimConsole *c, int fd, int e) + : PollEvent(fd, e), cons(c) +{ +} + +void +SimConsole::Event::process(int revent) +{ + if (revent & POLLIN) + cons->data(); + else if (revent & POLLNVAL) + cons->detach(); +} + +SimConsole::SimConsole(const string &name, ostream *os, int num) + : SimObject(name), event(NULL), number(num), in_fd(-1), out_fd(-1), + listener(NULL), txbuf(16384), rxbuf(16384), outfile(os) +#if TRACING_ON == 1 + , linebuf(16384) +#endif +{ + if (outfile) + outfile->setf(ios::unitbuf); +} + +SimConsole::~SimConsole() +{ + close(); +} + +void +SimConsole::close() +{ + if (in_fd != -1) + ::close(in_fd); + + if (out_fd != in_fd && out_fd != -1) + ::close(out_fd); +} + +void +SimConsole::attach(int in, int out, ConsoleListener *l) +{ + in_fd = in; + out_fd = out; + listener = l; + + event = new Event(this, in, POLLIN); + pollQueue.schedule(event); + + stringstream stream; + ccprintf(stream, "==== m5 slave console: Console %d ====", number); + + // we need an actual carriage return followed by a newline for the + // terminal + stream << "\r\n"; + + write((const uint8_t *)stream.str().c_str(), stream.str().size()); + + + DPRINTFN("attach console %d\n", number); + + txbuf.readall(out); +} + +void +SimConsole::detach() +{ + close(); + in_fd = -1; + out_fd = -1; + + pollQueue.remove(event); + + if (listener) { + listener->add(this); + listener = NULL; + } + + DPRINTFN("detach console %d\n", number); +} + +void +SimConsole::data() +{ + uint8_t buf[1024]; + int len; + + len = read(buf, sizeof(buf)); + if (len) { + rxbuf.write((char *)buf, len); + // Inform the UART there is data available + uart->dataAvailable(); + } +} + +size_t +SimConsole::read(uint8_t *buf, size_t len) +{ + if (in_fd < 0) + panic("Console not properly attached.\n"); + + size_t ret; + do { + ret = ::read(in_fd, buf, len); + } while (ret == -1 && errno == EINTR); + + + if (ret < 0) + DPRINTFN("Read failed.\n"); + + if (ret <= 0) { + detach(); + return 0; + } + + return ret; +} + +// Console output. +size_t +SimConsole::write(const uint8_t *buf, size_t len) +{ + if (out_fd < 0) + panic("Console not properly attached.\n"); + + size_t ret; + for (;;) { + ret = ::write(out_fd, buf, len); + + if (ret >= 0) + break; + + if (errno != EINTR) + detach(); + } + + return ret; +} + +#define MORE_PENDING (ULL(1) << 61) +#define RECEIVE_SUCCESS (ULL(0) << 62) +#define RECEIVE_NONE (ULL(2) << 62) +#define RECEIVE_ERROR (ULL(3) << 62) + +uint8_t +SimConsole::in() +{ + bool empty; + uint8_t c; + + empty = rxbuf.empty(); + assert(!empty); + rxbuf.read((char *)&c, 1); + empty = rxbuf.empty(); + + + DPRINTF(ConsoleVerbose, "in: \'%c\' %#02x more: %d\n", + isprint(c) ? c : ' ', c, !empty); + + return c; +} + +uint64_t +SimConsole::console_in() +{ + uint64_t value; + + if (dataAvailable()) { + value = RECEIVE_SUCCESS | in(); + if (!rxbuf.empty()) + value |= MORE_PENDING; + } else { + value = RECEIVE_NONE; + } + + DPRINTF(ConsoleVerbose, "console_in: return: %#x\n", value); + + return value; +} + +void +SimConsole::out(char c) +{ +#if TRACING_ON == 1 + if (DTRACE(Console)) { + static char last = '\0'; + + if (c != '\n' && c != '\r' || + last != '\n' && last != '\r') { + if (c == '\n' || c == '\r') { + int size = linebuf.size(); + char *buffer = new char[size + 1]; + linebuf.read(buffer, size); + buffer[size] = '\0'; + DPRINTF(Console, "%s\n", buffer); + delete [] buffer; + } else { + linebuf.write(c); + } + } + + last = c; + } +#endif + + txbuf.write(c); + + if (out_fd >= 0) + write(c); + + if (outfile) + outfile->write(&c, 1); + + DPRINTF(ConsoleVerbose, "out: \'%c\' %#02x\n", + isprint(c) ? c : ' ', (int)c); + +} + + +void +SimConsole::serialize(ostream &os) +{ +} + +void +SimConsole::unserialize(Checkpoint *cp, const std::string §ion) +{ +} + + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimConsole) + + SimObjectParam<ConsoleListener *> listener; + SimObjectParam<IntrControl *> intr_control; + Param<string> output; + Param<bool> append_name; + Param<int> number; + +END_DECLARE_SIM_OBJECT_PARAMS(SimConsole) + +BEGIN_INIT_SIM_OBJECT_PARAMS(SimConsole) + + INIT_PARAM(listener, "console listener"), + INIT_PARAM(intr_control, "interrupt controller"), + INIT_PARAM(output, "file to dump output to"), + INIT_PARAM_DFLT(append_name, "append name() to filename", true), + INIT_PARAM_DFLT(number, "console number", 0) + +END_INIT_SIM_OBJECT_PARAMS(SimConsole) + +CREATE_SIM_OBJECT(SimConsole) +{ + string filename = output; + ostream *stream = NULL; + + if (!filename.empty()) { + if (append_name) + filename += "." + getInstanceName(); + stream = simout.find(filename); + } + + SimConsole *console = new SimConsole(getInstanceName(), stream, number); + ((ConsoleListener *)listener)->add(console); + + return console; +} + +REGISTER_SIM_OBJECT("SimConsole", SimConsole) + +//////////////////////////////////////////////////////////////////////// +// +// + +ConsoleListener::ConsoleListener(const string &name) + : SimObject(name), event(NULL) +{} + +ConsoleListener::~ConsoleListener() +{ + if (event) + delete event; +} + +void +ConsoleListener::Event::process(int revent) +{ + listener->accept(); +} + +/////////////////////////////////////////////////////////////////////// +// socket creation and console attach +// + +void +ConsoleListener::listen(int port) +{ + while (!listener.listen(port, true)) { + DPRINTF(Console, + ": can't bind address console port %d inuse PID %d\n", + port, getpid()); + port++; + } + + ccprintf(cerr, "Listening for console connection on port %d\n", port); + + event = new Event(this, listener.getfd(), POLLIN); + pollQueue.schedule(event); +} + +void +ConsoleListener::add(SimConsole *cons) +{ ConsoleList.push_back(cons);} + +void +ConsoleListener::accept() +{ + if (!listener.islistening()) + panic("%s: cannot accept a connection if not listening!", name()); + + int sfd = listener.accept(true); + if (sfd != -1) { + iter_t i = ConsoleList.begin(); + iter_t end = ConsoleList.end(); + if (i == end) { + close(sfd); + } else { + (*i)->attach(sfd, this); + i = ConsoleList.erase(i); + } + } +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(ConsoleListener) + + Param<int> port; + +END_DECLARE_SIM_OBJECT_PARAMS(ConsoleListener) + +BEGIN_INIT_SIM_OBJECT_PARAMS(ConsoleListener) + + INIT_PARAM_DFLT(port, "listen port", 3456) + +END_INIT_SIM_OBJECT_PARAMS(ConsoleListener) + +CREATE_SIM_OBJECT(ConsoleListener) +{ + ConsoleListener *listener = new ConsoleListener(getInstanceName()); + listener->listen(port); + + return listener; +} + +REGISTER_SIM_OBJECT("ConsoleListener", ConsoleListener) diff --git a/src/dev/simconsole.hh b/src/dev/simconsole.hh new file mode 100644 index 000000000..64d1f6717 --- /dev/null +++ b/src/dev/simconsole.hh @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* @file + * User Console Interface + */ + +#ifndef __CONSOLE_HH__ +#define __CONSOLE_HH__ + +#include <iostream> + +#include "base/circlebuf.hh" +#include "cpu/intr_control.hh" +#include "base/pollevent.hh" +#include "base/socket.hh" +#include "sim/sim_object.hh" + +class ConsoleListener; +class Uart; + +class SimConsole : public SimObject +{ + public: + Uart *uart; + + protected: + class Event : public PollEvent + { + protected: + SimConsole *cons; + + public: + Event(SimConsole *c, int fd, int e); + void process(int revent); + }; + + friend class Event; + Event *event; + + protected: + int number; + int in_fd; + int out_fd; + ConsoleListener *listener; + + public: + SimConsole(const std::string &name, std::ostream *os, int num); + ~SimConsole(); + + protected: + CircleBuf txbuf; + CircleBuf rxbuf; + std::ostream *outfile; +#if TRACING_ON == 1 + CircleBuf linebuf; +#endif + + public: + /////////////////////// + // Terminal Interface + + void attach(int fd, ConsoleListener *l = NULL) { attach(fd, fd, l); } + void attach(int in, int out, ConsoleListener *l = NULL); + void detach(); + + void data(); + + void close(); + void read(uint8_t &c) { read(&c, 1); } + size_t read(uint8_t *buf, size_t len); + void write(uint8_t c) { write(&c, 1); } + size_t write(const uint8_t *buf, size_t len); + + public: + ///////////////// + // OS interface + + // Get a character from the console. + uint8_t in(); + + // get a character from the console in the console specific format + // corresponds to GETC: + // retval<63:61> + // 000: success: character received + // 001: success: character received, more pending + // 100: failure: no character ready + // 110: failure: character received with error + // 111: failure: character received with error, more pending + // retval<31:0> + // character read from console + // + // Interrupts are cleared when the buffer is empty. + uint64_t console_in(); + + // Send a character to the console + void out(char c); + + //Ask the console if data is available + bool dataAvailable() { return !rxbuf.empty(); } + + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); +}; + +class ConsoleListener : public SimObject +{ + protected: + class Event : public PollEvent + { + protected: + ConsoleListener *listener; + + public: + Event(ConsoleListener *l, int fd, int e) + : PollEvent(fd, e), listener(l) {} + void process(int revent); + }; + + friend class Event; + Event *event; + + typedef std::list<SimConsole *> list_t; + typedef list_t::iterator iter_t; + list_t ConsoleList; + + protected: + ListenSocket listener; + + public: + ConsoleListener(const std::string &name); + ~ConsoleListener(); + + void add(SimConsole *cons); + + void accept(); + void listen(int port); +}; + +#endif // __CONSOLE_HH__ diff --git a/src/dev/simple_disk.cc b/src/dev/simple_disk.cc new file mode 100644 index 000000000..9eee4668c --- /dev/null +++ b/src/dev/simple_disk.cc @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* @file + * Simple disk interface for the system console + */ + +#include <sys/types.h> +#include <sys/uio.h> +#include <fcntl.h> +#include <unistd.h> + +#include <cstring> +#include <string> + +#include "base/misc.hh" +#include "base/trace.hh" +#include "dev/disk_image.hh" +#include "dev/simple_disk.hh" +#include "mem/port.hh" +#include "sim/builder.hh" +#include "sim/system.hh" + +using namespace std; + +SimpleDisk::SimpleDisk(const string &name, System *sys, DiskImage *img) + : SimObject(name), system(sys), image(img) +{} + +SimpleDisk::~SimpleDisk() +{} + + +void +SimpleDisk::read(Addr addr, baddr_t block, int count) const +{ + uint8_t *data = new uint8_t[SectorSize * count]; + + if (count & (SectorSize - 1)) + panic("Not reading a multiple of a sector (count = %d)", count); + + for (int i = 0, j = 0; i < count; i += SectorSize, j++) + image->read(data + i, block + j); + + system->functionalPort.writeBlob(addr, data, count); + + DPRINTF(SimpleDisk, "read block=%#x len=%d\n", (uint64_t)block, count); + DDUMP(SimpleDiskData, data, count); + + delete data; +} + +void +SimpleDisk::write(Addr addr, baddr_t block, int count) +{ + panic("unimplemented!\n"); + +#if 0 + uint8_t *data = physmem->dma_addr(addr, count); + if (!data) + panic("dma out of range! write addr=%#x count=%d\n", addr, count); + + image->write(data, block, count); +#endif +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleDisk) + + SimObjectParam<System *> system; + SimObjectParam<DiskImage *> disk; + +END_DECLARE_SIM_OBJECT_PARAMS(SimpleDisk) + +BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleDisk) + + INIT_PARAM(system, "System pointer"), + INIT_PARAM(disk, "Disk Image") + +END_INIT_SIM_OBJECT_PARAMS(SimpleDisk) + +CREATE_SIM_OBJECT(SimpleDisk) +{ + return new SimpleDisk(getInstanceName(), system, disk); +} + +REGISTER_SIM_OBJECT("SimpleDisk", SimpleDisk) diff --git a/src/dev/simple_disk.hh b/src/dev/simple_disk.hh new file mode 100644 index 000000000..19967f208 --- /dev/null +++ b/src/dev/simple_disk.hh @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* @file + * Simple disk interface for the system console + */ + +#ifndef __DEV_SIMPLE_DISK_HH__ +#define __DEV_SIMPLE_DISK_HH__ + +#include "sim/sim_object.hh" +#include "arch/isa_traits.hh" + +class DiskImage; +class System; + +/* + * Trivial interface to a disk image used by the System Console + */ +class SimpleDisk : public SimObject +{ + public: + typedef uint64_t baddr_t; + + protected: + System *system; + DiskImage *image; + + public: + SimpleDisk(const std::string &name, System *sys, DiskImage *img); + ~SimpleDisk(); + + void read(Addr addr, baddr_t block, int count) const; + void write(Addr addr, baddr_t block, int count); +}; + +#endif // __DEV_SIMPLE_DISK_HH__ diff --git a/src/dev/sinic.cc b/src/dev/sinic.cc new file mode 100644 index 000000000..31fbc49aa --- /dev/null +++ b/src/dev/sinic.cc @@ -0,0 +1,1756 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <deque> +#include <limits> +#include <string> + +#include "base/inet.hh" +#include "cpu/exec_context.hh" +#include "cpu/intr_control.hh" +#include "dev/etherlink.hh" +#include "dev/sinic.hh" +#include "dev/pciconfigall.hh" +#include "mem/packet.hh" +#include "sim/builder.hh" +#include "sim/debug.hh" +#include "sim/eventq.hh" +#include "sim/host.hh" +#include "sim/stats.hh" +#include "arch/vtophys.hh" + +using namespace Net; +using namespace TheISA; + +namespace Sinic { + +const char *RxStateStrings[] = +{ + "rxIdle", + "rxFifoBlock", + "rxBeginCopy", + "rxCopy", + "rxCopyDone" +}; + +const char *TxStateStrings[] = +{ + "txIdle", + "txFifoBlock", + "txBeginCopy", + "txCopy", + "txCopyDone" +}; + + +/////////////////////////////////////////////////////////////////////// +// +// Sinic PCI Device +// +Base::Base(Params *p) + : PciDev(p), rxEnable(false), txEnable(false), clock(p->clock), + intrDelay(p->intr_delay), intrTick(0), cpuIntrEnable(false), + cpuPendingIntr(false), intrEvent(0), interface(NULL) +{ +} + +Device::Device(Params *p) + : Base(p), rxUnique(0), txUnique(0), + virtualRegs(p->virtual_count < 1 ? 1 : p->virtual_count), + rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size), + rxKickTick(0), txKickTick(0), + txEvent(this), rxDmaEvent(this), txDmaEvent(this), + dmaReadDelay(p->dma_read_delay), dmaReadFactor(p->dma_read_factor), + dmaWriteDelay(p->dma_write_delay), dmaWriteFactor(p->dma_write_factor) +{ + reset(); + +} + +Device::~Device() +{} + +void +Device::regStats() +{ + rxBytes + .name(name() + ".rxBytes") + .desc("Bytes Received") + .prereq(rxBytes) + ; + + rxBandwidth + .name(name() + ".rxBandwidth") + .desc("Receive Bandwidth (bits/s)") + .precision(0) + .prereq(rxBytes) + ; + + rxPackets + .name(name() + ".rxPackets") + .desc("Number of Packets Received") + .prereq(rxBytes) + ; + + rxPacketRate + .name(name() + ".rxPPS") + .desc("Packet Reception Rate (packets/s)") + .precision(0) + .prereq(rxBytes) + ; + + rxIpPackets + .name(name() + ".rxIpPackets") + .desc("Number of IP Packets Received") + .prereq(rxBytes) + ; + + rxTcpPackets + .name(name() + ".rxTcpPackets") + .desc("Number of Packets Received") + .prereq(rxBytes) + ; + + rxUdpPackets + .name(name() + ".rxUdpPackets") + .desc("Number of UDP Packets Received") + .prereq(rxBytes) + ; + + rxIpChecksums + .name(name() + ".rxIpChecksums") + .desc("Number of rx IP Checksums done by device") + .precision(0) + .prereq(rxBytes) + ; + + rxTcpChecksums + .name(name() + ".rxTcpChecksums") + .desc("Number of rx TCP Checksums done by device") + .precision(0) + .prereq(rxBytes) + ; + + rxUdpChecksums + .name(name() + ".rxUdpChecksums") + .desc("Number of rx UDP Checksums done by device") + .precision(0) + .prereq(rxBytes) + ; + + totBandwidth + .name(name() + ".totBandwidth") + .desc("Total Bandwidth (bits/s)") + .precision(0) + .prereq(totBytes) + ; + + totPackets + .name(name() + ".totPackets") + .desc("Total Packets") + .precision(0) + .prereq(totBytes) + ; + + totBytes + .name(name() + ".totBytes") + .desc("Total Bytes") + .precision(0) + .prereq(totBytes) + ; + + totPacketRate + .name(name() + ".totPPS") + .desc("Total Tranmission Rate (packets/s)") + .precision(0) + .prereq(totBytes) + ; + + txBytes + .name(name() + ".txBytes") + .desc("Bytes Transmitted") + .prereq(txBytes) + ; + + txBandwidth + .name(name() + ".txBandwidth") + .desc("Transmit Bandwidth (bits/s)") + .precision(0) + .prereq(txBytes) + ; + + txPackets + .name(name() + ".txPackets") + .desc("Number of Packets Transmitted") + .prereq(txBytes) + ; + + txPacketRate + .name(name() + ".txPPS") + .desc("Packet Tranmission Rate (packets/s)") + .precision(0) + .prereq(txBytes) + ; + + txIpPackets + .name(name() + ".txIpPackets") + .desc("Number of IP Packets Transmitted") + .prereq(txBytes) + ; + + txTcpPackets + .name(name() + ".txTcpPackets") + .desc("Number of TCP Packets Transmitted") + .prereq(txBytes) + ; + + txUdpPackets + .name(name() + ".txUdpPackets") + .desc("Number of Packets Transmitted") + .prereq(txBytes) + ; + + txIpChecksums + .name(name() + ".txIpChecksums") + .desc("Number of tx IP Checksums done by device") + .precision(0) + .prereq(txBytes) + ; + + txTcpChecksums + .name(name() + ".txTcpChecksums") + .desc("Number of tx TCP Checksums done by device") + .precision(0) + .prereq(txBytes) + ; + + txUdpChecksums + .name(name() + ".txUdpChecksums") + .desc("Number of tx UDP Checksums done by device") + .precision(0) + .prereq(txBytes) + ; + + txBandwidth = txBytes * Stats::constant(8) / simSeconds; + rxBandwidth = rxBytes * Stats::constant(8) / simSeconds; + totBandwidth = txBandwidth + rxBandwidth; + totBytes = txBytes + rxBytes; + totPackets = txPackets + rxPackets; + txPacketRate = txPackets / simSeconds; + rxPacketRate = rxPackets / simSeconds; +} + +void +Device::prepareIO(int cpu, int index) +{ + int size = virtualRegs.size(); + if (index > size) + panic("Trying to access a vnic that doesn't exist %d > %d\n", + index, size); +} + +void +Device::prepareRead(int cpu, int index) +{ + using namespace Regs; + prepareIO(cpu, index); + + VirtualReg &vnic = virtualRegs[index]; + + // update rx registers + uint64_t rxdone = vnic.RxDone; + rxdone = set_RxDone_Packets(rxdone, rxFifo.countPacketsAfter(rxFifoPtr)); + rxdone = set_RxDone_Empty(rxdone, rxFifo.empty()); + rxdone = set_RxDone_High(rxdone, rxFifo.size() > regs.RxFifoMark); + rxdone = set_RxDone_NotHigh(rxdone, rxLow); + regs.RxData = vnic.RxData; + regs.RxDone = rxdone; + regs.RxWait = rxdone; + + // update tx regsiters + uint64_t txdone = vnic.TxDone; + txdone = set_TxDone_Packets(txdone, txFifo.packets()); + txdone = set_TxDone_Full(txdone, txFifo.avail() < regs.TxMaxCopy); + txdone = set_TxDone_Low(txdone, txFifo.size() < regs.TxFifoMark); + regs.TxData = vnic.TxData; + regs.TxDone = txdone; + regs.TxWait = txdone; +} + +void +Device::prepareWrite(int cpu, int index) +{ + prepareIO(cpu, index); +} + +/** + * I/O read of device register + */ +Tick +Device::read(Packet *pkt) +{ + assert(config.command & PCI_CMD_MSE); + assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]); + + int cpu = pkt->req->getCpuNum(); + Addr daddr = pkt->getAddr() - BARAddrs[0]; + Addr index = daddr >> Regs::VirtualShift; + Addr raddr = daddr & Regs::VirtualMask; + + pkt->time += pioDelay; + pkt->allocate(); + + if (!regValid(raddr)) + panic("invalid register: cpu=%d vnic=%d da=%#x pa=%#x size=%d", + cpu, index, daddr, pkt->getAddr(), pkt->getSize()); + + const Regs::Info &info = regInfo(raddr); + if (!info.read) + panic("read %s (write only): " + "cpu=%d vnic=%d da=%#x pa=%#x size=%d", + info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize()); + + panic("read %s (invalid size): " + "cpu=%d vnic=%d da=%#x pa=%#x size=%d", + info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize()); + + prepareRead(cpu, index); + + uint64_t value = 0; + if (pkt->getSize() == 4) { + uint32_t reg = regData32(raddr); + pkt->set(reg); + value = reg; + } + + if (pkt->getSize() == 8) { + uint64_t reg = regData64(raddr); + pkt->set(reg); + value = reg; + } + + DPRINTF(EthernetPIO, + "read %s: cpu=%d vnic=%d da=%#x pa=%#x size=%d val=%#x\n", + info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize(), value); + + // reading the interrupt status register has the side effect of + // clearing it + if (raddr == Regs::IntrStatus) + devIntrClear(); + + return pioDelay; +} + +/** + * IPR read of device register + + Fault +Device::iprRead(Addr daddr, int cpu, uint64_t &result) +{ + if (!regValid(daddr)) + panic("invalid address: da=%#x", daddr); + + const Regs::Info &info = regInfo(daddr); + if (!info.read) + panic("reading %s (write only): cpu=%d da=%#x", info.name, cpu, daddr); + + DPRINTF(EthernetPIO, "IPR read %s: cpu=%d da=%#x\n", + info.name, cpu, daddr); + + prepareRead(cpu, 0); + + if (info.size == 4) + result = regData32(daddr); + + if (info.size == 8) + result = regData64(daddr); + + DPRINTF(EthernetPIO, "IPR read %s: cpu=%s da=%#x val=%#x\n", + info.name, cpu, result); + + return NoFault; +} +*/ +/** + * I/O write of device register + */ +Tick +Device::write(Packet *pkt) +{ + assert(config.command & PCI_CMD_MSE); + assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]); + + int cpu = pkt->req->getCpuNum(); + Addr daddr = pkt->getAddr() - BARAddrs[0]; + Addr index = daddr >> Regs::VirtualShift; + Addr raddr = daddr & Regs::VirtualMask; + + pkt->time += pioDelay; + + if (!regValid(raddr)) + panic("invalid register: cpu=%d, da=%#x pa=%#x size=%d", + cpu, daddr, pkt->getAddr(), pkt->getSize()); + + const Regs::Info &info = regInfo(raddr); + if (!info.write) + panic("write %s (read only): " + "cpu=%d vnic=%d da=%#x pa=%#x size=%d", + info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize()); + + if (pkt->getSize() != info.size) + panic("write %s (invalid size): " + "cpu=%d vnic=%d da=%#x pa=%#x size=%d", + info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize()); + + VirtualReg &vnic = virtualRegs[index]; + + DPRINTF(EthernetPIO, + "write %s vnic %d: cpu=%d val=%#x da=%#x pa=%#x size=%d\n", + info.name, index, cpu, info.size == 4 ? pkt->get<uint32_t>() : + pkt->get<uint64_t>(), daddr, pkt->getAddr(), pkt->getSize()); + + prepareWrite(cpu, index); + + switch (raddr) { + case Regs::Config: + changeConfig(pkt->get<uint32_t>()); + break; + + case Regs::Command: + command(pkt->get<uint32_t>()); + break; + + case Regs::IntrStatus: + devIntrClear(regs.IntrStatus & pkt->get<uint32_t>()); + break; + + case Regs::IntrMask: + devIntrChangeMask(pkt->get<uint32_t>()); + break; + + case Regs::RxData: + if (Regs::get_RxDone_Busy(vnic.RxDone)) + panic("receive machine busy with another request! rxState=%s", + RxStateStrings[rxState]); + + vnic.rxUnique = rxUnique++; + vnic.RxDone = Regs::RxDone_Busy; + vnic.RxData = pkt->get<uint64_t>(); + + if (Regs::get_RxData_Vaddr(pkt->get<uint64_t>())) { + panic("vtophys not implemented in newmem"); +/* Addr vaddr = Regs::get_RxData_Addr(reg64); + Addr paddr = vtophys(req->xc, vaddr); + DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d): " + "vaddr=%#x, paddr=%#x\n", + index, vnic.rxUnique, vaddr, paddr); + + vnic.RxData = Regs::set_RxData_Addr(vnic.RxData, paddr);*/ + } else { + DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d)\n", + index, vnic.rxUnique); + } + + if (vnic.rxPacket == rxFifo.end()) { + DPRINTF(EthernetPIO, "request new packet...appending to rxList\n"); + rxList.push_back(index); + } else { + DPRINTF(EthernetPIO, "packet exists...appending to rxBusy\n"); + rxBusy.push_back(index); + } + + if (rxEnable && (rxState == rxIdle || rxState == rxFifoBlock)) { + rxState = rxFifoBlock; + rxKick(); + } + break; + + case Regs::TxData: + if (Regs::get_TxDone_Busy(vnic.TxDone)) + panic("transmit machine busy with another request! txState=%s", + TxStateStrings[txState]); + + vnic.txUnique = txUnique++; + vnic.TxDone = Regs::TxDone_Busy; + + if (Regs::get_TxData_Vaddr(pkt->get<uint64_t>())) { + panic("vtophys won't work here in newmem.\n"); + /*Addr vaddr = Regs::get_TxData_Addr(reg64); + Addr paddr = vtophys(req->xc, vaddr); + DPRINTF(EthernetPIO, "write TxData vnic %d (rxunique %d): " + "vaddr=%#x, paddr=%#x\n", + index, vnic.txUnique, vaddr, paddr); + + vnic.TxData = Regs::set_TxData_Addr(vnic.TxData, paddr);*/ + } else { + DPRINTF(EthernetPIO, "write TxData vnic %d (rxunique %d)\n", + index, vnic.txUnique); + } + + if (txList.empty() || txList.front() != index) + txList.push_back(index); + if (txEnable && txState == txIdle && txList.front() == index) { + txState = txFifoBlock; + txKick(); + } + break; + } + + return pioDelay; +} + +void +Device::devIntrPost(uint32_t interrupts) +{ + if ((interrupts & Regs::Intr_Res)) + panic("Cannot set a reserved interrupt"); + + regs.IntrStatus |= interrupts; + + DPRINTF(EthernetIntr, + "interrupt written to intStatus: intr=%#x status=%#x mask=%#x\n", + interrupts, regs.IntrStatus, regs.IntrMask); + + interrupts = regs.IntrStatus & regs.IntrMask; + + // Intr_RxHigh is special, we only signal it if we've emptied the fifo + // and then filled it above the high watermark + if (rxEmpty) + rxEmpty = false; + else + interrupts &= ~Regs::Intr_RxHigh; + + // Intr_TxLow is special, we only signal it if we've filled up the fifo + // and then dropped below the low watermark + if (txFull) + txFull = false; + else + interrupts &= ~Regs::Intr_TxLow; + + if (interrupts) { + Tick when = curTick; + if ((interrupts & Regs::Intr_NoDelay) == 0) + when += intrDelay; + cpuIntrPost(when); + } +} + +void +Device::devIntrClear(uint32_t interrupts) +{ + if ((interrupts & Regs::Intr_Res)) + panic("Cannot clear a reserved interrupt"); + + regs.IntrStatus &= ~interrupts; + + DPRINTF(EthernetIntr, + "interrupt cleared from intStatus: intr=%x status=%x mask=%x\n", + interrupts, regs.IntrStatus, regs.IntrMask); + + if (!(regs.IntrStatus & regs.IntrMask)) + cpuIntrClear(); +} + +void +Device::devIntrChangeMask(uint32_t newmask) +{ + if (regs.IntrMask == newmask) + return; + + regs.IntrMask = newmask; + + DPRINTF(EthernetIntr, + "interrupt mask changed: intStatus=%x intMask=%x masked=%x\n", + regs.IntrStatus, regs.IntrMask, regs.IntrStatus & regs.IntrMask); + + if (regs.IntrStatus & regs.IntrMask) + cpuIntrPost(curTick); + else + cpuIntrClear(); +} + +void +Base::cpuIntrPost(Tick when) +{ + // If the interrupt you want to post is later than an interrupt + // already scheduled, just let it post in the coming one and don't + // schedule another. + // HOWEVER, must be sure that the scheduled intrTick is in the + // future (this was formerly the source of a bug) + /** + * @todo this warning should be removed and the intrTick code should + * be fixed. + */ + assert(when >= curTick); + assert(intrTick >= curTick || intrTick == 0); + if (!cpuIntrEnable) { + DPRINTF(EthernetIntr, "interrupts not enabled.\n", + intrTick); + return; + } + + if (when > intrTick && intrTick != 0) { + DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n", + intrTick); + return; + } + + intrTick = when; + if (intrTick < curTick) { + debug_break(); + intrTick = curTick; + } + + DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n", + intrTick); + + if (intrEvent) + intrEvent->squash(); + intrEvent = new IntrEvent(this, true); + intrEvent->schedule(intrTick); +} + +void +Base::cpuInterrupt() +{ + assert(intrTick == curTick); + + // Whether or not there's a pending interrupt, we don't care about + // it anymore + intrEvent = 0; + intrTick = 0; + + // Don't send an interrupt if there's already one + if (cpuPendingIntr) { + DPRINTF(EthernetIntr, + "would send an interrupt now, but there's already pending\n"); + } else { + // Send interrupt + cpuPendingIntr = true; + + DPRINTF(EthernetIntr, "posting interrupt\n"); + intrPost(); + } +} + +void +Base::cpuIntrClear() +{ + if (!cpuPendingIntr) + return; + + if (intrEvent) { + intrEvent->squash(); + intrEvent = 0; + } + + intrTick = 0; + + cpuPendingIntr = false; + + DPRINTF(EthernetIntr, "clearing cchip interrupt\n"); + intrClear(); +} + +bool +Base::cpuIntrPending() const +{ return cpuPendingIntr; } + +void +Device::changeConfig(uint32_t newconf) +{ + uint32_t changed = regs.Config ^ newconf; + if (!changed) + return; + + regs.Config = newconf; + + if ((changed & Regs::Config_IntEn)) { + cpuIntrEnable = regs.Config & Regs::Config_IntEn; + if (cpuIntrEnable) { + if (regs.IntrStatus & regs.IntrMask) + cpuIntrPost(curTick); + } else { + cpuIntrClear(); + } + } + + if ((changed & Regs::Config_TxEn)) { + txEnable = regs.Config & Regs::Config_TxEn; + if (txEnable) + txKick(); + } + + if ((changed & Regs::Config_RxEn)) { + rxEnable = regs.Config & Regs::Config_RxEn; + if (rxEnable) + rxKick(); + } +} + +void +Device::command(uint32_t command) +{ + if (command & Regs::Command_Intr) + devIntrPost(Regs::Intr_Soft); + + if (command & Regs::Command_Reset) + reset(); +} + +void +Device::reset() +{ + using namespace Regs; + + memset(®s, 0, sizeof(regs)); + + regs.Config = 0; + if (params()->rx_thread) + regs.Config |= Config_RxThread; + if (params()->tx_thread) + regs.Config |= Config_TxThread; + if (params()->rss) + regs.Config |= Config_RSS; + if (params()->zero_copy) + regs.Config |= Config_ZeroCopy; + if (params()->delay_copy) + regs.Config |= Config_DelayCopy; + if (params()->virtual_addr) + regs.Config |= Config_Vaddr; + + if (params()->delay_copy && params()->zero_copy) + panic("Can't delay copy and zero copy"); + + regs.IntrMask = Intr_Soft | Intr_RxHigh | Intr_RxPacket | Intr_TxLow; + regs.RxMaxCopy = params()->rx_max_copy; + regs.TxMaxCopy = params()->tx_max_copy; + regs.RxMaxIntr = params()->rx_max_intr; + regs.VirtualCount = params()->virtual_count; + regs.RxFifoSize = params()->rx_fifo_size; + regs.TxFifoSize = params()->tx_fifo_size; + regs.RxFifoMark = params()->rx_fifo_threshold; + regs.TxFifoMark = params()->tx_fifo_threshold; + regs.HwAddr = params()->eaddr; + + rxList.clear(); + rxBusy.clear(); + rxActive = -1; + txList.clear(); + + rxState = rxIdle; + txState = txIdle; + + rxFifo.clear(); + rxFifoPtr = rxFifo.end(); + txFifo.clear(); + rxEmpty = false; + rxLow = true; + txFull = false; + + int size = virtualRegs.size(); + virtualRegs.clear(); + virtualRegs.resize(size); + for (int i = 0; i < size; ++i) + virtualRegs[i].rxPacket = rxFifo.end(); +} + +void +Device::rxDmaDone() +{ + assert(rxState == rxCopy); + rxState = rxCopyDone; + DPRINTF(EthernetDMA, "end rx dma write paddr=%#x len=%d\n", + rxDmaAddr, rxDmaLen); + DDUMP(EthernetData, rxDmaData, rxDmaLen); + + // If the transmit state machine has a pending DMA, let it go first + if (txState == txBeginCopy) + txKick(); + + rxKick(); +} + +void +Device::rxKick() +{ + VirtualReg *vnic = NULL; + + DPRINTF(EthernetSM, "rxKick: rxState=%s (rxFifo.size=%d)\n", + RxStateStrings[rxState], rxFifo.size()); + + if (rxKickTick > curTick) { + DPRINTF(EthernetSM, "rxKick: exiting, can't run till %d\n", + rxKickTick); + return; + } + + next: + if (rxState == rxIdle) + goto exit; + + if (rxActive == -1) { + if (rxState != rxFifoBlock) + panic("no active vnic while in state %s", RxStateStrings[rxState]); + + DPRINTF(EthernetSM, "processing rxState=%s\n", + RxStateStrings[rxState]); + } else { + vnic = &virtualRegs[rxActive]; + DPRINTF(EthernetSM, + "processing rxState=%s for vnic %d (rxunique %d)\n", + RxStateStrings[rxState], rxActive, vnic->rxUnique); + } + + switch (rxState) { + case rxFifoBlock: + if (DTRACE(EthernetSM)) { + PacketFifo::iterator end = rxFifo.end(); + int size = virtualRegs.size(); + for (int i = 0; i < size; ++i) { + VirtualReg *vn = &virtualRegs[i]; + if (vn->rxPacket != end && + !Regs::get_RxDone_Busy(vn->RxDone)) { + DPRINTF(EthernetSM, + "vnic %d (rxunique %d), has outstanding packet %d\n", + i, vn->rxUnique, + rxFifo.countPacketsBefore(vn->rxPacket)); + } + } + } + + if (!rxBusy.empty()) { + rxActive = rxBusy.front(); + rxBusy.pop_front(); + vnic = &virtualRegs[rxActive]; + + if (vnic->rxPacket == rxFifo.end()) + panic("continuing vnic without packet\n"); + + DPRINTF(EthernetSM, + "continue processing for vnic %d (rxunique %d)\n", + rxActive, vnic->rxUnique); + + rxState = rxBeginCopy; + + break; + } + + if (rxFifoPtr == rxFifo.end()) { + DPRINTF(EthernetSM, "receive waiting for data. Nothing to do.\n"); + goto exit; + } + + if (rxList.empty()) + panic("Not idle, but nothing to do!"); + + assert(!rxFifo.empty()); + + rxActive = rxList.front(); + rxList.pop_front(); + vnic = &virtualRegs[rxActive]; + + DPRINTF(EthernetSM, + "processing new packet for vnic %d (rxunique %d)\n", + rxActive, vnic->rxUnique); + + // Grab a new packet from the fifo. + vnic->rxPacket = rxFifoPtr++; + vnic->rxPacketOffset = 0; + vnic->rxPacketBytes = (*vnic->rxPacket)->length; + assert(vnic->rxPacketBytes); + + vnic->rxDoneData = 0; + /* scope for variables */ { + IpPtr ip(*vnic->rxPacket); + if (ip) { + DPRINTF(Ethernet, "ID is %d\n", ip->id()); + vnic->rxDoneData |= Regs::RxDone_IpPacket; + rxIpChecksums++; + if (cksum(ip) != 0) { + DPRINTF(EthernetCksum, "Rx IP Checksum Error\n"); + vnic->rxDoneData |= Regs::RxDone_IpError; + } + TcpPtr tcp(ip); + UdpPtr udp(ip); + if (tcp) { + DPRINTF(Ethernet, + "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", + tcp->sport(), tcp->dport(), tcp->seq(), + tcp->ack()); + vnic->rxDoneData |= Regs::RxDone_TcpPacket; + rxTcpChecksums++; + if (cksum(tcp) != 0) { + DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n"); + vnic->rxDoneData |= Regs::RxDone_TcpError; + } + } else if (udp) { + vnic->rxDoneData |= Regs::RxDone_UdpPacket; + rxUdpChecksums++; + if (cksum(udp) != 0) { + DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n"); + vnic->rxDoneData |= Regs::RxDone_UdpError; + } + } + } + } + rxState = rxBeginCopy; + break; + + case rxBeginCopy: + if (dmaPending()) + goto exit; + + rxDmaAddr = params()->platform->pciToDma( + Regs::get_RxData_Addr(vnic->RxData)); + rxDmaLen = std::min<int>(Regs::get_RxData_Len(vnic->RxData), + vnic->rxPacketBytes); + rxDmaData = (*vnic->rxPacket)->data + vnic->rxPacketOffset; + rxState = rxCopy; + if (rxDmaAddr == 1LL) { + rxState = rxCopyDone; + break; + } + + + dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaEvent, rxDmaData); + break; + + case rxCopy: + DPRINTF(EthernetSM, "receive machine still copying\n"); + goto exit; + + case rxCopyDone: + vnic->RxDone = vnic->rxDoneData; + vnic->RxDone |= Regs::RxDone_Complete; + + if (vnic->rxPacketBytes == rxDmaLen) { + // Packet is complete. Indicate how many bytes were copied + vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone, rxDmaLen); + + DPRINTF(EthernetSM, + "rxKick: packet complete on vnic %d (rxunique %d)\n", + rxActive, vnic->rxUnique); + rxFifo.remove(vnic->rxPacket); + vnic->rxPacket = rxFifo.end(); + } else { + vnic->rxPacketBytes -= rxDmaLen; + vnic->rxPacketOffset += rxDmaLen; + vnic->RxDone |= Regs::RxDone_More; + vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone, + vnic->rxPacketBytes); + DPRINTF(EthernetSM, + "rxKick: packet not complete on vnic %d (rxunique %d): " + "%d bytes left\n", + rxActive, vnic->rxUnique, vnic->rxPacketBytes); + } + + rxActive = -1; + rxState = rxBusy.empty() && rxList.empty() ? rxIdle : rxFifoBlock; + + if (rxFifo.empty()) { + devIntrPost(Regs::Intr_RxEmpty); + rxEmpty = true; + } + + if (rxFifo.size() < params()->rx_fifo_low_mark) + rxLow = true; + + if (rxFifo.size() > params()->rx_fifo_threshold) + rxLow = false; + + devIntrPost(Regs::Intr_RxDMA); + break; + + default: + panic("Invalid rxState!"); + } + + DPRINTF(EthernetSM, "entering next rxState=%s\n", + RxStateStrings[rxState]); + + goto next; + + exit: + /** + * @todo do we want to schedule a future kick? + */ + DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n", + RxStateStrings[rxState]); +} + +void +Device::txDmaDone() +{ + assert(txState == txCopy); + txState = txCopyDone; + DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n", + txDmaAddr, txDmaLen); + DDUMP(EthernetData, txDmaData, txDmaLen); + + // If the receive state machine has a pending DMA, let it go first + if (rxState == rxBeginCopy) + rxKick(); + + txKick(); +} + +void +Device::transmit() +{ + if (txFifo.empty()) { + DPRINTF(Ethernet, "nothing to transmit\n"); + return; + } + + uint32_t interrupts; + EthPacketPtr packet = txFifo.front(); + if (!interface->sendPacket(packet)) { + DPRINTF(Ethernet, "Packet Transmit: failed txFifo available %d\n", + txFifo.avail()); + goto reschedule; + } + + txFifo.pop(); +#if TRACING_ON + if (DTRACE(Ethernet)) { + IpPtr ip(packet); + if (ip) { + DPRINTF(Ethernet, "ID is %d\n", ip->id()); + TcpPtr tcp(ip); + if (tcp) { + DPRINTF(Ethernet, + "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", + tcp->sport(), tcp->dport(), tcp->seq(), + tcp->ack()); + } + } + } +#endif + + DDUMP(EthernetData, packet->data, packet->length); + txBytes += packet->length; + txPackets++; + + DPRINTF(Ethernet, "Packet Transmit: successful txFifo Available %d\n", + txFifo.avail()); + + interrupts = Regs::Intr_TxPacket; + if (txFifo.size() < regs.TxFifoMark) + interrupts |= Regs::Intr_TxLow; + devIntrPost(interrupts); + + reschedule: + if (!txFifo.empty() && !txEvent.scheduled()) { + DPRINTF(Ethernet, "reschedule transmit\n"); + txEvent.schedule(curTick + retryTime); + } +} + +void +Device::txKick() +{ + VirtualReg *vnic; + DPRINTF(EthernetSM, "txKick: txState=%s (txFifo.size=%d)\n", + TxStateStrings[txState], txFifo.size()); + + if (txKickTick > curTick) { + DPRINTF(EthernetSM, "txKick: exiting, can't run till %d\n", + txKickTick); + return; + } + + next: + if (txState == txIdle) + goto exit; + + assert(!txList.empty()); + vnic = &virtualRegs[txList.front()]; + + switch (txState) { + case txFifoBlock: + assert(Regs::get_TxDone_Busy(vnic->TxDone)); + if (!txPacket) { + // Grab a new packet from the fifo. + txPacket = new EthPacketData(16384); + txPacketOffset = 0; + } + + if (txFifo.avail() - txPacket->length < + Regs::get_TxData_Len(vnic->TxData)) { + DPRINTF(EthernetSM, "transmit fifo full. Nothing to do.\n"); + goto exit; + } + + txState = txBeginCopy; + break; + + case txBeginCopy: + if (dmaPending()) + goto exit; + + txDmaAddr = params()->platform->pciToDma( + Regs::get_TxData_Addr(vnic->TxData)); + txDmaLen = Regs::get_TxData_Len(vnic->TxData); + txDmaData = txPacket->data + txPacketOffset; + txState = txCopy; + + dmaRead(txDmaAddr, txDmaLen, &txDmaEvent, txDmaData); + break; + + case txCopy: + DPRINTF(EthernetSM, "transmit machine still copying\n"); + goto exit; + + case txCopyDone: + vnic->TxDone = txDmaLen | Regs::TxDone_Complete; + txPacket->length += txDmaLen; + if ((vnic->TxData & Regs::TxData_More)) { + txPacketOffset += txDmaLen; + txState = txIdle; + devIntrPost(Regs::Intr_TxDMA); + break; + } + + assert(txPacket->length <= txFifo.avail()); + if ((vnic->TxData & Regs::TxData_Checksum)) { + IpPtr ip(txPacket); + if (ip) { + TcpPtr tcp(ip); + if (tcp) { + tcp->sum(0); + tcp->sum(cksum(tcp)); + txTcpChecksums++; + } + + UdpPtr udp(ip); + if (udp) { + udp->sum(0); + udp->sum(cksum(udp)); + txUdpChecksums++; + } + + ip->sum(0); + ip->sum(cksum(ip)); + txIpChecksums++; + } + } + + txFifo.push(txPacket); + if (txFifo.avail() < regs.TxMaxCopy) { + devIntrPost(Regs::Intr_TxFull); + txFull = true; + } + txPacket = 0; + transmit(); + txList.pop_front(); + txState = txList.empty() ? txIdle : txFifoBlock; + devIntrPost(Regs::Intr_TxDMA); + break; + + default: + panic("Invalid txState!"); + } + + DPRINTF(EthernetSM, "entering next txState=%s\n", + TxStateStrings[txState]); + + goto next; + + exit: + /** + * @todo do we want to schedule a future kick? + */ + DPRINTF(EthernetSM, "tx state machine exited txState=%s\n", + TxStateStrings[txState]); +} + +void +Device::transferDone() +{ + if (txFifo.empty()) { + DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n"); + return; + } + + DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n"); + + if (txEvent.scheduled()) + txEvent.reschedule(curTick + cycles(1)); + else + txEvent.schedule(curTick + cycles(1)); +} + +bool +Device::rxFilter(const EthPacketPtr &packet) +{ + if (!Regs::get_Config_Filter(regs.Config)) + return false; + + panic("receive filter not implemented\n"); + bool drop = true; + +#if 0 + string type; + + EthHdr *eth = packet->eth(); + if (eth->unicast()) { + // If we're accepting all unicast addresses + if (acceptUnicast) + drop = false; + + // If we make a perfect match + if (acceptPerfect && params->eaddr == eth.dst()) + drop = false; + + if (acceptArp && eth->type() == ETH_TYPE_ARP) + drop = false; + + } else if (eth->broadcast()) { + // if we're accepting broadcasts + if (acceptBroadcast) + drop = false; + + } else if (eth->multicast()) { + // if we're accepting all multicasts + if (acceptMulticast) + drop = false; + + } + + if (drop) { + DPRINTF(Ethernet, "rxFilter drop\n"); + DDUMP(EthernetData, packet->data, packet->length); + } +#endif + return drop; +} + +bool +Device::recvPacket(EthPacketPtr packet) +{ + rxBytes += packet->length; + rxPackets++; + + DPRINTF(Ethernet, "Receiving packet from wire, rxFifo Available is %d\n", + rxFifo.avail()); + + if (!rxEnable) { + DPRINTF(Ethernet, "receive disabled...packet dropped\n"); + return true; + } + + if (rxFilter(packet)) { + DPRINTF(Ethernet, "packet filtered...dropped\n"); + return true; + } + + if (rxFifo.size() >= regs.RxFifoMark) + devIntrPost(Regs::Intr_RxHigh); + + if (!rxFifo.push(packet)) { + DPRINTF(Ethernet, + "packet will not fit in receive buffer...packet dropped\n"); + return false; + } + + // If we were at the last element, back up one ot go to the new + // last element of the list. + if (rxFifoPtr == rxFifo.end()) + --rxFifoPtr; + + devIntrPost(Regs::Intr_RxPacket); + rxKick(); + return true; +} + +//===================================================================== +// +// +void +Base::serialize(std::ostream &os) +{ + // Serialize the PciDev base class + PciDev::serialize(os); + + SERIALIZE_SCALAR(rxEnable); + SERIALIZE_SCALAR(txEnable); + SERIALIZE_SCALAR(cpuIntrEnable); + + /* + * Keep track of pending interrupt status. + */ + SERIALIZE_SCALAR(intrTick); + SERIALIZE_SCALAR(cpuPendingIntr); + Tick intrEventTick = 0; + if (intrEvent) + intrEventTick = intrEvent->when(); + SERIALIZE_SCALAR(intrEventTick); +} + +void +Base::unserialize(Checkpoint *cp, const std::string §ion) +{ + // Unserialize the PciDev base class + PciDev::unserialize(cp, section); + + UNSERIALIZE_SCALAR(rxEnable); + UNSERIALIZE_SCALAR(txEnable); + UNSERIALIZE_SCALAR(cpuIntrEnable); + + /* + * Keep track of pending interrupt status. + */ + UNSERIALIZE_SCALAR(intrTick); + UNSERIALIZE_SCALAR(cpuPendingIntr); + Tick intrEventTick; + UNSERIALIZE_SCALAR(intrEventTick); + if (intrEventTick) { + intrEvent = new IntrEvent(this, true); + intrEvent->schedule(intrEventTick); + } +} + +void +Device::serialize(std::ostream &os) +{ + int count; + + // Serialize the PciDev base class + Base::serialize(os); + + if (rxState == rxCopy) + panic("can't serialize with an in flight dma request rxState=%s", + RxStateStrings[rxState]); + + if (txState == txCopy) + panic("can't serialize with an in flight dma request txState=%s", + TxStateStrings[txState]); + + /* + * Serialize the device registers + */ + SERIALIZE_SCALAR(regs.Config); + SERIALIZE_SCALAR(regs.IntrStatus); + SERIALIZE_SCALAR(regs.IntrMask); + SERIALIZE_SCALAR(regs.RxMaxCopy); + SERIALIZE_SCALAR(regs.TxMaxCopy); + SERIALIZE_SCALAR(regs.RxMaxIntr); + SERIALIZE_SCALAR(regs.VirtualCount); + SERIALIZE_SCALAR(regs.RxData); + SERIALIZE_SCALAR(regs.RxDone); + SERIALIZE_SCALAR(regs.TxData); + SERIALIZE_SCALAR(regs.TxDone); + + /* + * Serialize the virtual nic state + */ + int virtualRegsSize = virtualRegs.size(); + SERIALIZE_SCALAR(virtualRegsSize); + for (int i = 0; i < virtualRegsSize; ++i) { + VirtualReg *vnic = &virtualRegs[i]; + + std::string reg = csprintf("vnic%d", i); + paramOut(os, reg + ".RxData", vnic->RxData); + paramOut(os, reg + ".RxDone", vnic->RxDone); + paramOut(os, reg + ".TxData", vnic->TxData); + paramOut(os, reg + ".TxDone", vnic->TxDone); + + bool rxPacketExists = vnic->rxPacket != rxFifo.end(); + paramOut(os, reg + ".rxPacketExists", rxPacketExists); + if (rxPacketExists) { + int rxPacket = 0; + PacketFifo::iterator i = rxFifo.begin(); + while (i != vnic->rxPacket) { + assert(i != rxFifo.end()); + ++i; + ++rxPacket; + } + + paramOut(os, reg + ".rxPacket", rxPacket); + paramOut(os, reg + ".rxPacketOffset", vnic->rxPacketOffset); + paramOut(os, reg + ".rxPacketBytes", vnic->rxPacketBytes); + } + paramOut(os, reg + ".rxDoneData", vnic->rxDoneData); + } + + int rxFifoPtr = rxFifo.countPacketsBefore(this->rxFifoPtr); + SERIALIZE_SCALAR(rxFifoPtr); + + SERIALIZE_SCALAR(rxActive); + + VirtualList::iterator i, end; + for (count = 0, i = rxList.begin(), end = rxList.end(); i != end; ++i) + paramOut(os, csprintf("rxList%d", count++), *i); + int rxListSize = count; + SERIALIZE_SCALAR(rxListSize); + + for (count = 0, i = rxBusy.begin(), end = rxBusy.end(); i != end; ++i) + paramOut(os, csprintf("rxBusy%d", count++), *i); + int rxBusySize = count; + SERIALIZE_SCALAR(rxBusySize); + + for (count = 0, i = txList.begin(), end = txList.end(); i != end; ++i) + paramOut(os, csprintf("txList%d", count++), *i); + int txListSize = count; + SERIALIZE_SCALAR(txListSize); + + /* + * Serialize rx state machine + */ + int rxState = this->rxState; + SERIALIZE_SCALAR(rxState); + SERIALIZE_SCALAR(rxEmpty); + SERIALIZE_SCALAR(rxLow); + rxFifo.serialize("rxFifo", os); + + /* + * Serialize tx state machine + */ + int txState = this->txState; + SERIALIZE_SCALAR(txState); + SERIALIZE_SCALAR(txFull); + txFifo.serialize("txFifo", os); + bool txPacketExists = txPacket; + SERIALIZE_SCALAR(txPacketExists); + if (txPacketExists) { + txPacket->serialize("txPacket", os); + SERIALIZE_SCALAR(txPacketOffset); + SERIALIZE_SCALAR(txPacketBytes); + } + + /* + * If there's a pending transmit, store the time so we can + * reschedule it later + */ + Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0; + SERIALIZE_SCALAR(transmitTick); +} + +void +Device::unserialize(Checkpoint *cp, const std::string §ion) +{ + // Unserialize the PciDev base class + Base::unserialize(cp, section); + + /* + * Unserialize the device registers + */ + UNSERIALIZE_SCALAR(regs.Config); + UNSERIALIZE_SCALAR(regs.IntrStatus); + UNSERIALIZE_SCALAR(regs.IntrMask); + UNSERIALIZE_SCALAR(regs.RxMaxCopy); + UNSERIALIZE_SCALAR(regs.TxMaxCopy); + UNSERIALIZE_SCALAR(regs.RxMaxIntr); + UNSERIALIZE_SCALAR(regs.VirtualCount); + UNSERIALIZE_SCALAR(regs.RxData); + UNSERIALIZE_SCALAR(regs.RxDone); + UNSERIALIZE_SCALAR(regs.TxData); + UNSERIALIZE_SCALAR(regs.TxDone); + + UNSERIALIZE_SCALAR(rxActive); + + int rxListSize; + UNSERIALIZE_SCALAR(rxListSize); + rxList.clear(); + for (int i = 0; i < rxListSize; ++i) { + int value; + paramIn(cp, section, csprintf("rxList%d", i), value); + rxList.push_back(value); + } + + int rxBusySize; + UNSERIALIZE_SCALAR(rxBusySize); + rxBusy.clear(); + for (int i = 0; i < rxBusySize; ++i) { + int value; + paramIn(cp, section, csprintf("rxBusy%d", i), value); + rxBusy.push_back(value); + } + + int txListSize; + UNSERIALIZE_SCALAR(txListSize); + txList.clear(); + for (int i = 0; i < txListSize; ++i) { + int value; + paramIn(cp, section, csprintf("txList%d", i), value); + txList.push_back(value); + } + + /* + * Unserialize rx state machine + */ + int rxState; + UNSERIALIZE_SCALAR(rxState); + UNSERIALIZE_SCALAR(rxEmpty); + UNSERIALIZE_SCALAR(rxLow); + this->rxState = (RxState) rxState; + rxFifo.unserialize("rxFifo", cp, section); + + int rxFifoPtr; + UNSERIALIZE_SCALAR(rxFifoPtr); + this->rxFifoPtr = rxFifo.begin(); + for (int i = 0; i < rxFifoPtr; ++i) + ++this->rxFifoPtr; + + /* + * Unserialize tx state machine + */ + int txState; + UNSERIALIZE_SCALAR(txState); + UNSERIALIZE_SCALAR(txFull); + this->txState = (TxState) txState; + txFifo.unserialize("txFifo", cp, section); + bool txPacketExists; + UNSERIALIZE_SCALAR(txPacketExists); + txPacket = 0; + if (txPacketExists) { + txPacket = new EthPacketData(16384); + txPacket->unserialize("txPacket", cp, section); + UNSERIALIZE_SCALAR(txPacketOffset); + UNSERIALIZE_SCALAR(txPacketBytes); + } + + /* + * unserialize the virtual nic registers/state + * + * this must be done after the unserialization of the rxFifo + * because the packet iterators depend on the fifo being populated + */ + int virtualRegsSize; + UNSERIALIZE_SCALAR(virtualRegsSize); + virtualRegs.clear(); + virtualRegs.resize(virtualRegsSize); + for (int i = 0; i < virtualRegsSize; ++i) { + VirtualReg *vnic = &virtualRegs[i]; + std::string reg = csprintf("vnic%d", i); + + paramIn(cp, section, reg + ".RxData", vnic->RxData); + paramIn(cp, section, reg + ".RxDone", vnic->RxDone); + paramIn(cp, section, reg + ".TxData", vnic->TxData); + paramIn(cp, section, reg + ".TxDone", vnic->TxDone); + + vnic->rxUnique = rxUnique++; + vnic->txUnique = txUnique++; + + bool rxPacketExists; + paramIn(cp, section, reg + ".rxPacketExists", rxPacketExists); + if (rxPacketExists) { + int rxPacket; + paramIn(cp, section, reg + ".rxPacket", rxPacket); + vnic->rxPacket = rxFifo.begin(); + while (rxPacket--) + ++vnic->rxPacket; + + paramIn(cp, section, reg + ".rxPacketOffset", + vnic->rxPacketOffset); + paramIn(cp, section, reg + ".rxPacketBytes", vnic->rxPacketBytes); + } else { + vnic->rxPacket = rxFifo.end(); + } + paramIn(cp, section, reg + ".rxDoneData", vnic->rxDoneData); + } + + /* + * If there's a pending transmit, reschedule it now + */ + Tick transmitTick; + UNSERIALIZE_SCALAR(transmitTick); + if (transmitTick) + txEvent.schedule(curTick + transmitTick); + + pioPort->sendStatusChange(Port::RangeChange); + +} + + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(Interface) + + SimObjectParam<EtherInt *> peer; + SimObjectParam<Device *> device; + +END_DECLARE_SIM_OBJECT_PARAMS(Interface) + +BEGIN_INIT_SIM_OBJECT_PARAMS(Interface) + + INIT_PARAM_DFLT(peer, "peer interface", NULL), + INIT_PARAM(device, "Ethernet device of this interface") + +END_INIT_SIM_OBJECT_PARAMS(Interface) + +CREATE_SIM_OBJECT(Interface) +{ + Interface *dev_int = new Interface(getInstanceName(), device); + + EtherInt *p = (EtherInt *)peer; + if (p) { + dev_int->setPeer(p); + p->setPeer(dev_int); + } + + return dev_int; +} + +REGISTER_SIM_OBJECT("SinicInt", Interface) + + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(Device) + + + SimObjectParam<System *> system; + SimObjectParam<Platform *> platform; + SimObjectParam<PciConfigAll *> configspace; + SimObjectParam<PciConfigData *> configdata; + Param<uint32_t> pci_bus; + Param<uint32_t> pci_dev; + Param<uint32_t> pci_func; + Param<Tick> pio_latency; + Param<Tick> intr_delay; + + Param<Tick> clock; + Param<Tick> dma_read_delay; + Param<Tick> dma_read_factor; + Param<Tick> dma_write_delay; + Param<Tick> dma_write_factor; + + Param<Tick> rx_delay; + Param<Tick> tx_delay; + Param<uint32_t> rx_max_copy; + Param<uint32_t> tx_max_copy; + Param<uint32_t> rx_max_intr; + Param<uint32_t> rx_fifo_size; + Param<uint32_t> tx_fifo_size; + Param<uint32_t> rx_fifo_threshold; + Param<uint32_t> rx_fifo_low_mark; + Param<uint32_t> tx_fifo_high_mark; + Param<uint32_t> tx_fifo_threshold; + + Param<bool> rx_filter; + Param<std::string> hardware_address; + Param<bool> rx_thread; + Param<bool> tx_thread; + Param<bool> rss; + Param<uint32_t> virtual_count; + Param<bool> zero_copy; + Param<bool> delay_copy; + Param<bool> virtual_addr; + +END_DECLARE_SIM_OBJECT_PARAMS(Device) + +BEGIN_INIT_SIM_OBJECT_PARAMS(Device) + + + INIT_PARAM(system, "System pointer"), + INIT_PARAM(platform, "Platform pointer"), + INIT_PARAM(configspace, "PCI Configspace"), + INIT_PARAM(configdata, "PCI Config data"), + INIT_PARAM(pci_bus, "PCI bus ID"), + INIT_PARAM(pci_dev, "PCI device number"), + INIT_PARAM(pci_func, "PCI function code"), + INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1), + INIT_PARAM(intr_delay, "Interrupt Delay"), + INIT_PARAM(clock, "State machine cycle time"), + + INIT_PARAM(dma_read_delay, "fixed delay for dma reads"), + INIT_PARAM(dma_read_factor, "multiplier for dma reads"), + INIT_PARAM(dma_write_delay, "fixed delay for dma writes"), + INIT_PARAM(dma_write_factor, "multiplier for dma writes"), + + INIT_PARAM(rx_delay, "Receive Delay"), + INIT_PARAM(tx_delay, "Transmit Delay"), + INIT_PARAM(rx_max_copy, "rx max copy"), + INIT_PARAM(tx_max_copy, "rx max copy"), + INIT_PARAM(rx_max_intr, "rx max intr"), + INIT_PARAM(rx_fifo_size, "max size in bytes of rxFifo"), + INIT_PARAM(tx_fifo_size, "max size in bytes of txFifo"), + INIT_PARAM(rx_fifo_threshold, "max size in bytes of rxFifo"), + INIT_PARAM(rx_fifo_low_mark, "max size in bytes of rxFifo"), + INIT_PARAM(tx_fifo_high_mark, "max size in bytes of txFifo"), + INIT_PARAM(tx_fifo_threshold, "max size in bytes of txFifo"), + + INIT_PARAM(rx_filter, "Enable Receive Filter"), + INIT_PARAM(hardware_address, "Ethernet Hardware Address"), + INIT_PARAM(rx_thread, ""), + INIT_PARAM(tx_thread, ""), + INIT_PARAM(rss, ""), + INIT_PARAM(virtual_count, ""), + INIT_PARAM(zero_copy, ""), + INIT_PARAM(delay_copy, ""), + INIT_PARAM(virtual_addr, "") + +END_INIT_SIM_OBJECT_PARAMS(Device) + + +CREATE_SIM_OBJECT(Device) +{ + Device::Params *params = new Device::Params; + params->name = getInstanceName(); + params->platform = platform; + params->system = system; + params->configSpace = configspace; + params->configData = configdata; + params->busNum = pci_bus; + params->deviceNum = pci_dev; + params->functionNum = pci_func; + params->pio_delay = pio_latency; + params->intr_delay = intr_delay; + params->clock = clock; + + params->dma_read_delay = dma_read_delay; + params->dma_read_factor = dma_read_factor; + params->dma_write_delay = dma_write_delay; + params->dma_write_factor = dma_write_factor; + + params->tx_delay = tx_delay; + params->rx_delay = rx_delay; + params->rx_max_copy = rx_max_copy; + params->tx_max_copy = tx_max_copy; + params->rx_max_intr = rx_max_intr; + params->rx_fifo_size = rx_fifo_size; + params->tx_fifo_size = tx_fifo_size; + params->rx_fifo_threshold = rx_fifo_threshold; + params->rx_fifo_low_mark = rx_fifo_low_mark; + params->tx_fifo_high_mark = tx_fifo_high_mark; + params->tx_fifo_threshold = tx_fifo_threshold; + + params->rx_filter = rx_filter; + params->eaddr = hardware_address; + params->rx_thread = rx_thread; + params->tx_thread = tx_thread; + params->rss = rss; + params->virtual_count = virtual_count; + params->zero_copy = zero_copy; + params->delay_copy = delay_copy; + params->virtual_addr = virtual_addr; + + return new Device(params); +} + +REGISTER_SIM_OBJECT("Sinic", Device) + +/* namespace Sinic */ } diff --git a/src/dev/sinic.hh b/src/dev/sinic.hh new file mode 100644 index 000000000..1bb4c77e0 --- /dev/null +++ b/src/dev/sinic.hh @@ -0,0 +1,371 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __DEV_SINIC_HH__ +#define __DEV_SINIC_HH__ + +#include "base/inet.hh" +#include "base/statistics.hh" +#include "dev/etherint.hh" +#include "dev/etherpkt.hh" +#include "dev/io_device.hh" +#include "dev/pcidev.hh" +#include "dev/pktfifo.hh" +#include "dev/sinicreg.hh" +#include "sim/eventq.hh" + +namespace Sinic { + +class Interface; +class Base : public PciDev +{ + protected: + bool rxEnable; + bool txEnable; + Tick clock; + inline Tick cycles(int numCycles) const { return numCycles * clock; } + + protected: + Tick intrDelay; + Tick intrTick; + bool cpuIntrEnable; + bool cpuPendingIntr; + void cpuIntrPost(Tick when); + void cpuInterrupt(); + void cpuIntrClear(); + + typedef EventWrapper<Base, &Base::cpuInterrupt> IntrEvent; + friend void IntrEvent::process(); + IntrEvent *intrEvent; + Interface *interface; + + bool cpuIntrPending() const; + void cpuIntrAck() { cpuIntrClear(); } + +/** + * Serialization stuff + */ + public: + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); + +/** + * Construction/Destruction/Parameters + */ + public: + struct Params : public PciDev::Params + { + Tick clock; + Tick intr_delay; + }; + + Base(Params *p); +}; + +class Device : public Base +{ + protected: + /** Receive State Machine States */ + enum RxState { + rxIdle, + rxFifoBlock, + rxBeginCopy, + rxCopy, + rxCopyDone + }; + + /** Transmit State Machine states */ + enum TxState { + txIdle, + txFifoBlock, + txBeginCopy, + txCopy, + txCopyDone + }; + + /** device register file */ + struct { + uint32_t Config; // 0x00 + uint32_t Command; // 0x04 + uint32_t IntrStatus; // 0x08 + uint32_t IntrMask; // 0x0c + uint32_t RxMaxCopy; // 0x10 + uint32_t TxMaxCopy; // 0x14 + uint32_t RxMaxIntr; // 0x18 + uint32_t VirtualCount; // 0x1c + uint32_t RxFifoSize; // 0x20 + uint32_t TxFifoSize; // 0x24 + uint32_t RxFifoMark; // 0x28 + uint32_t TxFifoMark; // 0x2c + uint64_t RxData; // 0x30 + uint64_t RxDone; // 0x38 + uint64_t RxWait; // 0x40 + uint64_t TxData; // 0x48 + uint64_t TxDone; // 0x50 + uint64_t TxWait; // 0x58 + uint64_t HwAddr; // 0x60 + } regs; + + struct VirtualReg { + uint64_t RxData; + uint64_t RxDone; + uint64_t TxData; + uint64_t TxDone; + + PacketFifo::iterator rxPacket; + int rxPacketOffset; + int rxPacketBytes; + uint64_t rxDoneData; + + Counter rxUnique; + Counter txUnique; + + VirtualReg() + : RxData(0), RxDone(0), TxData(0), TxDone(0), + rxPacketOffset(0), rxPacketBytes(0), rxDoneData(0) + { } + }; + typedef std::vector<VirtualReg> VirtualRegs; + typedef std::list<int> VirtualList; + Counter rxUnique; + Counter txUnique; + VirtualRegs virtualRegs; + VirtualList rxList; + VirtualList rxBusy; + int rxActive; + VirtualList txList; + + uint8_t ®Data8(Addr daddr) { return *((uint8_t *)®s + daddr); } + uint32_t ®Data32(Addr daddr) { return *(uint32_t *)®Data8(daddr); } + uint64_t ®Data64(Addr daddr) { return *(uint64_t *)®Data8(daddr); } + + protected: + RxState rxState; + PacketFifo rxFifo; + PacketFifo::iterator rxFifoPtr; + bool rxEmpty; + bool rxLow; + Addr rxDmaAddr; + uint8_t *rxDmaData; + int rxDmaLen; + + TxState txState; + PacketFifo txFifo; + bool txFull; + EthPacketPtr txPacket; + int txPacketOffset; + int txPacketBytes; + Addr txDmaAddr; + uint8_t *txDmaData; + int txDmaLen; + + protected: + void reset(); + + void rxKick(); + Tick rxKickTick; + typedef EventWrapper<Device, &Device::rxKick> RxKickEvent; + friend void RxKickEvent::process(); + + void txKick(); + Tick txKickTick; + typedef EventWrapper<Device, &Device::txKick> TxKickEvent; + friend void TxKickEvent::process(); + + /** + * Retransmit event + */ + void transmit(); + void txEventTransmit() + { + transmit(); + if (txState == txFifoBlock) + txKick(); + } + typedef EventWrapper<Device, &Device::txEventTransmit> TxEvent; + friend void TxEvent::process(); + TxEvent txEvent; + + void txDump() const; + void rxDump() const; + + /** + * receive address filter + */ + bool rxFilter(const EthPacketPtr &packet); + +/** + * device configuration + */ + void changeConfig(uint32_t newconfig); + void command(uint32_t command); + +/** + * device ethernet interface + */ + public: + bool recvPacket(EthPacketPtr packet); + void transferDone(); + void setInterface(Interface *i) { assert(!interface); interface = i; } + +/** + * DMA parameters + */ + protected: + void rxDmaDone(); + friend class EventWrapper<Device, &Device::rxDmaDone>; + EventWrapper<Device, &Device::rxDmaDone> rxDmaEvent; + + void txDmaDone(); + friend class EventWrapper<Device, &Device::txDmaDone>; + EventWrapper<Device, &Device::txDmaDone> txDmaEvent; + + Tick dmaReadDelay; + Tick dmaReadFactor; + Tick dmaWriteDelay; + Tick dmaWriteFactor; + +/** + * Interrupt management + */ + protected: + void devIntrPost(uint32_t interrupts); + void devIntrClear(uint32_t interrupts = Regs::Intr_All); + void devIntrChangeMask(uint32_t newmask); + +/** + * Memory Interface + */ + public: + virtual Tick read(Packet *pkt); + virtual Tick write(Packet *pkt); + + void prepareIO(int cpu, int index); + void prepareRead(int cpu, int index); + void prepareWrite(int cpu, int index); + // Fault iprRead(Addr daddr, int cpu, uint64_t &result); + +/** + * Statistics + */ + private: + Stats::Scalar<> rxBytes; + Stats::Formula rxBandwidth; + Stats::Scalar<> rxPackets; + Stats::Formula rxPacketRate; + Stats::Scalar<> rxIpPackets; + Stats::Scalar<> rxTcpPackets; + Stats::Scalar<> rxUdpPackets; + Stats::Scalar<> rxIpChecksums; + Stats::Scalar<> rxTcpChecksums; + Stats::Scalar<> rxUdpChecksums; + + Stats::Scalar<> txBytes; + Stats::Formula txBandwidth; + Stats::Formula totBandwidth; + Stats::Formula totPackets; + Stats::Formula totBytes; + Stats::Formula totPacketRate; + Stats::Scalar<> txPackets; + Stats::Formula txPacketRate; + Stats::Scalar<> txIpPackets; + Stats::Scalar<> txTcpPackets; + Stats::Scalar<> txUdpPackets; + Stats::Scalar<> txIpChecksums; + Stats::Scalar<> txTcpChecksums; + Stats::Scalar<> txUdpChecksums; + + public: + virtual void regStats(); + +/** + * Serialization stuff + */ + public: + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); + +/** + * Construction/Destruction/Parameters + */ + public: + struct Params : public Base::Params + { + Tick tx_delay; + Tick rx_delay; + bool rx_filter; + Net::EthAddr eaddr; + uint32_t rx_max_copy; + uint32_t tx_max_copy; + uint32_t rx_max_intr; + uint32_t rx_fifo_size; + uint32_t tx_fifo_size; + uint32_t rx_fifo_threshold; + uint32_t rx_fifo_low_mark; + uint32_t tx_fifo_high_mark; + uint32_t tx_fifo_threshold; + Tick dma_read_delay; + Tick dma_read_factor; + Tick dma_write_delay; + Tick dma_write_factor; + bool rx_thread; + bool tx_thread; + bool rss; + uint32_t virtual_count; + bool zero_copy; + bool delay_copy; + bool virtual_addr; + }; + + protected: + const Params *params() const { return (const Params *)_params; } + + public: + Device(Params *params); + ~Device(); +}; + +/* + * Ethernet Interface for an Ethernet Device + */ +class Interface : public EtherInt +{ + private: + Device *dev; + + public: + Interface(const std::string &name, Device *d) + : EtherInt(name), dev(d) { dev->setInterface(this); } + + virtual bool recvPacket(EthPacketPtr pkt) { return dev->recvPacket(pkt); } + virtual void sendDone() { dev->transferDone(); } +}; + +/* namespace Sinic */ } + +#endif // __DEV_SINIC_HH__ diff --git a/dev/sinicreg.hh b/src/dev/sinicreg.hh index d41eb5b16..d41eb5b16 100644 --- a/dev/sinicreg.hh +++ b/src/dev/sinicreg.hh diff --git a/src/dev/tsunami.cc b/src/dev/tsunami.cc new file mode 100644 index 000000000..ed011531d --- /dev/null +++ b/src/dev/tsunami.cc @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file + * Implementation of Tsunami platform. + */ + +#include <deque> +#include <string> +#include <vector> + +#include "cpu/intr_control.hh" +#include "dev/simconsole.hh" +#include "dev/tsunami_cchip.hh" +#include "dev/tsunami_pchip.hh" +#include "dev/tsunami_io.hh" +#include "dev/tsunami.hh" +#include "sim/builder.hh" +#include "sim/system.hh" + +using namespace std; +//Should this be AlphaISA? +using namespace TheISA; + +Tsunami::Tsunami(const string &name, System *s, IntrControl *ic) + : Platform(name, ic), system(s) +{ + // set the back pointer from the system to myself + system->platform = this; + + for (int i = 0; i < Tsunami::Max_CPUs; i++) + intr_sum_type[i] = 0; +} + +Tick +Tsunami::intrFrequency() +{ + return io->frequency(); +} + +void +Tsunami::postConsoleInt() +{ + io->postPIC(0x10); +} + +void +Tsunami::clearConsoleInt() +{ + io->clearPIC(0x10); +} + +void +Tsunami::postPciInt(int line) +{ + cchip->postDRIR(line); +} + +void +Tsunami::clearPciInt(int line) +{ + cchip->clearDRIR(line); +} + +Addr +Tsunami::pciToDma(Addr pciAddr) const +{ + return pchip->translatePciToDma(pciAddr); +} + +void +Tsunami::serialize(std::ostream &os) +{ + SERIALIZE_ARRAY(intr_sum_type, Tsunami::Max_CPUs); +} + +void +Tsunami::unserialize(Checkpoint *cp, const std::string §ion) +{ + UNSERIALIZE_ARRAY(intr_sum_type, Tsunami::Max_CPUs); +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(Tsunami) + + SimObjectParam<System *> system; + SimObjectParam<IntrControl *> intrctrl; + +END_DECLARE_SIM_OBJECT_PARAMS(Tsunami) + +BEGIN_INIT_SIM_OBJECT_PARAMS(Tsunami) + + INIT_PARAM(system, "system"), + INIT_PARAM(intrctrl, "interrupt controller") + +END_INIT_SIM_OBJECT_PARAMS(Tsunami) + +CREATE_SIM_OBJECT(Tsunami) +{ + return new Tsunami(getInstanceName(), system, intrctrl); +} + +REGISTER_SIM_OBJECT("Tsunami", Tsunami) diff --git a/src/dev/tsunami.hh b/src/dev/tsunami.hh new file mode 100644 index 000000000..668c82674 --- /dev/null +++ b/src/dev/tsunami.hh @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * Declaration of top level class for the Tsunami chipset. This class just + * retains pointers to all its children so the children can communicate. + */ + +#ifndef __DEV_TSUNAMI_HH__ +#define __DEV_TSUNAMI_HH__ + +#include "dev/platform.hh" + +class IdeController; +class TsunamiCChip; +class TsunamiPChip; +class TsunamiIO; +class System; + +/** + * Top level class for Tsunami Chipset emulation. + * This structure just contains pointers to all the + * children so the children can commnicate to do the + * read work + */ + +class Tsunami : public Platform +{ + public: + /** Max number of CPUs in a Tsunami */ + static const int Max_CPUs = 64; + + /** Pointer to the system */ + System *system; + + /** Pointer to the TsunamiIO device which has the RTC */ + TsunamiIO *io; + + /** Pointer to the Tsunami CChip. + * The chip contains some configuration information and + * all the interrupt mask and status registers + */ + TsunamiCChip *cchip; + + /** Pointer to the Tsunami PChip. + * The pchip is the interface to the PCI bus, in our case + * it does not have to do much. + */ + TsunamiPChip *pchip; + + int intr_sum_type[Tsunami::Max_CPUs]; + int ipi_pending[Tsunami::Max_CPUs]; + + public: + /** + * Constructor for the Tsunami Class. + * @param name name of the object + * @param intrctrl pointer to the interrupt controller + */ + Tsunami(const std::string &name, System *s, IntrControl *intctrl); + + /** + * Return the interrupting frequency to AlphaAccess + * @return frequency of RTC interrupts + */ + virtual Tick intrFrequency(); + + /** + * Cause the cpu to post a serial interrupt to the CPU. + */ + virtual void postConsoleInt(); + + /** + * Clear a posted CPU interrupt (id=55) + */ + virtual void clearConsoleInt(); + + /** + * Cause the chipset to post a cpi interrupt to the CPU. + */ + virtual void postPciInt(int line); + + /** + * Clear a posted PCI->CPU interrupt + */ + virtual void clearPciInt(int line); + + virtual Addr pciToDma(Addr pciAddr) const; + + /** + * Serialize this object to the given output stream. + * @param os The stream to serialize to. + */ + virtual void serialize(std::ostream &os); + + /** + * Reconstruct the state of this object from a checkpoint. + * @param cp The checkpoint use. + * @param section The section name of this object + */ + virtual void unserialize(Checkpoint *cp, const std::string §ion); +}; + +#endif // __DEV_TSUNAMI_HH__ diff --git a/src/dev/tsunami_cchip.cc b/src/dev/tsunami_cchip.cc new file mode 100644 index 000000000..146321b9f --- /dev/null +++ b/src/dev/tsunami_cchip.cc @@ -0,0 +1,554 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file + * Emulation of the Tsunami CChip CSRs + */ + +#include <deque> +#include <string> +#include <vector> + +#include "arch/alpha/ev5.hh" +#include "base/trace.hh" +#include "dev/tsunami_cchip.hh" +#include "dev/tsunamireg.h" +#include "dev/tsunami.hh" +#include "mem/port.hh" +#include "cpu/exec_context.hh" +#include "cpu/intr_control.hh" +#include "sim/builder.hh" +#include "sim/system.hh" + +using namespace std; +//Should this be AlphaISA? +using namespace TheISA; + +TsunamiCChip::TsunamiCChip(Params *p) + : BasicPioDevice(p), tsunami(p->tsunami) +{ + pioSize = 0xfffffff; + + drir = 0; + ipint = 0; + itint = 0; + + for (int x = 0; x < Tsunami::Max_CPUs; x++) + { + dim[x] = 0; + dir[x] = 0; + } + + //Put back pointer in tsunami + tsunami->cchip = this; +} + +Tick +TsunamiCChip::read(Packet *pkt) +{ + DPRINTF(Tsunami, "read va=%#x size=%d\n", pkt->getAddr(), pkt->getSize()); + + assert(pkt->result == Packet::Unknown); + assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); + + pkt->time += pioDelay; + Addr regnum = (pkt->getAddr() - pioAddr) >> 6; + Addr daddr = (pkt->getAddr() - pioAddr); + + pkt->allocate(); + switch (pkt->getSize()) { + + case sizeof(uint64_t): + if (daddr & TSDEV_CC_BDIMS) + { + pkt->set(dim[(daddr >> 4) & 0x3F]); + break; + } + + if (daddr & TSDEV_CC_BDIRS) + { + pkt->set(dir[(daddr >> 4) & 0x3F]); + break; + } + + switch(regnum) { + case TSDEV_CC_CSR: + pkt->set(0x0); + break; + case TSDEV_CC_MTR: + panic("TSDEV_CC_MTR not implemeted\n"); + break; + case TSDEV_CC_MISC: + pkt->set((ipint << 8) & 0xF | (itint << 4) & 0xF | + (pkt->req->getCpuNum() & 0x3)); + break; + case TSDEV_CC_AAR0: + case TSDEV_CC_AAR1: + case TSDEV_CC_AAR2: + case TSDEV_CC_AAR3: + pkt->set(0); + break; + case TSDEV_CC_DIM0: + pkt->set(dim[0]); + break; + case TSDEV_CC_DIM1: + pkt->set(dim[1]); + break; + case TSDEV_CC_DIM2: + pkt->set(dim[2]); + break; + case TSDEV_CC_DIM3: + pkt->set(dim[3]); + break; + case TSDEV_CC_DIR0: + pkt->set(dir[0]); + break; + case TSDEV_CC_DIR1: + pkt->set(dir[1]); + break; + case TSDEV_CC_DIR2: + pkt->set(dir[2]); + break; + case TSDEV_CC_DIR3: + pkt->set(dir[3]); + break; + case TSDEV_CC_DRIR: + pkt->set(drir); + break; + case TSDEV_CC_PRBEN: + panic("TSDEV_CC_PRBEN not implemented\n"); + break; + case TSDEV_CC_IIC0: + case TSDEV_CC_IIC1: + case TSDEV_CC_IIC2: + case TSDEV_CC_IIC3: + panic("TSDEV_CC_IICx not implemented\n"); + break; + case TSDEV_CC_MPR0: + case TSDEV_CC_MPR1: + case TSDEV_CC_MPR2: + case TSDEV_CC_MPR3: + panic("TSDEV_CC_MPRx not implemented\n"); + break; + case TSDEV_CC_IPIR: + pkt->set(ipint); + break; + case TSDEV_CC_ITIR: + pkt->set(itint); + break; + default: + panic("default in cchip read reached, accessing 0x%x\n"); + } // uint64_t + + break; + case sizeof(uint32_t): + case sizeof(uint16_t): + case sizeof(uint8_t): + default: + panic("invalid access size(?) for tsunami register!\n"); + } + DPRINTF(Tsunami, "Tsunami CChip: read regnum=%#x size=%d data=%lld\n", + regnum, pkt->getSize(), pkt->get<uint64_t>()); + + pkt->result = Packet::Success; + return pioDelay; +} + +Tick +TsunamiCChip::write(Packet *pkt) +{ + pkt->time += pioDelay; + + + assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); + Addr daddr = pkt->getAddr() - pioAddr; + Addr regnum = (pkt->getAddr() - pioAddr) >> 6 ; + + + assert(pkt->getSize() == sizeof(uint64_t)); + + DPRINTF(Tsunami, "write - addr=%#x value=%#x\n", pkt->getAddr(), pkt->get<uint64_t>()); + + bool supportedWrite = false; + + + if (daddr & TSDEV_CC_BDIMS) + { + int number = (daddr >> 4) & 0x3F; + + uint64_t bitvector; + uint64_t olddim; + uint64_t olddir; + + olddim = dim[number]; + olddir = dir[number]; + dim[number] = pkt->get<uint64_t>(); + dir[number] = dim[number] & drir; + for(int x = 0; x < Tsunami::Max_CPUs; x++) + { + bitvector = ULL(1) << x; + // Figure out which bits have changed + if ((dim[number] & bitvector) != (olddim & bitvector)) + { + // The bit is now set and it wasn't before (set) + if((dim[number] & bitvector) && (dir[number] & bitvector)) + { + tsunami->intrctrl->post(number, TheISA::INTLEVEL_IRQ1, x); + DPRINTF(Tsunami, "dim write resulting in posting dir" + " interrupt to cpu %d\n", number); + } + else if ((olddir & bitvector) && + !(dir[number] & bitvector)) + { + // The bit was set and now its now clear and + // we were interrupting on that bit before + tsunami->intrctrl->clear(number, TheISA::INTLEVEL_IRQ1, x); + DPRINTF(Tsunami, "dim write resulting in clear" + " dir interrupt to cpu %d\n", number); + + } + + + } + } + } else { + switch(regnum) { + case TSDEV_CC_CSR: + panic("TSDEV_CC_CSR write\n"); + case TSDEV_CC_MTR: + panic("TSDEV_CC_MTR write not implemented\n"); + case TSDEV_CC_MISC: + uint64_t ipreq; + ipreq = (pkt->get<uint64_t>() >> 12) & 0xF; + //If it is bit 12-15, this is an IPI post + if (ipreq) { + reqIPI(ipreq); + supportedWrite = true; + } + + //If it is bit 8-11, this is an IPI clear + uint64_t ipintr; + ipintr = (pkt->get<uint64_t>() >> 8) & 0xF; + if (ipintr) { + clearIPI(ipintr); + supportedWrite = true; + } + + //If it is the 4-7th bit, clear the RTC interrupt + uint64_t itintr; + itintr = (pkt->get<uint64_t>() >> 4) & 0xF; + if (itintr) { + clearITI(itintr); + supportedWrite = true; + } + + // ignore NXMs + if (pkt->get<uint64_t>() & 0x10000000) + supportedWrite = true; + + if(!supportedWrite) + panic("TSDEV_CC_MISC write not implemented\n"); + + break; + case TSDEV_CC_AAR0: + case TSDEV_CC_AAR1: + case TSDEV_CC_AAR2: + case TSDEV_CC_AAR3: + panic("TSDEV_CC_AARx write not implemeted\n"); + case TSDEV_CC_DIM0: + case TSDEV_CC_DIM1: + case TSDEV_CC_DIM2: + case TSDEV_CC_DIM3: + int number; + if(regnum == TSDEV_CC_DIM0) + number = 0; + else if(regnum == TSDEV_CC_DIM1) + number = 1; + else if(regnum == TSDEV_CC_DIM2) + number = 2; + else + number = 3; + + uint64_t bitvector; + uint64_t olddim; + uint64_t olddir; + + olddim = dim[number]; + olddir = dir[number]; + dim[number] = pkt->get<uint64_t>(); + dir[number] = dim[number] & drir; + for(int x = 0; x < 64; x++) + { + bitvector = ULL(1) << x; + // Figure out which bits have changed + if ((dim[number] & bitvector) != (olddim & bitvector)) + { + // The bit is now set and it wasn't before (set) + if((dim[number] & bitvector) && (dir[number] & bitvector)) + { + tsunami->intrctrl->post(number, TheISA::INTLEVEL_IRQ1, x); + DPRINTF(Tsunami, "posting dir interrupt to cpu 0\n"); + } + else if ((olddir & bitvector) && + !(dir[number] & bitvector)) + { + // The bit was set and now its now clear and + // we were interrupting on that bit before + tsunami->intrctrl->clear(number, TheISA::INTLEVEL_IRQ1, x); + DPRINTF(Tsunami, "dim write resulting in clear" + " dir interrupt to cpu %d\n", + x); + + } + + + } + } + break; + case TSDEV_CC_DIR0: + case TSDEV_CC_DIR1: + case TSDEV_CC_DIR2: + case TSDEV_CC_DIR3: + panic("TSDEV_CC_DIR write not implemented\n"); + case TSDEV_CC_DRIR: + panic("TSDEV_CC_DRIR write not implemented\n"); + case TSDEV_CC_PRBEN: + panic("TSDEV_CC_PRBEN write not implemented\n"); + case TSDEV_CC_IIC0: + case TSDEV_CC_IIC1: + case TSDEV_CC_IIC2: + case TSDEV_CC_IIC3: + panic("TSDEV_CC_IICx write not implemented\n"); + case TSDEV_CC_MPR0: + case TSDEV_CC_MPR1: + case TSDEV_CC_MPR2: + case TSDEV_CC_MPR3: + panic("TSDEV_CC_MPRx write not implemented\n"); + case TSDEV_CC_IPIR: + clearIPI(pkt->get<uint64_t>()); + break; + case TSDEV_CC_ITIR: + clearITI(pkt->get<uint64_t>()); + break; + case TSDEV_CC_IPIQ: + reqIPI(pkt->get<uint64_t>()); + break; + default: + panic("default in cchip read reached, accessing 0x%x\n"); + } // swtich(regnum) + } // not BIG_TSUNAMI write + pkt->result = Packet::Success; + return pioDelay; +} + +void +TsunamiCChip::clearIPI(uint64_t ipintr) +{ + int numcpus = tsunami->intrctrl->cpu->system->execContexts.size(); + assert(numcpus <= Tsunami::Max_CPUs); + + if (ipintr) { + for (int cpunum=0; cpunum < numcpus; cpunum++) { + // Check each cpu bit + uint64_t cpumask = ULL(1) << cpunum; + if (ipintr & cpumask) { + // Check if there is a pending ipi + if (ipint & cpumask) { + ipint &= ~cpumask; + tsunami->intrctrl->clear(cpunum, TheISA::INTLEVEL_IRQ3, 0); + DPRINTF(IPI, "clear IPI IPI cpu=%d\n", cpunum); + } + else + warn("clear IPI for CPU=%d, but NO IPI\n", cpunum); + } + } + } + else + panic("Big IPI Clear, but not processors indicated\n"); +} + +void +TsunamiCChip::clearITI(uint64_t itintr) +{ + int numcpus = tsunami->intrctrl->cpu->system->execContexts.size(); + assert(numcpus <= Tsunami::Max_CPUs); + + if (itintr) { + for (int i=0; i < numcpus; i++) { + uint64_t cpumask = ULL(1) << i; + if (itintr & cpumask & itint) { + tsunami->intrctrl->clear(i, TheISA::INTLEVEL_IRQ2, 0); + itint &= ~cpumask; + DPRINTF(Tsunami, "clearing rtc interrupt to cpu=%d\n", i); + } + } + } + else + panic("Big ITI Clear, but not processors indicated\n"); +} + +void +TsunamiCChip::reqIPI(uint64_t ipreq) +{ + int numcpus = tsunami->intrctrl->cpu->system->execContexts.size(); + assert(numcpus <= Tsunami::Max_CPUs); + + if (ipreq) { + for (int cpunum=0; cpunum < numcpus; cpunum++) { + // Check each cpu bit + uint64_t cpumask = ULL(1) << cpunum; + if (ipreq & cpumask) { + // Check if there is already an ipi (bits 8:11) + if (!(ipint & cpumask)) { + ipint |= cpumask; + tsunami->intrctrl->post(cpunum, TheISA::INTLEVEL_IRQ3, 0); + DPRINTF(IPI, "send IPI cpu=%d\n", cpunum); + } + else + warn("post IPI for CPU=%d, but IPI already\n", cpunum); + } + } + } + else + panic("Big IPI Request, but not processors indicated\n"); +} + + +void +TsunamiCChip::postRTC() +{ + int size = tsunami->intrctrl->cpu->system->execContexts.size(); + assert(size <= Tsunami::Max_CPUs); + + for (int i = 0; i < size; i++) { + uint64_t cpumask = ULL(1) << i; + if (!(cpumask & itint)) { + itint |= cpumask; + tsunami->intrctrl->post(i, TheISA::INTLEVEL_IRQ2, 0); + DPRINTF(Tsunami, "Posting RTC interrupt to cpu=%d", i); + } + } + +} + +void +TsunamiCChip::postDRIR(uint32_t interrupt) +{ + uint64_t bitvector = ULL(1) << interrupt; + uint64_t size = tsunami->intrctrl->cpu->system->execContexts.size(); + assert(size <= Tsunami::Max_CPUs); + drir |= bitvector; + + for(int i=0; i < size; i++) { + dir[i] = dim[i] & drir; + if (dim[i] & bitvector) { + tsunami->intrctrl->post(i, TheISA::INTLEVEL_IRQ1, interrupt); + DPRINTF(Tsunami, "posting dir interrupt to cpu %d," + "interrupt %d\n",i, interrupt); + } + } +} + +void +TsunamiCChip::clearDRIR(uint32_t interrupt) +{ + uint64_t bitvector = ULL(1) << interrupt; + uint64_t size = tsunami->intrctrl->cpu->system->execContexts.size(); + assert(size <= Tsunami::Max_CPUs); + + if (drir & bitvector) + { + drir &= ~bitvector; + for(int i=0; i < size; i++) { + if (dir[i] & bitvector) { + tsunami->intrctrl->clear(i, TheISA::INTLEVEL_IRQ1, interrupt); + DPRINTF(Tsunami, "clearing dir interrupt to cpu %d," + "interrupt %d\n",i, interrupt); + + } + dir[i] = dim[i] & drir; + } + } + else + DPRINTF(Tsunami, "Spurrious clear? interrupt %d\n", interrupt); +} + + +void +TsunamiCChip::serialize(std::ostream &os) +{ + SERIALIZE_ARRAY(dim, Tsunami::Max_CPUs); + SERIALIZE_ARRAY(dir, Tsunami::Max_CPUs); + SERIALIZE_SCALAR(ipint); + SERIALIZE_SCALAR(itint); + SERIALIZE_SCALAR(drir); +} + +void +TsunamiCChip::unserialize(Checkpoint *cp, const std::string §ion) +{ + UNSERIALIZE_ARRAY(dim, Tsunami::Max_CPUs); + UNSERIALIZE_ARRAY(dir, Tsunami::Max_CPUs); + UNSERIALIZE_SCALAR(ipint); + UNSERIALIZE_SCALAR(itint); + UNSERIALIZE_SCALAR(drir); +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiCChip) + + Param<Addr> pio_addr; + Param<Tick> pio_latency; + SimObjectParam<Platform *> platform; + SimObjectParam<System *> system; + SimObjectParam<Tsunami *> tsunami; + +END_DECLARE_SIM_OBJECT_PARAMS(TsunamiCChip) + +BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiCChip) + + INIT_PARAM(pio_addr, "Device Address"), + INIT_PARAM(pio_latency, "Programmed IO latency"), + INIT_PARAM(platform, "platform"), + INIT_PARAM(system, "system object"), + INIT_PARAM(tsunami, "Tsunami") + +END_INIT_SIM_OBJECT_PARAMS(TsunamiCChip) + +CREATE_SIM_OBJECT(TsunamiCChip) +{ + TsunamiCChip::Params *p = new TsunamiCChip::Params; + p->name = getInstanceName(); + p->pio_addr = pio_addr; + p->pio_delay = pio_latency; + p->platform = platform; + p->system = system; + p->tsunami = tsunami; + return new TsunamiCChip(p); +} + +REGISTER_SIM_OBJECT("TsunamiCChip", TsunamiCChip) diff --git a/src/dev/tsunami_cchip.hh b/src/dev/tsunami_cchip.hh new file mode 100644 index 000000000..3dde0131e --- /dev/null +++ b/src/dev/tsunami_cchip.hh @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file + * Emulation of the Tsunami CChip CSRs + */ + +#ifndef __TSUNAMI_CCHIP_HH__ +#define __TSUNAMI_CCHIP_HH__ + +#include "dev/tsunami.hh" +#include "base/range.hh" +#include "dev/io_device.hh" + + +/** + * Tsunami CChip CSR Emulation. This device includes all the interrupt + * handling code for the chipset. + */ +class TsunamiCChip : public BasicPioDevice +{ + protected: + /** + * pointer to the tsunami object. + * This is our access to all the other tsunami + * devices. + */ + Tsunami *tsunami; + + /** + * The dims are device interrupt mask registers. + * One exists for each CPU, the DRIR X DIM = DIR + */ + uint64_t dim[Tsunami::Max_CPUs]; + + /** + * The dirs are device interrupt registers. + * One exists for each CPU, the DRIR X DIM = DIR + */ + uint64_t dir[Tsunami::Max_CPUs]; + + /** + * This register contains bits for each PCI interrupt + * that can occur. + */ + uint64_t drir; + + /** Indicator of which CPUs have an IPI interrupt */ + uint64_t ipint; + + /** Indicator of which CPUs have an RTC interrupt */ + uint64_t itint; + + public: + struct Params : public BasicPioDevice::Params + { + Tsunami *tsunami; + }; + protected: + const Params *params() const {return (const Params *)_params; } + + public: + /** + * Initialize the Tsunami CChip by setting all of the + * device register to 0. + * @param p params struct + */ + TsunamiCChip(Params *p); + + virtual Tick read(Packet *pkt); + + virtual Tick write(Packet *pkt); + + /** + * post an RTC interrupt to the CPU + */ + void postRTC(); + + /** + * post an interrupt to the CPU. + * @param interrupt the interrupt number to post (0-64) + */ + void postDRIR(uint32_t interrupt); + + /** + * clear an interrupt previously posted to the CPU. + * @param interrupt the interrupt number to post (0-64) + */ + void clearDRIR(uint32_t interrupt); + + /** + * post an ipi interrupt to the CPU. + * @param ipintr the cpu number to clear(bitvector) + */ + void clearIPI(uint64_t ipintr); + + /** + * clear a timer interrupt previously posted to the CPU. + * @param itintr the cpu number to clear(bitvector) + */ + void clearITI(uint64_t itintr); + + /** + * request an interrupt be posted to the CPU. + * @param ipreq the cpu number to interrupt(bitvector) + */ + void reqIPI(uint64_t ipreq); + + + /** + * Serialize this object to the given output stream. + * @param os The stream to serialize to. + */ + virtual void serialize(std::ostream &os); + + /** + * Reconstruct the state of this object from a checkpoint. + * @param cp The checkpoint use. + * @param section The section name of this object + */ + virtual void unserialize(Checkpoint *cp, const std::string §ion); + +}; + +#endif // __TSUNAMI_CCHIP_HH__ diff --git a/src/dev/tsunami_io.cc b/src/dev/tsunami_io.cc new file mode 100644 index 000000000..729a61cf7 --- /dev/null +++ b/src/dev/tsunami_io.cc @@ -0,0 +1,685 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file + * Tsunami I/O including PIC, PIT, RTC, DMA + */ + +#include <sys/time.h> + +#include <deque> +#include <string> +#include <vector> + +#include "base/trace.hh" +#include "dev/pitreg.h" +#include "dev/rtcreg.h" +#include "dev/tsunami_cchip.hh" +#include "dev/tsunami.hh" +#include "dev/tsunami_io.hh" +#include "dev/tsunamireg.h" +#include "mem/port.hh" +#include "sim/builder.hh" +#include "sim/system.hh" + +using namespace std; +//Should this be AlphaISA? +using namespace TheISA; + +TsunamiIO::RTC::RTC(const string &name, Tsunami* t, Tick i) + : _name(name), event(t, i), addr(0) +{ + memset(clock_data, 0, sizeof(clock_data)); + stat_regA = RTCA_32768HZ | RTCA_1024HZ; + stat_regB = RTCB_PRDC_IE |RTCB_BIN | RTCB_24HR; +} + +void +TsunamiIO::RTC::set_time(time_t t) +{ + struct tm tm; + gmtime_r(&t, &tm); + + sec = tm.tm_sec; + min = tm.tm_min; + hour = tm.tm_hour; + wday = tm.tm_wday + 1; + mday = tm.tm_mday; + mon = tm.tm_mon + 1; + year = tm.tm_year; + + DPRINTFN("Real-time clock set to %s", asctime(&tm)); +} + +void +TsunamiIO::RTC::writeAddr(const uint8_t data) +{ + if (data <= RTC_STAT_REGD) + addr = data; + else + panic("RTC addresses over 0xD are not implemented.\n"); +} + +void +TsunamiIO::RTC::writeData(const uint8_t data) +{ + if (addr < RTC_STAT_REGA) + clock_data[addr] = data; + else { + switch (addr) { + case RTC_STAT_REGA: + if (data != (RTCA_32768HZ | RTCA_1024HZ)) + panic("Unimplemented RTC register A value write!\n"); + stat_regA = data; + break; + case RTC_STAT_REGB: + if ((data & ~(RTCB_PRDC_IE | RTCB_SQWE)) != (RTCB_BIN | RTCB_24HR)) + panic("Write to RTC reg B bits that are not implemented!\n"); + + if (data & RTCB_PRDC_IE) { + if (!event.scheduled()) + event.scheduleIntr(); + } else { + if (event.scheduled()) + event.deschedule(); + } + stat_regB = data; + break; + case RTC_STAT_REGC: + case RTC_STAT_REGD: + panic("RTC status registers C and D are not implemented.\n"); + break; + } + } +} + +uint8_t +TsunamiIO::RTC::readData() +{ + if (addr < RTC_STAT_REGA) + return clock_data[addr]; + else { + switch (addr) { + case RTC_STAT_REGA: + // toggle UIP bit for linux + stat_regA ^= RTCA_UIP; + return stat_regA; + break; + case RTC_STAT_REGB: + return stat_regB; + break; + case RTC_STAT_REGC: + case RTC_STAT_REGD: + return 0x00; + break; + default: + panic("Shouldn't be here"); + } + } +} + +void +TsunamiIO::RTC::serialize(const string &base, ostream &os) +{ + paramOut(os, base + ".addr", addr); + arrayParamOut(os, base + ".clock_data", clock_data, sizeof(clock_data)); + paramOut(os, base + ".stat_regA", stat_regA); + paramOut(os, base + ".stat_regB", stat_regB); +} + +void +TsunamiIO::RTC::unserialize(const string &base, Checkpoint *cp, + const string §ion) +{ + paramIn(cp, section, base + ".addr", addr); + arrayParamIn(cp, section, base + ".clock_data", clock_data, + sizeof(clock_data)); + paramIn(cp, section, base + ".stat_regA", stat_regA); + paramIn(cp, section, base + ".stat_regB", stat_regB); + + // We're not unserializing the event here, but we need to + // rescehedule the event since curTick was moved forward by the + // checkpoint + event.reschedule(curTick + event.interval); +} + +TsunamiIO::RTC::RTCEvent::RTCEvent(Tsunami*t, Tick i) + : Event(&mainEventQueue), tsunami(t), interval(i) +{ + DPRINTF(MC146818, "RTC Event Initilizing\n"); + schedule(curTick + interval); +} + +void +TsunamiIO::RTC::RTCEvent::scheduleIntr() +{ + schedule(curTick + interval); +} + +void +TsunamiIO::RTC::RTCEvent::process() +{ + DPRINTF(MC146818, "RTC Timer Interrupt\n"); + schedule(curTick + interval); + //Actually interrupt the processor here + tsunami->cchip->postRTC(); +} + +const char * +TsunamiIO::RTC::RTCEvent::description() +{ + return "tsunami RTC interrupt"; +} + +TsunamiIO::PITimer::PITimer(const string &name) + : _name(name), counter0(name + ".counter0"), counter1(name + ".counter1"), + counter2(name + ".counter2") +{ + counter[0] = &counter0; + counter[1] = &counter0; + counter[2] = &counter0; +} + +void +TsunamiIO::PITimer::writeControl(const uint8_t data) +{ + int rw; + int sel; + + sel = GET_CTRL_SEL(data); + + if (sel == PIT_READ_BACK) + panic("PITimer Read-Back Command is not implemented.\n"); + + rw = GET_CTRL_RW(data); + + if (rw == PIT_RW_LATCH_COMMAND) + counter[sel]->latchCount(); + else { + counter[sel]->setRW(rw); + counter[sel]->setMode(GET_CTRL_MODE(data)); + counter[sel]->setBCD(GET_CTRL_BCD(data)); + } +} + +void +TsunamiIO::PITimer::serialize(const string &base, ostream &os) +{ + // serialize the counters + counter0.serialize(base + ".counter0", os); + counter1.serialize(base + ".counter1", os); + counter2.serialize(base + ".counter2", os); +} + +void +TsunamiIO::PITimer::unserialize(const string &base, Checkpoint *cp, + const string §ion) +{ + // unserialze the counters + counter0.unserialize(base + ".counter0", cp, section); + counter1.unserialize(base + ".counter1", cp, section); + counter2.unserialize(base + ".counter2", cp, section); +} + +TsunamiIO::PITimer::Counter::Counter(const string &name) + : _name(name), event(this), count(0), latched_count(0), period(0), + mode(0), output_high(false), latch_on(false), read_byte(LSB), + write_byte(LSB) +{ + +} + +void +TsunamiIO::PITimer::Counter::latchCount() +{ + // behave like a real latch + if(!latch_on) { + latch_on = true; + read_byte = LSB; + latched_count = count; + } +} + +uint8_t +TsunamiIO::PITimer::Counter::read() +{ + if (latch_on) { + switch (read_byte) { + case LSB: + read_byte = MSB; + return (uint8_t)latched_count; + break; + case MSB: + read_byte = LSB; + latch_on = false; + return latched_count >> 8; + break; + default: + panic("Shouldn't be here"); + } + } else { + switch (read_byte) { + case LSB: + read_byte = MSB; + return (uint8_t)count; + break; + case MSB: + read_byte = LSB; + return count >> 8; + break; + default: + panic("Shouldn't be here"); + } + } +} + +void +TsunamiIO::PITimer::Counter::write(const uint8_t data) +{ + switch (write_byte) { + case LSB: + count = (count & 0xFF00) | data; + + if (event.scheduled()) + event.deschedule(); + output_high = false; + write_byte = MSB; + break; + + case MSB: + count = (count & 0x00FF) | (data << 8); + period = count; + + if (period > 0) { + DPRINTF(Tsunami, "Timer set to curTick + %d\n", + count * event.interval); + event.schedule(curTick + count * event.interval); + } + write_byte = LSB; + break; + } +} + +void +TsunamiIO::PITimer::Counter::setRW(int rw_val) +{ + if (rw_val != PIT_RW_16BIT) + panic("Only LSB/MSB read/write is implemented.\n"); +} + +void +TsunamiIO::PITimer::Counter::setMode(int mode_val) +{ + if(mode_val != PIT_MODE_INTTC && mode_val != PIT_MODE_RATEGEN && + mode_val != PIT_MODE_SQWAVE) + panic("PIT mode %#x is not implemented: \n", mode_val); + + mode = mode_val; +} + +void +TsunamiIO::PITimer::Counter::setBCD(int bcd_val) +{ + if (bcd_val != PIT_BCD_FALSE) + panic("PITimer does not implement BCD counts.\n"); +} + +bool +TsunamiIO::PITimer::Counter::outputHigh() +{ + return output_high; +} + +void +TsunamiIO::PITimer::Counter::serialize(const string &base, ostream &os) +{ + paramOut(os, base + ".count", count); + paramOut(os, base + ".latched_count", latched_count); + paramOut(os, base + ".period", period); + paramOut(os, base + ".mode", mode); + paramOut(os, base + ".output_high", output_high); + paramOut(os, base + ".latch_on", latch_on); + paramOut(os, base + ".read_byte", read_byte); + paramOut(os, base + ".write_byte", write_byte); + + Tick event_tick = 0; + if (event.scheduled()) + event_tick = event.when(); + paramOut(os, base + ".event_tick", event_tick); +} + +void +TsunamiIO::PITimer::Counter::unserialize(const string &base, Checkpoint *cp, + const string §ion) +{ + paramIn(cp, section, base + ".count", count); + paramIn(cp, section, base + ".latched_count", latched_count); + paramIn(cp, section, base + ".period", period); + paramIn(cp, section, base + ".mode", mode); + paramIn(cp, section, base + ".output_high", output_high); + paramIn(cp, section, base + ".latch_on", latch_on); + paramIn(cp, section, base + ".read_byte", read_byte); + paramIn(cp, section, base + ".write_byte", write_byte); + + Tick event_tick; + paramIn(cp, section, base + ".event_tick", event_tick); + if (event_tick) + event.schedule(event_tick); +} + +TsunamiIO::PITimer::Counter::CounterEvent::CounterEvent(Counter* c_ptr) + : Event(&mainEventQueue) +{ + interval = (Tick)(Clock::Float::s / 1193180.0); + counter = c_ptr; +} + +void +TsunamiIO::PITimer::Counter::CounterEvent::process() +{ + DPRINTF(Tsunami, "Timer Interrupt\n"); + switch (counter->mode) { + case PIT_MODE_INTTC: + counter->output_high = true; + case PIT_MODE_RATEGEN: + case PIT_MODE_SQWAVE: + break; + default: + panic("Unimplemented PITimer mode.\n"); + } +} + +const char * +TsunamiIO::PITimer::Counter::CounterEvent::description() +{ + return "tsunami 8254 Interval timer"; +} + +TsunamiIO::TsunamiIO(Params *p) + : BasicPioDevice(p), tsunami(p->tsunami), pitimer(p->name + "pitimer"), + rtc(p->name + ".rtc", p->tsunami, p->frequency) +{ + pioSize = 0xff; + + // set the back pointer from tsunami to myself + tsunami->io = this; + + timerData = 0; + rtc.set_time(p->init_time == 0 ? time(NULL) : p->init_time); + picr = 0; + picInterrupting = false; +} + +Tick +TsunamiIO::frequency() const +{ + return Clock::Frequency / params()->frequency; +} + +Tick +TsunamiIO::read(Packet *pkt) +{ + assert(pkt->result == Packet::Unknown); + assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); + + pkt->time += pioDelay; + Addr daddr = pkt->getAddr() - pioAddr; + + DPRINTF(Tsunami, "io read va=%#x size=%d IOPorrt=%#x\n", pkt->getAddr(), + pkt->getSize(), daddr); + + pkt->allocate(); + + if (pkt->getSize() == sizeof(uint8_t)) { + switch(daddr) { + // PIC1 mask read + case TSDEV_PIC1_MASK: + pkt->set(~mask1); + break; + case TSDEV_PIC2_MASK: + pkt->set(~mask2); + break; + case TSDEV_PIC1_ISR: + // !!! If this is modified 64bit case needs to be too + // Pal code has to do a 64 bit physical read because there is + // no load physical byte instruction + pkt->set(picr); + break; + case TSDEV_PIC2_ISR: + // PIC2 not implemnted... just return 0 + pkt->set(0x00); + break; + case TSDEV_TMR0_DATA: + pkt->set(pitimer.counter0.read()); + break; + case TSDEV_TMR1_DATA: + pkt->set(pitimer.counter1.read()); + break; + case TSDEV_TMR2_DATA: + pkt->set(pitimer.counter2.read()); + break; + case TSDEV_RTC_DATA: + pkt->set(rtc.readData()); + break; + case TSDEV_CTRL_PORTB: + if (pitimer.counter2.outputHigh()) + pkt->set(PORTB_SPKR_HIGH); + else + pkt->set(0x00); + break; + default: + panic("I/O Read - va%#x size %d\n", pkt->getAddr(), pkt->getSize()); + } + } else if (pkt->getSize() == sizeof(uint64_t)) { + if (daddr == TSDEV_PIC1_ISR) + pkt->set<uint64_t>(picr); + else + panic("I/O Read - invalid addr - va %#x size %d\n", + pkt->getAddr(), pkt->getSize()); + } else { + panic("I/O Read - invalid size - va %#x size %d\n", pkt->getAddr(), pkt->getSize()); + } + pkt->result = Packet::Success; + return pioDelay; +} + +Tick +TsunamiIO::write(Packet *pkt) +{ + pkt->time += pioDelay; + + assert(pkt->result == Packet::Unknown); + assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); + Addr daddr = pkt->getAddr() - pioAddr; + + DPRINTF(Tsunami, "io write - va=%#x size=%d IOPort=%#x Data=%#x\n", + pkt->getAddr(), pkt->getSize(), pkt->getAddr() & 0xfff, (uint32_t)pkt->get<uint8_t>()); + + assert(pkt->getSize() == sizeof(uint8_t)); + + switch(daddr) { + case TSDEV_PIC1_MASK: + mask1 = ~(pkt->get<uint8_t>()); + if ((picr & mask1) && !picInterrupting) { + picInterrupting = true; + tsunami->cchip->postDRIR(55); + DPRINTF(Tsunami, "posting pic interrupt to cchip\n"); + } + if ((!(picr & mask1)) && picInterrupting) { + picInterrupting = false; + tsunami->cchip->clearDRIR(55); + DPRINTF(Tsunami, "clearing pic interrupt\n"); + } + break; + case TSDEV_PIC2_MASK: + mask2 = pkt->get<uint8_t>(); + //PIC2 Not implemented to interrupt + break; + case TSDEV_PIC1_ACK: + // clear the interrupt on the PIC + picr &= ~(1 << (pkt->get<uint8_t>() & 0xF)); + if (!(picr & mask1)) + tsunami->cchip->clearDRIR(55); + break; + case TSDEV_DMA1_MODE: + mode1 = pkt->get<uint8_t>(); + break; + case TSDEV_DMA2_MODE: + mode2 = pkt->get<uint8_t>(); + break; + case TSDEV_TMR0_DATA: + pitimer.counter0.write(pkt->get<uint8_t>()); + break; + case TSDEV_TMR1_DATA: + pitimer.counter1.write(pkt->get<uint8_t>()); + break; + case TSDEV_TMR2_DATA: + pitimer.counter2.write(pkt->get<uint8_t>()); + break; + case TSDEV_TMR_CTRL: + pitimer.writeControl(pkt->get<uint8_t>()); + break; + case TSDEV_RTC_ADDR: + rtc.writeAddr(pkt->get<uint8_t>()); + break; + case TSDEV_RTC_DATA: + rtc.writeData(pkt->get<uint8_t>()); + break; + case TSDEV_KBD: + case TSDEV_DMA1_CMND: + case TSDEV_DMA2_CMND: + case TSDEV_DMA1_MMASK: + case TSDEV_DMA2_MMASK: + case TSDEV_PIC2_ACK: + case TSDEV_DMA1_RESET: + case TSDEV_DMA2_RESET: + case TSDEV_DMA1_MASK: + case TSDEV_DMA2_MASK: + case TSDEV_CTRL_PORTB: + break; + default: + panic("I/O Write - va%#x size %d data %#x\n", pkt->getAddr(), pkt->getSize(), pkt->get<uint8_t>()); + } + + pkt->result = Packet::Success; + return pioDelay; +} + +void +TsunamiIO::postPIC(uint8_t bitvector) +{ + //PIC2 Is not implemented, because nothing of interest there + picr |= bitvector; + if (picr & mask1) { + tsunami->cchip->postDRIR(55); + DPRINTF(Tsunami, "posting pic interrupt to cchip\n"); + } +} + +void +TsunamiIO::clearPIC(uint8_t bitvector) +{ + //PIC2 Is not implemented, because nothing of interest there + picr &= ~bitvector; + if (!(picr & mask1)) { + tsunami->cchip->clearDRIR(55); + DPRINTF(Tsunami, "clearing pic interrupt to cchip\n"); + } +} + +void +TsunamiIO::serialize(ostream &os) +{ + SERIALIZE_SCALAR(timerData); + SERIALIZE_SCALAR(mask1); + SERIALIZE_SCALAR(mask2); + SERIALIZE_SCALAR(mode1); + SERIALIZE_SCALAR(mode2); + SERIALIZE_SCALAR(picr); + SERIALIZE_SCALAR(picInterrupting); + + // Serialize the timers + pitimer.serialize("pitimer", os); + rtc.serialize("rtc", os); +} + +void +TsunamiIO::unserialize(Checkpoint *cp, const string §ion) +{ + UNSERIALIZE_SCALAR(timerData); + UNSERIALIZE_SCALAR(mask1); + UNSERIALIZE_SCALAR(mask2); + UNSERIALIZE_SCALAR(mode1); + UNSERIALIZE_SCALAR(mode2); + UNSERIALIZE_SCALAR(picr); + UNSERIALIZE_SCALAR(picInterrupting); + + // Unserialize the timers + pitimer.unserialize("pitimer", cp, section); + rtc.unserialize("rtc", cp, section); +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO) + + Param<Addr> pio_addr; + Param<Tick> pio_latency; + Param<Tick> frequency; + SimObjectParam<Platform *> platform; + SimObjectParam<System *> system; + Param<time_t> time; + SimObjectParam<Tsunami *> tsunami; + +END_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO) + +BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiIO) + + INIT_PARAM(pio_addr, "Device Address"), + INIT_PARAM(pio_latency, "Programmed IO latency"), + INIT_PARAM(frequency, "clock interrupt frequency"), + INIT_PARAM(platform, "platform"), + INIT_PARAM(system, "system object"), + INIT_PARAM(time, "System time to use (0 for actual time"), + INIT_PARAM(tsunami, "Tsunami") + +END_INIT_SIM_OBJECT_PARAMS(TsunamiIO) + +CREATE_SIM_OBJECT(TsunamiIO) +{ + TsunamiIO::Params *p = new TsunamiIO::Params; + p->frequency = frequency; + p->name = getInstanceName(); + p->pio_addr = pio_addr; + p->pio_delay = pio_latency; + p->platform = platform; + p->system = system; + p->init_time = time; + p->tsunami = tsunami; + return new TsunamiIO(p); +} + +REGISTER_SIM_OBJECT("TsunamiIO", TsunamiIO) diff --git a/src/dev/tsunami_io.hh b/src/dev/tsunami_io.hh new file mode 100644 index 000000000..71ca0d98f --- /dev/null +++ b/src/dev/tsunami_io.hh @@ -0,0 +1,351 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file + * Tsunami I/O Space mapping including RTC/timer interrupts + */ + +#ifndef __DEV_TSUNAMI_IO_HH__ +#define __DEV_TSUNAMI_IO_HH__ + +#include "dev/io_device.hh" +#include "base/range.hh" +#include "dev/tsunami.hh" +#include "sim/eventq.hh" + +/** + * Tsunami I/O device is a catch all for all the south bridge stuff we care + * to implement. + */ +class TsunamiIO : public BasicPioDevice +{ + private: + struct tm tm; + + protected: + /** Real-Time Clock (MC146818) */ + class RTC + { + private: + /** Event for RTC periodic interrupt */ + struct RTCEvent : public Event + { + /** A pointer back to tsunami to create interrupt the processor. */ + Tsunami* tsunami; + Tick interval; + + RTCEvent(Tsunami* t, Tick i); + + /** Schedule the RTC periodic interrupt */ + void scheduleIntr(); + + /** Event process to occur at interrupt*/ + virtual void process(); + + /** Event description */ + virtual const char *description(); + }; + + private: + std::string _name; + const std::string &name() const { return _name; } + + /** RTC periodic interrupt event */ + RTCEvent event; + + /** Current RTC register address/index */ + int addr; + + /** Data for real-time clock function */ + union { + uint8_t clock_data[10]; + + struct { + uint8_t sec; + uint8_t sec_alrm; + uint8_t min; + uint8_t min_alrm; + uint8_t hour; + uint8_t hour_alrm; + uint8_t wday; + uint8_t mday; + uint8_t mon; + uint8_t year; + }; + }; + + /** RTC status register A */ + uint8_t stat_regA; + + /** RTC status register B */ + uint8_t stat_regB; + + public: + RTC(const std::string &name, Tsunami* t, Tick i); + + /** Set the initial RTC time/date */ + void set_time(time_t t); + + /** RTC address port: write address of RTC RAM data to access */ + void writeAddr(const uint8_t data); + + /** RTC write data */ + void writeData(const uint8_t data); + + /** RTC read data */ + uint8_t readData(); + + /** + * Serialize this object to the given output stream. + * @param os The stream to serialize to. + */ + void serialize(const std::string &base, std::ostream &os); + + /** + * Reconstruct the state of this object from a checkpoint. + * @param cp The checkpoint use. + * @param section The section name of this object + */ + void unserialize(const std::string &base, Checkpoint *cp, + const std::string §ion); + }; + + /** Programmable Interval Timer (Intel 8254) */ + class PITimer + { + /** Counter element for PIT */ + class Counter + { + /** Event for counter interrupt */ + class CounterEvent : public Event + { + private: + /** Pointer back to Counter */ + Counter* counter; + Tick interval; + + public: + CounterEvent(Counter*); + + /** Event process */ + virtual void process(); + + /** Event description */ + virtual const char *description(); + + friend class Counter; + }; + + private: + std::string _name; + const std::string &name() const { return _name; } + + CounterEvent event; + + /** Current count value */ + uint16_t count; + + /** Latched count */ + uint16_t latched_count; + + /** Interrupt period */ + uint16_t period; + + /** Current mode of operation */ + uint8_t mode; + + /** Output goes high when the counter reaches zero */ + bool output_high; + + /** State of the count latch */ + bool latch_on; + + /** Set of values for read_byte and write_byte */ + enum {LSB, MSB}; + + /** Determine which byte of a 16-bit count value to read/write */ + uint8_t read_byte, write_byte; + + public: + Counter(const std::string &name); + + /** Latch the current count (if one is not already latched) */ + void latchCount(); + + /** Set the read/write mode */ + void setRW(int rw_val); + + /** Set operational mode */ + void setMode(int mode_val); + + /** Set count encoding */ + void setBCD(int bcd_val); + + /** Read a count byte */ + uint8_t read(); + + /** Write a count byte */ + void write(const uint8_t data); + + /** Is the output high? */ + bool outputHigh(); + + /** + * Serialize this object to the given output stream. + * @param os The stream to serialize to. + */ + void serialize(const std::string &base, std::ostream &os); + + /** + * Reconstruct the state of this object from a checkpoint. + * @param cp The checkpoint use. + * @param section The section name of this object + */ + void unserialize(const std::string &base, Checkpoint *cp, + const std::string §ion); + }; + + private: + std::string _name; + const std::string &name() const { return _name; } + + /** PIT has three seperate counters */ + Counter *counter[3]; + + public: + /** Public way to access individual counters (avoid array accesses) */ + Counter counter0; + Counter counter1; + Counter counter2; + + PITimer(const std::string &name); + + /** Write control word */ + void writeControl(const uint8_t data); + + /** + * Serialize this object to the given output stream. + * @param os The stream to serialize to. + */ + void serialize(const std::string &base, std::ostream &os); + + /** + * Reconstruct the state of this object from a checkpoint. + * @param cp The checkpoint use. + * @param section The section name of this object + */ + void unserialize(const std::string &base, Checkpoint *cp, + const std::string §ion); + }; + + /** Mask of the PIC1 */ + uint8_t mask1; + + /** Mask of the PIC2 */ + uint8_t mask2; + + /** Mode of PIC1. Not used for anything */ + uint8_t mode1; + + /** Mode of PIC2. Not used for anything */ + uint8_t mode2; + + /** Raw PIC interrupt register before masking */ + uint8_t picr; //Raw PIC interrput register + + /** Is the pic interrupting right now or not. */ + bool picInterrupting; + + /** A pointer to the Tsunami device which be belong to */ + Tsunami *tsunami; + + /** Intel 8253 Periodic Interval Timer */ + PITimer pitimer; + + RTC rtc; + + /** The interval is set via two writes to the PIT. + * This variable contains a flag as to how many writes have happened, and + * the time so far. + */ + uint16_t timerData; + + public: + /** + * Return the freqency of the RTC + * @return interrupt rate of the RTC + */ + Tick frequency() const; + + struct Params : public BasicPioDevice::Params + { + Tick frequency; + Tsunami *tsunami; + time_t init_time; + }; + protected: + const Params *params() const { return (const Params*)_params; } + + public: + /** + * Initialize all the data for devices supported by Tsunami I/O. + * @param p pointer to Params struct + */ + TsunamiIO(Params *p); + + virtual Tick read(Packet *pkt); + virtual Tick write(Packet *pkt); + + /** + * Post an PIC interrupt to the CPU via the CChip + * @param bitvector interrupt to post. + */ + void postPIC(uint8_t bitvector); + + /** + * Clear a posted interrupt + * @param bitvector interrupt to clear + */ + void clearPIC(uint8_t bitvector); + + /** + * Serialize this object to the given output stream. + * @param os The stream to serialize to. + */ + virtual void serialize(std::ostream &os); + + /** + * Reconstruct the state of this object from a checkpoint. + * @param cp The checkpoint use. + * @param section The section name of this object + */ + virtual void unserialize(Checkpoint *cp, const std::string §ion); + +}; + +#endif // __DEV_TSUNAMI_IO_HH__ diff --git a/src/dev/tsunami_pchip.cc b/src/dev/tsunami_pchip.cc new file mode 100644 index 000000000..c430ca0a0 --- /dev/null +++ b/src/dev/tsunami_pchip.cc @@ -0,0 +1,358 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file + * Tsunami PChip (pci) + */ + +#include <deque> +#include <string> +#include <vector> + +#include "base/trace.hh" +#include "dev/tsunami_pchip.hh" +#include "dev/tsunamireg.h" +#include "dev/tsunami.hh" +#include "mem/packet.hh" +#include "sim/builder.hh" +#include "sim/system.hh" + +using namespace std; +//Should this be AlphaISA? +using namespace TheISA; + +TsunamiPChip::TsunamiPChip(Params *p) +: BasicPioDevice(p) +{ + pioSize = 0xfff; + + for (int i = 0; i < 4; i++) { + wsba[i] = 0; + wsm[i] = 0; + tba[i] = 0; + } + + // initialize pchip control register + pctl = (ULL(0x1) << 20) | (ULL(0x1) << 32) | (ULL(0x2) << 36); + + //Set back pointer in tsunami + p->tsunami->pchip = this; +} + +Tick +TsunamiPChip::read(Packet *pkt) +{ + assert(pkt->result == Packet::Unknown); + assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); + + + pkt->time += pioDelay; + pkt->allocate(); + Addr daddr = (pkt->getAddr() - pioAddr) >> 6;; + assert(pkt->getSize() == sizeof(uint64_t)); + + + DPRINTF(Tsunami, "read va=%#x size=%d\n", pkt->getAddr(), pkt->getSize()); + + switch(daddr) { + case TSDEV_PC_WSBA0: + pkt->set(wsba[0]); + break; + case TSDEV_PC_WSBA1: + pkt->set(wsba[1]); + break; + case TSDEV_PC_WSBA2: + pkt->set(wsba[2]); + break; + case TSDEV_PC_WSBA3: + pkt->set(wsba[3]); + break; + case TSDEV_PC_WSM0: + pkt->set(wsm[0]); + break; + case TSDEV_PC_WSM1: + pkt->set(wsm[1]); + break; + case TSDEV_PC_WSM2: + pkt->set(wsm[2]); + break; + case TSDEV_PC_WSM3: + pkt->set(wsm[3]); + break; + case TSDEV_PC_TBA0: + pkt->set(tba[0]); + break; + case TSDEV_PC_TBA1: + pkt->set(tba[1]); + break; + case TSDEV_PC_TBA2: + pkt->set(tba[2]); + break; + case TSDEV_PC_TBA3: + pkt->set(tba[3]); + break; + case TSDEV_PC_PCTL: + pkt->set(pctl); + break; + case TSDEV_PC_PLAT: + panic("PC_PLAT not implemented\n"); + case TSDEV_PC_RES: + panic("PC_RES not implemented\n"); + case TSDEV_PC_PERROR: + pkt->set((uint64_t)0x00); + break; + case TSDEV_PC_PERRMASK: + pkt->set((uint64_t)0x00); + break; + case TSDEV_PC_PERRSET: + panic("PC_PERRSET not implemented\n"); + case TSDEV_PC_TLBIV: + panic("PC_TLBIV not implemented\n"); + case TSDEV_PC_TLBIA: + pkt->set((uint64_t)0x00); // shouldn't be readable, but linux + break; + case TSDEV_PC_PMONCTL: + panic("PC_PMONCTL not implemented\n"); + case TSDEV_PC_PMONCNT: + panic("PC_PMONCTN not implemented\n"); + default: + panic("Default in PChip Read reached reading 0x%x\n", daddr); + } + pkt->result = Packet::Success; + return pioDelay; + +} + +Tick +TsunamiPChip::write(Packet *pkt) +{ + pkt->time += pioDelay; + + assert(pkt->result == Packet::Unknown); + assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); + Addr daddr = (pkt->getAddr() - pioAddr) >> 6; + + assert(pkt->getSize() == sizeof(uint64_t)); + + DPRINTF(Tsunami, "write - va=%#x size=%d \n", pkt->getAddr(), pkt->getSize()); + + switch(daddr) { + case TSDEV_PC_WSBA0: + wsba[0] = pkt->get<uint64_t>(); + break; + case TSDEV_PC_WSBA1: + wsba[1] = pkt->get<uint64_t>(); + break; + case TSDEV_PC_WSBA2: + wsba[2] = pkt->get<uint64_t>(); + break; + case TSDEV_PC_WSBA3: + wsba[3] = pkt->get<uint64_t>(); + break; + case TSDEV_PC_WSM0: + wsm[0] = pkt->get<uint64_t>(); + break; + case TSDEV_PC_WSM1: + wsm[1] = pkt->get<uint64_t>(); + break; + case TSDEV_PC_WSM2: + wsm[2] = pkt->get<uint64_t>(); + break; + case TSDEV_PC_WSM3: + wsm[3] = pkt->get<uint64_t>(); + break; + case TSDEV_PC_TBA0: + tba[0] = pkt->get<uint64_t>(); + break; + case TSDEV_PC_TBA1: + tba[1] = pkt->get<uint64_t>(); + break; + case TSDEV_PC_TBA2: + tba[2] = pkt->get<uint64_t>(); + break; + case TSDEV_PC_TBA3: + tba[3] = pkt->get<uint64_t>(); + break; + case TSDEV_PC_PCTL: + pctl = pkt->get<uint64_t>(); + break; + case TSDEV_PC_PLAT: + panic("PC_PLAT not implemented\n"); + case TSDEV_PC_RES: + panic("PC_RES not implemented\n"); + case TSDEV_PC_PERROR: + break; + case TSDEV_PC_PERRMASK: + panic("PC_PERRMASK not implemented\n"); + case TSDEV_PC_PERRSET: + panic("PC_PERRSET not implemented\n"); + case TSDEV_PC_TLBIV: + panic("PC_TLBIV not implemented\n"); + case TSDEV_PC_TLBIA: + break; // value ignored, supposted to invalidate SG TLB + case TSDEV_PC_PMONCTL: + panic("PC_PMONCTL not implemented\n"); + case TSDEV_PC_PMONCNT: + panic("PC_PMONCTN not implemented\n"); + default: + panic("Default in PChip write reached reading 0x%x\n", daddr); + + } // uint64_t + + pkt->result = Packet::Success; + return pioDelay; +} + +#define DMA_ADDR_MASK ULL(0x3ffffffff) + +Addr +TsunamiPChip::translatePciToDma(Addr busAddr) +{ + // compare the address to the window base registers + uint64_t tbaMask = 0; + uint64_t baMask = 0; + + uint64_t windowMask = 0; + uint64_t windowBase = 0; + + uint64_t pteEntry = 0; + + Addr pteAddr; + Addr dmaAddr; + +#if 0 + DPRINTF(IdeDisk, "Translation for bus address: %#x\n", busAddr); + for (int i = 0; i < 4; i++) { + DPRINTF(IdeDisk, "(%d) base:%#x mask:%#x\n", + i, wsba[i], wsm[i]); + + windowBase = wsba[i]; + windowMask = ~wsm[i] & (ULL(0xfff) << 20); + + if ((busAddr & windowMask) == (windowBase & windowMask)) { + DPRINTF(IdeDisk, "Would have matched %d (wb:%#x wm:%#x --> ba&wm:%#x wb&wm:%#x)\n", + i, windowBase, windowMask, (busAddr & windowMask), + (windowBase & windowMask)); + } + } +#endif + + for (int i = 0; i < 4; i++) { + + windowBase = wsba[i]; + windowMask = ~wsm[i] & (ULL(0xfff) << 20); + + if ((busAddr & windowMask) == (windowBase & windowMask)) { + + if (wsba[i] & 0x1) { // see if enabled + if (wsba[i] & 0x2) { // see if SG bit is set + /** @todo + This currently is faked by just doing a direct + read from memory, however, to be realistic, this + needs to actually do a bus transaction. The process + is explained in the tsunami documentation on page + 10-12 and basically munges the address to look up a + PTE from a table in memory and then uses that mapping + to create an address for the SG page + */ + + tbaMask = ~(((wsm[i] & (ULL(0xfff) << 20)) >> 10) | ULL(0x3ff)); + baMask = (wsm[i] & (ULL(0xfff) << 20)) | (ULL(0x7f) << 13); + pteAddr = (tba[i] & tbaMask) | ((busAddr & baMask) >> 10); + + pioPort->readBlob(pteAddr, (uint8_t*)&pteEntry, sizeof(uint64_t)); + + dmaAddr = ((pteEntry & ~ULL(0x1)) << 12) | (busAddr & ULL(0x1fff)); + + } else { + baMask = (wsm[i] & (ULL(0xfff) << 20)) | ULL(0xfffff); + tbaMask = ~baMask; + dmaAddr = (tba[i] & tbaMask) | (busAddr & baMask); + } + + return (dmaAddr & DMA_ADDR_MASK); + } + } + } + + // if no match was found, then return the original address + return busAddr; +} + +void +TsunamiPChip::serialize(std::ostream &os) +{ + SERIALIZE_SCALAR(pctl); + SERIALIZE_ARRAY(wsba, 4); + SERIALIZE_ARRAY(wsm, 4); + SERIALIZE_ARRAY(tba, 4); +} + +void +TsunamiPChip::unserialize(Checkpoint *cp, const std::string §ion) +{ + UNSERIALIZE_SCALAR(pctl); + UNSERIALIZE_ARRAY(wsba, 4); + UNSERIALIZE_ARRAY(wsm, 4); + UNSERIALIZE_ARRAY(tba, 4); +} + + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiPChip) + + Param<Addr> pio_addr; + Param<Tick> pio_latency; + SimObjectParam<Platform *> platform; + SimObjectParam<System *> system; + SimObjectParam<Tsunami *> tsunami; + +END_DECLARE_SIM_OBJECT_PARAMS(TsunamiPChip) + +BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiPChip) + + INIT_PARAM(pio_addr, "Device Address"), + INIT_PARAM(pio_latency, "Programmed IO latency"), + INIT_PARAM(platform, "platform"), + INIT_PARAM(system, "system object"), + INIT_PARAM(tsunami, "Tsunami") + +END_INIT_SIM_OBJECT_PARAMS(TsunamiPChip) + +CREATE_SIM_OBJECT(TsunamiPChip) +{ + TsunamiPChip::Params *p = new TsunamiPChip::Params; + p->name = getInstanceName(); + p->pio_addr = pio_addr; + p->pio_delay = pio_latency; + p->platform = platform; + p->system = system; + p->tsunami = tsunami; + return new TsunamiPChip(p); +} + +REGISTER_SIM_OBJECT("TsunamiPChip", TsunamiPChip) diff --git a/src/dev/tsunami_pchip.hh b/src/dev/tsunami_pchip.hh new file mode 100644 index 000000000..bb84339c9 --- /dev/null +++ b/src/dev/tsunami_pchip.hh @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file + * Tsunami PCI interface CSRs + */ + +#ifndef __TSUNAMI_PCHIP_HH__ +#define __TSUNAMI_PCHIP_HH__ + +#include "dev/tsunami.hh" +#include "base/range.hh" +#include "dev/io_device.hh" + +/** + * A very simple implementation of the Tsunami PCI interface chips. + */ +class TsunamiPChip : public BasicPioDevice +{ + protected: + /** Pchip control register */ + uint64_t pctl; + + /** Window Base addresses */ + uint64_t wsba[4]; + + /** Window masks */ + uint64_t wsm[4]; + + /** Translated Base Addresses */ + uint64_t tba[4]; + + public: + struct Params : public BasicPioDevice::Params + { + Tsunami *tsunami; + }; + protected: + const Params *params() const { return (const Params*)_params; } + + public: + /** + * Register the PChip with the mmu and init all wsba, wsm, and tba to 0 + * @param p pointer to the parameters struct + */ + TsunamiPChip(Params *p); + + /** + * Translate a PCI bus address to a memory address for DMA. + * @todo Andrew says this needs to be fixed. What's wrong with it? + * @param busAddr PCI address to translate. + * @return memory system address + */ + Addr translatePciToDma(Addr busAddr); + + virtual Tick read(Packet *pkt); + virtual Tick write(Packet *pkt); + + /** + * Serialize this object to the given output stream. + * @param os The stream to serialize to. + */ + virtual void serialize(std::ostream &os); + + /** + * Reconstruct the state of this object from a checkpoint. + * @param cp The checkpoint use. + * @param section The section name of this object + */ + virtual void unserialize(Checkpoint *cp, const std::string §ion); +}; + +#endif // __TSUNAMI_PCHIP_HH__ diff --git a/dev/tsunamireg.h b/src/dev/tsunamireg.h index a10259900..a10259900 100644 --- a/dev/tsunamireg.h +++ b/src/dev/tsunamireg.h diff --git a/src/dev/uart.cc b/src/dev/uart.cc new file mode 100644 index 000000000..4a9f2b505 --- /dev/null +++ b/src/dev/uart.cc @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file + * Implements a base class for UARTs + */ + +#include "dev/simconsole.hh" +#include "dev/uart.hh" +#include "dev/platform.hh" +#include "sim/builder.hh" + +using namespace std; + +Uart::Uart(Params *p) + : BasicPioDevice(p), platform(p->platform), cons(p->cons) +{ + + status = 0; + + // set back pointers + cons->uart = this; + platform->uart = this; +} + +DEFINE_SIM_OBJECT_CLASS_NAME("Uart", Uart) + diff --git a/src/dev/uart.hh b/src/dev/uart.hh new file mode 100644 index 000000000..2dd15d9b8 --- /dev/null +++ b/src/dev/uart.hh @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file + * Base class for UART + */ + +#ifndef __UART_HH__ +#define __UART_HH__ + +#include "base/range.hh" +#include "dev/io_device.hh" + +class SimConsole; +class Platform; + +const int RX_INT = 0x1; +const int TX_INT = 0x2; + + +class Uart : public BasicPioDevice +{ + + protected: + int status; + Platform *platform; + SimConsole *cons; + + public: + struct Params : public BasicPioDevice::Params + { + SimConsole *cons; + }; + + Uart(Params *p); + + /** + * Inform the uart that there is data available. + */ + virtual void dataAvailable() = 0; + + + /** + * Return if we have an interrupt pending + * @return interrupt status + */ + bool intStatus() { return status ? true : false; } + + protected: + const Params *params() const {return (const Params *)_params; } + +}; + +#endif // __UART_HH__ diff --git a/src/dev/uart8250.cc b/src/dev/uart8250.cc new file mode 100644 index 000000000..8a5a1f1cd --- /dev/null +++ b/src/dev/uart8250.cc @@ -0,0 +1,366 @@ +/* + * Copyright (c) 2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file + * Implements a 8250 UART + */ + +#include <string> +#include <vector> + +#include "arch/alpha/ev5.hh" +#include "base/inifile.hh" +#include "base/str.hh" // for to_number +#include "base/trace.hh" +#include "dev/simconsole.hh" +#include "dev/uart8250.hh" +#include "dev/platform.hh" +#include "sim/builder.hh" + +using namespace std; +using namespace TheISA; + +Uart8250::IntrEvent::IntrEvent(Uart8250 *u, int bit) + : Event(&mainEventQueue), uart(u) +{ + DPRINTF(Uart, "UART Interrupt Event Initilizing\n"); + intrBit = bit; +} + +const char * +Uart8250::IntrEvent::description() +{ + return "uart interrupt delay event"; +} + +void +Uart8250::IntrEvent::process() +{ + if (intrBit & uart->IER) { + DPRINTF(Uart, "UART InterEvent, interrupting\n"); + uart->platform->postConsoleInt(); + uart->status |= intrBit; + } + else + DPRINTF(Uart, "UART InterEvent, not interrupting\n"); + +} + +/* The linux serial driver (8250.c about line 1182) loops reading from + * the device until the device reports it has no more data to + * read. After a maximum of 255 iterations the code prints "serial8250 + * too much work for irq X," and breaks out of the loop. Since the + * simulated system is so much slower than the actual system, if a + * user is typing on the keyboard it is very easy for them to provide + * input at a fast enough rate to not allow the loop to exit and thus + * the error to be printed. This magic number provides a delay between + * the time the UART receives a character to send to the simulated + * system and the time it actually notifies the system it has a + * character to send to alleviate this problem. --Ali + */ +void +Uart8250::IntrEvent::scheduleIntr() +{ + static const Tick interval = (Tick)((Clock::Float::s / 2e9) * 450); + DPRINTF(Uart, "Scheduling IER interrupt for %#x, at cycle %lld\n", intrBit, + curTick + interval); + if (!scheduled()) + schedule(curTick + interval); + else + reschedule(curTick + interval); +} + + +Uart8250::Uart8250(Params *p) + : Uart(p), txIntrEvent(this, TX_INT), rxIntrEvent(this, RX_INT) +{ + pioSize = 8; + + IER = 0; + DLAB = 0; + LCR = 0; + MCR = 0; +} + +Tick +Uart8250::read(Packet *pkt) +{ + assert(pkt->result == Packet::Unknown); + assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); + assert(pkt->getSize() == 1); + + pkt->time += pioDelay; + Addr daddr = pkt->getAddr() - pioAddr; + pkt->allocate(); + + DPRINTF(Uart, " read register %#x\n", daddr); + + switch (daddr) { + case 0x0: + if (!(LCR & 0x80)) { // read byte + if (cons->dataAvailable()) + pkt->set(cons->in()); + else { + pkt->set((uint8_t)0); + // A limited amount of these are ok. + DPRINTF(Uart, "empty read of RX register\n"); + } + status &= ~RX_INT; + platform->clearConsoleInt(); + + if (cons->dataAvailable() && (IER & UART_IER_RDI)) + rxIntrEvent.scheduleIntr(); + } else { // dll divisor latch + ; + } + break; + case 0x1: + if (!(LCR & 0x80)) { // Intr Enable Register(IER) + pkt->set(IER); + } else { // DLM divisor latch MSB + ; + } + break; + case 0x2: // Intr Identification Register (IIR) + DPRINTF(Uart, "IIR Read, status = %#x\n", (uint32_t)status); + + if (status & RX_INT) /* Rx data interrupt has a higher priority */ + pkt->set(IIR_RXID); + else if (status & TX_INT) + pkt->set(IIR_TXID); + else + pkt->set(IIR_NOPEND); + + //Tx interrupts are cleared on IIR reads + status &= ~TX_INT; + break; + case 0x3: // Line Control Register (LCR) + pkt->set(LCR); + break; + case 0x4: // Modem Control Register (MCR) + break; + case 0x5: // Line Status Register (LSR) + uint8_t lsr; + lsr = 0; + // check if there are any bytes to be read + if (cons->dataAvailable()) + lsr = UART_LSR_DR; + lsr |= UART_LSR_TEMT | UART_LSR_THRE; + pkt->set(lsr); + break; + case 0x6: // Modem Status Register (MSR) + pkt->set((uint8_t)0); + break; + case 0x7: // Scratch Register (SCR) + pkt->set((uint8_t)0); // doesn't exist with at 8250. + break; + default: + panic("Tried to access a UART port that doesn't exist\n"); + break; + } +/* uint32_t d32 = *data; + DPRINTF(Uart, "Register read to register %#x returned %#x\n", daddr, d32); +*/ + pkt->result = Packet::Success; + return pioDelay; +} + +Tick +Uart8250::write(Packet *pkt) +{ + + assert(pkt->result == Packet::Unknown); + assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); + assert(pkt->getSize() == 1); + + pkt->time += pioDelay; + Addr daddr = pkt->getAddr() - pioAddr; + + DPRINTF(Uart, " write register %#x value %#x\n", daddr, pkt->get<uint8_t>()); + + switch (daddr) { + case 0x0: + if (!(LCR & 0x80)) { // write byte + cons->out(pkt->get<uint8_t>()); + platform->clearConsoleInt(); + status &= ~TX_INT; + if (UART_IER_THRI & IER) + txIntrEvent.scheduleIntr(); + } else { // dll divisor latch + ; + } + break; + case 0x1: + if (!(LCR & 0x80)) { // Intr Enable Register(IER) + IER = pkt->get<uint8_t>(); + if (UART_IER_THRI & IER) + { + DPRINTF(Uart, "IER: IER_THRI set, scheduling TX intrrupt\n"); + txIntrEvent.scheduleIntr(); + } + else + { + DPRINTF(Uart, "IER: IER_THRI cleared, descheduling TX intrrupt\n"); + if (txIntrEvent.scheduled()) + txIntrEvent.deschedule(); + if (status & TX_INT) + platform->clearConsoleInt(); + status &= ~TX_INT; + } + + if ((UART_IER_RDI & IER) && cons->dataAvailable()) { + DPRINTF(Uart, "IER: IER_RDI set, scheduling RX intrrupt\n"); + rxIntrEvent.scheduleIntr(); + } else { + DPRINTF(Uart, "IER: IER_RDI cleared, descheduling RX intrrupt\n"); + if (rxIntrEvent.scheduled()) + rxIntrEvent.deschedule(); + if (status & RX_INT) + platform->clearConsoleInt(); + status &= ~RX_INT; + } + } else { // DLM divisor latch MSB + ; + } + break; + case 0x2: // FIFO Control Register (FCR) + break; + case 0x3: // Line Control Register (LCR) + LCR = pkt->get<uint8_t>(); + break; + case 0x4: // Modem Control Register (MCR) + if (pkt->get<uint8_t>() == (UART_MCR_LOOP | 0x0A)) + MCR = 0x9A; + break; + case 0x7: // Scratch Register (SCR) + // We are emulating a 8250 so we don't have a scratch reg + break; + default: + panic("Tried to access a UART port that doesn't exist\n"); + break; + } + pkt->result = Packet::Success; + return pioDelay; +} + +void +Uart8250::dataAvailable() +{ + // if the kernel wants an interrupt when we have data + if (IER & UART_IER_RDI) + { + platform->postConsoleInt(); + status |= RX_INT; + } + +} + +void +Uart8250::addressRanges(AddrRangeList &range_list) +{ + assert(pioSize != 0); + range_list.clear(); + range_list.push_back(RangeSize(pioAddr, pioSize)); +} + + + +void +Uart8250::serialize(ostream &os) +{ + SERIALIZE_SCALAR(status); + SERIALIZE_SCALAR(IER); + SERIALIZE_SCALAR(DLAB); + SERIALIZE_SCALAR(LCR); + SERIALIZE_SCALAR(MCR); + Tick rxintrwhen; + if (rxIntrEvent.scheduled()) + rxintrwhen = rxIntrEvent.when(); + else + rxintrwhen = 0; + Tick txintrwhen; + if (txIntrEvent.scheduled()) + txintrwhen = txIntrEvent.when(); + else + txintrwhen = 0; + SERIALIZE_SCALAR(rxintrwhen); + SERIALIZE_SCALAR(txintrwhen); +} + +void +Uart8250::unserialize(Checkpoint *cp, const std::string §ion) +{ + UNSERIALIZE_SCALAR(status); + UNSERIALIZE_SCALAR(IER); + UNSERIALIZE_SCALAR(DLAB); + UNSERIALIZE_SCALAR(LCR); + UNSERIALIZE_SCALAR(MCR); + Tick rxintrwhen; + Tick txintrwhen; + UNSERIALIZE_SCALAR(rxintrwhen); + UNSERIALIZE_SCALAR(txintrwhen); + if (rxintrwhen != 0) + rxIntrEvent.schedule(rxintrwhen); + if (txintrwhen != 0) + txIntrEvent.schedule(txintrwhen); +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(Uart8250) + + Param<Addr> pio_addr; + Param<Tick> pio_latency; + SimObjectParam<Platform *> platform; + SimObjectParam<SimConsole *> sim_console; + SimObjectParam<System *> system; + +END_DECLARE_SIM_OBJECT_PARAMS(Uart8250) + +BEGIN_INIT_SIM_OBJECT_PARAMS(Uart8250) + + INIT_PARAM(pio_addr, "Device Address"), + INIT_PARAM_DFLT(pio_latency, "Programmed IO latency", 1000), + INIT_PARAM(platform, "platform"), + INIT_PARAM(sim_console, "The Simulator Console"), + INIT_PARAM(system, "system object") + +END_INIT_SIM_OBJECT_PARAMS(Uart8250) + +CREATE_SIM_OBJECT(Uart8250) +{ + Uart8250::Params *p = new Uart8250::Params; + p->name = getInstanceName(); + p->pio_addr = pio_addr; + p->pio_delay = pio_latency; + p->platform = platform; + p->cons = sim_console; + p->system = system; + return new Uart8250(p); +} + +REGISTER_SIM_OBJECT("Uart8250", Uart8250) + diff --git a/src/dev/uart8250.hh b/src/dev/uart8250.hh new file mode 100644 index 000000000..4b7c2f1e4 --- /dev/null +++ b/src/dev/uart8250.hh @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file + * Defines a 8250 UART + */ + +#ifndef __DEV_UART8250_HH__ +#define __DEV_UART8250_HH__ + +#include "dev/tsunamireg.h" +#include "base/range.hh" +#include "dev/io_device.hh" +#include "dev/uart.hh" + + +/* UART8250 Interrupt ID Register + * bit 0 Interrupt Pending 0 = true, 1 = false + * bit 2:1 ID of highest priority interrupt + * bit 7:3 zeroes + */ +const uint8_t IIR_NOPEND = 0x1; + +// Interrupt IDs +const uint8_t IIR_MODEM = 0x00; /* Modem Status (lowest priority) */ +const uint8_t IIR_TXID = 0x02; /* Tx Data */ +const uint8_t IIR_RXID = 0x04; /* Rx Data */ +const uint8_t IIR_LINE = 0x06; /* Rx Line Status (highest priority)*/ + +class SimConsole; +class Platform; + +class Uart8250 : public Uart +{ + + + protected: + uint8_t IER, DLAB, LCR, MCR; + + class IntrEvent : public Event + { + protected: + Uart8250 *uart; + int intrBit; + public: + IntrEvent(Uart8250 *u, int bit); + virtual void process(); + virtual const char *description(); + void scheduleIntr(); + }; + + IntrEvent txIntrEvent; + IntrEvent rxIntrEvent; + + public: + Uart8250(Params *p); + + virtual Tick read(Packet *pkt); + virtual Tick write(Packet *pkt); + virtual void addressRanges(AddrRangeList &range_list); + + + /** + * Inform the uart that there is data available. + */ + virtual void dataAvailable(); + + + /** + * Return if we have an interrupt pending + * @return interrupt status + */ + virtual bool intStatus() { return status ? true : false; } + + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); + +}; + +#endif // __TSUNAMI_UART_HH__ diff --git a/kern/kernel_stats.cc b/src/kern/kernel_stats.cc index b85d88145..b85d88145 100644 --- a/kern/kernel_stats.cc +++ b/src/kern/kernel_stats.cc diff --git a/kern/kernel_stats.hh b/src/kern/kernel_stats.hh index 16ec721d0..16ec721d0 100644 --- a/kern/kernel_stats.hh +++ b/src/kern/kernel_stats.hh diff --git a/src/kern/linux/events.cc b/src/kern/linux/events.cc new file mode 100644 index 000000000..b688e9dd0 --- /dev/null +++ b/src/kern/linux/events.cc @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2004-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "arch/arguments.hh" +#include "base/trace.hh" +#include "cpu/exec_context.hh" +#include "kern/linux/events.hh" +#include "kern/linux/printk.hh" +#include "kern/system_events.hh" +#include "sim/system.hh" + + +namespace Linux { + +void +DebugPrintkEvent::process(ExecContext *xc) +{ + if (DTRACE(DebugPrintf)) { + if (!raw) { + StringWrap name(xc->getSystemPtr()->name() + ".dprintk"); + DPRINTFN(""); + } + + AlphaISA::AlphaArguments args(xc); + Printk(args); + SkipFuncEvent::process(xc); + } +} + +} // namespace linux diff --git a/kern/linux/events.hh b/src/kern/linux/events.hh index 95c268976..95c268976 100644 --- a/kern/linux/events.hh +++ b/src/kern/linux/events.hh diff --git a/src/kern/linux/linux.hh b/src/kern/linux/linux.hh new file mode 100644 index 000000000..63e0dd5ca --- /dev/null +++ b/src/kern/linux/linux.hh @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __LINUX_HH__ +#define __LINUX_HH__ +#include "config/full_system.hh" + +#if FULL_SYSTEM + +class Linux {}; + +#else //!FULL_SYSTEM + +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> // for host open() flags +#include <string.h> // for memset() +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include "arch/isa_traits.hh" +#include "sim/syscall_emul.hh" + +class TranslatingPort; + +/// +/// This class encapsulates the types, structures, constants, +/// functions, and syscall-number mappings specific to the Alpha Linux +/// syscall interface. +/// +class Linux { + + public: + + //@{ + /// Basic Linux types. + typedef uint64_t size_t; + typedef uint64_t off_t; + typedef int64_t time_t; + typedef uint32_t uid_t; + typedef uint32_t gid_t; + //@} + +#if BSD_HOST + typedef struct stat hst_stat; + typedef struct stat hst_stat64; +#else + typedef struct stat hst_stat ; + typedef struct stat64 hst_stat64; +#endif + + /// Stat buffer. Note that we can't call it 'stat' since that + /// gets #defined to something else on some systems. + struct tgt_stat { + uint32_t st_dev; //!< device + uint32_t st_ino; //!< inode + uint32_t st_mode; //!< mode + uint32_t st_nlink; //!< link count + uint32_t st_uid; //!< owner's user ID + uint32_t st_gid; //!< owner's group ID + uint32_t st_rdev; //!< device number + int32_t _pad1; //!< for alignment + int64_t st_size; //!< file size in bytes + uint64_t st_atimeX; //!< time of last access + uint64_t st_mtimeX; //!< time of last modification + uint64_t st_ctimeX; //!< time of last status change + uint32_t st_blksize; //!< optimal I/O block size + int32_t st_blocks; //!< number of blocks allocated + uint32_t st_flags; //!< flags + uint32_t st_gen; //!< unknown + }; + + // same for stat64 + struct tgt_stat64 { + uint64_t st_dev; + uint64_t st_ino; + uint64_t st_rdev; + int64_t st_size; + uint64_t st_blocks; + + uint32_t st_mode; + uint32_t st_uid; + uint32_t st_gid; + uint32_t st_blksize; + uint32_t st_nlink; + uint32_t __pad0; + + uint64_t tgt_st_atime; + uint64_t st_atime_nsec; + uint64_t tgt_st_mtime; + uint64_t st_mtime_nsec; + uint64_t tgt_st_ctime; + uint64_t st_ctime_nsec; + int64_t ___unused[3]; + }; + + /// Length of strings in struct utsname (plus 1 for null char). + static const int _SYS_NMLN = 65; + + /// Interface struct for uname(). + struct utsname { + char sysname[_SYS_NMLN]; //!< System name. + char nodename[_SYS_NMLN]; //!< Node name. + char release[_SYS_NMLN]; //!< OS release. + char version[_SYS_NMLN]; //!< OS version. + char machine[_SYS_NMLN]; //!< Machine type. + }; + + /// Limit struct for getrlimit/setrlimit. + struct rlimit { + uint64_t rlim_cur; //!< soft limit + uint64_t rlim_max; //!< hard limit + }; + + /// For gettimeofday(). + struct timeval { + int64_t tv_sec; //!< seconds + int64_t tv_usec; //!< microseconds + }; + + // For writev/readv + struct tgt_iovec { + uint64_t iov_base; // void * + uint64_t iov_len; + }; + + + /// For getrusage(). + struct rusage { + struct timeval ru_utime; //!< user time used + struct timeval ru_stime; //!< system time used + int64_t ru_maxrss; //!< max rss + int64_t ru_ixrss; //!< integral shared memory size + int64_t ru_idrss; //!< integral unshared data " + int64_t ru_isrss; //!< integral unshared stack " + int64_t ru_minflt; //!< page reclaims - total vmfaults + int64_t ru_majflt; //!< page faults + int64_t ru_nswap; //!< swaps + int64_t ru_inblock; //!< block input operations + int64_t ru_oublock; //!< block output operations + int64_t ru_msgsnd; //!< messages sent + int64_t ru_msgrcv; //!< messages received + int64_t ru_nsignals; //!< signals received + int64_t ru_nvcsw; //!< voluntary context switches + int64_t ru_nivcsw; //!< involuntary " + }; + + /// Helper function to convert a host stat buffer to a target stat + /// buffer. Also copies the target buffer out to the simulated + /// memory space. Used by stat(), fstat(), and lstat(). +#if !BSD_HOST + static void + copyOutStatBuf(TranslatingPort *mem, Addr addr, hst_stat *host) + { + using namespace TheISA; + + TypedBufferArg<Linux::tgt_stat> tgt(addr); + + tgt->st_dev = htog(host->st_dev); + tgt->st_ino = htog(host->st_ino); + tgt->st_mode = htog(host->st_mode); + tgt->st_nlink = htog(host->st_nlink); + tgt->st_uid = htog(host->st_uid); + tgt->st_gid = htog(host->st_gid); + tgt->st_rdev = htog(host->st_rdev); + tgt->st_size = htog(host->st_size); + tgt->st_atimeX = htog(host->st_atime); + tgt->st_mtimeX = htog(host->st_mtime); + tgt->st_ctimeX = htog(host->st_ctime); + tgt->st_blksize = htog(host->st_blksize); + tgt->st_blocks = htog(host->st_blocks); + + tgt.copyOut(mem); + } +#else + // Third version for bsd systems which no longer have any support for + // the old stat() call and stat() is actually a stat64() + static void + copyOutStatBuf(TranslatingPort *mem, Addr addr, hst_stat64 *host) + { + using namespace TheISA; + + TypedBufferArg<Linux::tgt_stat> tgt(addr); + + tgt->st_dev = htog(host->st_dev); + tgt->st_ino = htog(host->st_ino); + tgt->st_mode = htog(host->st_mode); + tgt->st_nlink = htog(host->st_nlink); + tgt->st_uid = htog(host->st_uid); + tgt->st_gid = htog(host->st_gid); + tgt->st_rdev = htog(host->st_rdev); + tgt->st_size = htog(host->st_size); + tgt->st_atimeX = htog(host->st_atime); + tgt->st_mtimeX = htog(host->st_mtime); + tgt->st_ctimeX = htog(host->st_ctime); + tgt->st_blksize = htog(host->st_blksize); + tgt->st_blocks = htog(host->st_blocks); + + tgt.copyOut(mem); + } +#endif + + + // Same for stat64 + static void + copyOutStat64Buf(TranslatingPort *mem, int fd, Addr addr, hst_stat64 *host) + { + using namespace TheISA; + + TypedBufferArg<Linux::tgt_stat64> tgt(addr); + + // fd == 1 checks are because libc does some checks + // that the stdout is interactive vs. a file + // this makes it work on non-linux systems + if (fd == 1) + tgt->st_dev = htog((uint64_t)0xA); + else + tgt->st_dev = htog((uint64_t)host->st_dev); + // XXX What about STAT64_HAS_BROKEN_ST_INO ??? + tgt->st_ino = htog((uint64_t)host->st_ino); + if (fd == 1) + tgt->st_rdev = htog((uint64_t)0x880d); + else + tgt->st_rdev = htog((uint64_t)host->st_rdev); + tgt->st_size = htog((int64_t)host->st_size); + tgt->st_blocks = htog((uint64_t)host->st_blocks); + + if (fd == 1) + tgt->st_mode = htog((uint32_t)0x2190); + else + tgt->st_mode = htog((uint32_t)host->st_mode); + tgt->st_uid = htog((uint32_t)host->st_uid); + tgt->st_gid = htog((uint32_t)host->st_gid); + tgt->st_blksize = htog((uint32_t)host->st_blksize); + tgt->st_nlink = htog((uint32_t)host->st_nlink); + tgt->tgt_st_atime = htog((uint64_t)host->st_atime); + tgt->tgt_st_mtime = htog((uint64_t)host->st_mtime); + tgt->tgt_st_ctime = htog((uint64_t)host->st_ctime); +#if defined(STAT_HAVE_NSEC) + tgt->st_atime_nsec = htog(host->st_atime_nsec); + tgt->st_mtime_nsec = htog(host->st_mtime_nsec); + tgt->st_ctime_nsec = htog(host->st_ctime_nsec); +#else + tgt->st_atime_nsec = 0; + tgt->st_mtime_nsec = 0; + tgt->st_ctime_nsec = 0; +#endif + + tgt.copyOut(mem); + } + +}; // class Linux + + +#endif // FULL_SYSTEM + +#endif // __LINUX_HH__ diff --git a/kern/linux/linux_syscalls.cc b/src/kern/linux/linux_syscalls.cc index c85b6d28f..c85b6d28f 100644 --- a/kern/linux/linux_syscalls.cc +++ b/src/kern/linux/linux_syscalls.cc diff --git a/kern/linux/linux_syscalls.hh b/src/kern/linux/linux_syscalls.hh index 7f2a08ea9..7f2a08ea9 100644 --- a/kern/linux/linux_syscalls.hh +++ b/src/kern/linux/linux_syscalls.hh diff --git a/src/kern/linux/printk.cc b/src/kern/linux/printk.cc new file mode 100644 index 000000000..918b8dabe --- /dev/null +++ b/src/kern/linux/printk.cc @@ -0,0 +1,261 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <algorithm> + +#include "base/trace.hh" +#include "arch/arguments.hh" + +using namespace std; + + +void +Printk(AlphaISA::AlphaArguments args) +{ + char *p = (char *)args++; + + ios::fmtflags saved_flags = DebugOut().flags(); + char old_fill = DebugOut().fill(); + int old_precision = DebugOut().precision(); + + while (*p) { + switch (*p) { + case '%': { + bool more = true; + bool islong = false; + bool leftjustify = false; + bool format = false; + bool zero = false; + int width = 0; + while (more && *++p) { + switch (*p) { + case 'l': + case 'L': + islong = true; + break; + case '-': + leftjustify = true; + break; + case '#': + format = true; + break; + case '0': + if (width) + width *= 10; + else + zero = true; + break; + default: + if (*p >= '1' && *p <= '9') + width = 10 * width + *p - '0'; + else + more = false; + break; + } + } + + bool hexnum = false; + bool octal = false; + bool sign = false; + switch (*p) { + case 'X': + case 'x': + hexnum = true; + break; + case 'O': + case 'o': + octal = true; + break; + case 'D': + case 'd': + sign = true; + break; + case 'P': + format = true; + case 'p': + hexnum = true; + break; + } + + switch (*p) { + case 'D': + case 'd': + case 'U': + case 'u': + case 'X': + case 'x': + case 'O': + case 'o': + case 'P': + case 'p': { + if (hexnum) + DebugOut() << hex; + + if (octal) + DebugOut() << oct; + + if (format) { + if (!zero) + DebugOut().setf(ios::showbase); + else { + if (hexnum) { + DebugOut() << "0x"; + width -= 2; + } else if (octal) { + DebugOut() << "0"; + width -= 1; + } + } + } + + if (zero) + DebugOut().fill('0'); + + if (width > 0) + DebugOut().width(width); + + if (leftjustify && !zero) + DebugOut().setf(ios::left); + + if (sign) { + if (islong) + DebugOut() << (int64_t)args; + else + DebugOut() << (int32_t)args; + } else { + if (islong) + DebugOut() << (uint64_t)args; + else + DebugOut() << (uint32_t)args; + } + + if (zero) + DebugOut().fill(' '); + + if (width > 0) + DebugOut().width(0); + + DebugOut() << dec; + + ++args; + } + break; + + case 's': { + char *s = (char *)args; + if (!s) + s = "<NULL>"; + + if (width > 0) + DebugOut().width(width); + if (leftjustify) + DebugOut().setf(ios::left); + + DebugOut() << s; + ++args; + } + break; + case 'C': + case 'c': { + uint64_t mask = (*p == 'C') ? 0xffL : 0x7fL; + uint64_t num; + int width; + + if (islong) { + num = (uint64_t)args; + width = sizeof(uint64_t); + } else { + num = (uint32_t)args; + width = sizeof(uint32_t); + } + + while (width-- > 0) { + char c = (char)(num & mask); + if (c) + DebugOut() << c; + num >>= 8; + } + + ++args; + } + break; + case 'b': { + uint64_t n = (uint64_t)args++; + char *s = (char *)args++; + DebugOut() << s << ": " << n; + } + break; + case 'n': + case 'N': { + args += 2; +#if 0 + uint64_t n = (uint64_t)args++; + struct reg_values *rv = (struct reg_values *)args++; +#endif + } + break; + case 'r': + case 'R': { + args += 2; +#if 0 + uint64_t n = (uint64_t)args++; + struct reg_desc *rd = (struct reg_desc *)args++; +#endif + } + break; + case '%': + DebugOut() << '%'; + break; + } + ++p; + } + break; + case '\n': + DebugOut() << endl; + ++p; + break; + case '\r': + ++p; + if (*p != '\n') + DebugOut() << endl; + break; + + default: { + size_t len = strcspn(p, "%\n\r\0"); + DebugOut().write(p, len); + p += len; + } + } + } + + DebugOut().flags(saved_flags); + DebugOut().fill(old_fill); + DebugOut().precision(old_precision); +} + diff --git a/src/kern/linux/printk.hh b/src/kern/linux/printk.hh new file mode 100644 index 000000000..b88c40f5e --- /dev/null +++ b/src/kern/linux/printk.hh @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __PRINTK_HH__ +#define __PRINTK_HH__ + +class AlphaISA::AlphaArguments; + +void Printk(AlphaISA::AlphaArguments args); + +#endif // __PRINTK_HH__ diff --git a/kern/linux/sched.hh b/src/kern/linux/sched.hh index a11fa590d..a11fa590d 100644 --- a/kern/linux/sched.hh +++ b/src/kern/linux/sched.hh diff --git a/src/kern/solaris/solaris.hh b/src/kern/solaris/solaris.hh new file mode 100644 index 000000000..e2b61d613 --- /dev/null +++ b/src/kern/solaris/solaris.hh @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __SOLARIS_HH__ +#define __SOLARIS_HH__ +#include "config/full_system.hh" + +#if FULL_SYSTEM + +class Solaris {}; + +#else //!FULL_SYSTEM + +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> // for host open() flags +#include <string.h> // for memset() +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include "arch/isa_traits.hh" +#include "sim/syscall_emul.hh" + +class TranslatingPort; + +/// +/// This class encapsulates the types, structures, constants, +/// functions, and syscall-number mappings specific to the Solaris +/// syscall interface. +/// +class Solaris { + + public: + + //@{ + /// Basic Solaris types. + typedef uint64_t size_t; + typedef uint64_t off_t; + typedef int64_t time_t; + typedef int32_t uid_t; + typedef int32_t gid_t; + typedef uint64_t rlim_t; + typedef uint64_t ino_t; + typedef uint64_t dev_t; + typedef uint32_t mode_t; + typedef uint32_t nlink_t; + //@} + +#if BSD_HOST + typedef struct stat hst_stat; + typedef struct stat hst_stat64; +#else + typedef struct stat hst_stat ; + typedef struct stat64 hst_stat64; +#endif + struct tgt_timespec { + int64_t tv_sec; + int64_t tv_nsec; + }; + + /// Stat buffer. Note that we can't call it 'stat' since that + /// gets #defined to something else on some systems. + struct tgt_stat { + uint64_t st_dev; //!< device + uint64_t st_ino; //!< inode + uint32_t st_mode; //!< mode + uint32_t st_nlink; //!< link count + int32_t st_uid; //!< owner's user ID + int32_t st_gid; //!< owner's group ID + uint64_t st_rdev; //!< device number + int64_t st_size; //!< file size in bytes + struct tgt_timespec st_atimeX; //!< time of last access + struct tgt_timespec st_mtimeX; //!< time of last modification + struct tgt_timespec st_ctimeX; //!< time of last status change + int32_t st_blksize; //!< optimal I/O block size + int64_t st_blocks; //!< number of blocks allocated + char st_fstype[16]; + }; + + // same for stat64 + struct tgt_stat64 { + uint64_t st_dev; //!< device + uint64_t st_ino; //!< inode + uint32_t st_mode; //!< mode + uint32_t st_nlink; //!< link count + int32_t st_uid; //!< owner's user ID + int32_t st_gid; //!< owner's group ID + uint64_t st_rdev; //!< device number + int64_t st_size; //!< file size in bytes + struct tgt_timespec st_atimeX; //!< time of last access + struct tgt_timespec st_mtimeX; //!< time of last modification + struct tgt_timespec st_ctimeX; //!< time of last status change + int32_t st_blksize; //!< optimal I/O block size + int64_t st_blocks; //!< number of blocks allocated + char st_fstype[16]; + }; + + /// Length of strings in struct utsname (plus 1 for null char). + static const int _SYS_NMLN = 257; + + /// Interface struct for uname(). + struct utsname { + char sysname[_SYS_NMLN]; //!< System name. + char nodename[_SYS_NMLN]; //!< Node name. + char release[_SYS_NMLN]; //!< OS release. + char version[_SYS_NMLN]; //!< OS version. + char machine[_SYS_NMLN]; //!< Machine type. + }; + + /// Limit struct for getrlimit/setrlimit. + struct rlimit { + uint64_t rlim_cur; //!< soft limit + uint64_t rlim_max; //!< hard limit + }; + + /// For gettimeofday(). + struct timeval { + int64_t tv_sec; //!< seconds + int64_t tv_usec; //!< microseconds + }; + + // For writev/readv + struct tgt_iovec { + uint64_t iov_base; // void * + uint64_t iov_len; + }; + + + /// For getrusage(). + struct rusage { + struct timeval ru_utime; //!< user time used + struct timeval ru_stime; //!< system time used + int64_t ru_maxrss; //!< max rss + int64_t ru_ixrss; //!< integral shared memory size + int64_t ru_idrss; //!< integral unshared data " + int64_t ru_isrss; //!< integral unshared stack " + int64_t ru_minflt; //!< page reclaims - total vmfaults + int64_t ru_majflt; //!< page faults + int64_t ru_nswap; //!< swaps + int64_t ru_inblock; //!< block input operations + int64_t ru_oublock; //!< block output operations + int64_t ru_msgsnd; //!< messages sent + int64_t ru_msgrcv; //!< messages received + int64_t ru_nsignals; //!< signals received + int64_t ru_nvcsw; //!< voluntary context switches + int64_t ru_nivcsw; //!< involuntary " + }; + + /// Helper function to convert a host stat buffer to a target stat + /// buffer. Also copies the target buffer out to the simulated + /// memory space. Used by stat(), fstat(), and lstat(). +#if !BSD_HOST + static void + copyOutStatBuf(TranslatingPort *mem, Addr addr, hst_stat *host) + { + using namespace TheISA; + + TypedBufferArg<Solaris::tgt_stat> tgt(addr); + + tgt->st_dev = htog(host->st_dev); + tgt->st_ino = htog(host->st_ino); + tgt->st_mode = htog(host->st_mode); + tgt->st_nlink = htog(host->st_nlink); + tgt->st_uid = htog(host->st_uid); + tgt->st_gid = htog(host->st_gid); + tgt->st_rdev = htog(host->st_rdev); + tgt->st_size = htog(host->st_size); + tgt->st_atimeX.tv_sec = htog((uint64_t)host->st_atime); + tgt->st_mtimeX.tv_sec = htog((uint64_t)host->st_mtime); + tgt->st_ctimeX.tv_sec = htog((uint64_t)host->st_ctime); +#if defined(STAT_HAVE_NSEC) + tgt->st_atimeX.tv_nsec = htog(host->st_atime_nsec); + tgt->st_mtimeX.tv_nsec = htog(host->st_mtime_nsec); + tgt->st_ctimeX.tv_nsec = htog(host->st_ctime_nsec); +#else + tgt->st_atimeX.tv_nsec = 0; + tgt->st_mtimeX.tv_nsec = 0; + tgt->st_ctimeX.tv_nsec = 0; +#endif + tgt->st_blksize = htog(host->st_blksize); + tgt->st_blocks = htog(host->st_blocks); + strncpy(tgt->st_fstype, "????", 16); + + tgt.copyOut(mem); + } +#else + // Third version for bsd systems which no longer have any support for + // the old stat() call and stat() is actually a stat64() + static void + copyOutStatBuf(TranslatingPort *mem, Addr addr, hst_stat64 *host) + { + using namespace TheISA; + + TypedBufferArg<Solaris::tgt_stat> tgt(addr); + + tgt->st_dev = htog(host->st_dev); + tgt->st_ino = htog(host->st_ino); + tgt->st_mode = htog(host->st_mode); + tgt->st_nlink = htog(host->st_nlink); + tgt->st_uid = htog(host->st_uid); + tgt->st_gid = htog(host->st_gid); + tgt->st_rdev = htog(host->st_rdev); + tgt->st_size = htog(host->st_size); + tgt->st_atimeX.tv_sec = htog((uint64_t)host->st_atime); + tgt->st_mtimeX.tv_sec = htog((uint64_t)host->st_mtime); + tgt->st_ctimeX.tv_sec = htog((uint64_t)host->st_ctime); +#if defined(STAT_HAVE_NSEC) + tgt->st_atimeX.tv_nsec = htog(host->st_atime_nsec); + tgt->st_mtimeX.tv_nsec = htog(host->st_mtime_nsec); + tgt->st_ctimeX.tv_nsec = htog(host->st_ctime_nsec); +#else + tgt->st_atimeX.tv_nsec = 0; + tgt->st_mtimeX.tv_nsec = 0; + tgt->st_ctimeX.tv_nsec = 0; +#endif + tgt->st_blksize = htog(host->st_blksize); + tgt->st_blocks = htog(host->st_blocks); + strncpy(tgt->st_fstype, "????", 16); + + tgt.copyOut(mem); + } +#endif + + + // Same for stat64 + static void + copyOutStat64Buf(TranslatingPort *mem, int fd, Addr addr, hst_stat64 *host) + { + using namespace TheISA; + + TypedBufferArg<Solaris::tgt_stat64> tgt(addr); + + // fd == 1 checks are because libc does some checks + // that the stdout is interactive vs. a file + // this makes it work on non-solaris systems + if (fd == 1) + tgt->st_dev = htog((uint64_t)0xA); + else + tgt->st_dev = htog((uint64_t)host->st_dev); + // XXX What about STAT64_HAS_BROKEN_ST_INO ??? + tgt->st_ino = htog((uint64_t)host->st_ino); + if (fd == 1) + tgt->st_rdev = htog((uint64_t)0x880d); + else + tgt->st_rdev = htog((uint64_t)host->st_rdev); + tgt->st_size = htog((int64_t)host->st_size); + tgt->st_blocks = htog((uint64_t)host->st_blocks); + + if (fd == 1) + tgt->st_mode = htog((uint32_t)0x2190); + else + tgt->st_mode = htog((uint32_t)host->st_mode); + tgt->st_uid = htog((uint32_t)host->st_uid); + tgt->st_gid = htog((uint32_t)host->st_gid); + tgt->st_blksize = htog((uint32_t)host->st_blksize); + tgt->st_nlink = htog((uint32_t)host->st_nlink); + tgt->st_atimeX.tv_sec = htog((uint64_t)host->st_atime); + tgt->st_mtimeX.tv_sec = htog((uint64_t)host->st_mtime); + tgt->st_ctimeX.tv_sec = htog((uint64_t)host->st_ctime); +#if defined(STAT_HAVE_NSEC) + tgt->st_atimeX.tv_nsec = htog(host->st_atime_nsec); + tgt->st_mtimeX.tv_nsec = htog(host->st_mtime_nsec); + tgt->st_ctimeX.tv_nsec = htog(host->st_ctime_nsec); +#else + tgt->st_atimeX.tv_nsec = 0; + tgt->st_mtimeX.tv_nsec = 0; + tgt->st_ctimeX.tv_nsec = 0; +#endif + + tgt.copyOut(mem); + } + +}; // class Solaris + + +#endif // FULL_SYSTEM + +#endif // __SOLARIS_HH__ diff --git a/src/kern/system_events.cc b/src/kern/system_events.cc new file mode 100644 index 000000000..f3b1bf91d --- /dev/null +++ b/src/kern/system_events.cc @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "cpu/base.hh" +#include "cpu/cpu_exec_context.hh" +#include "kern/kernel_stats.hh" +#include "kern/system_events.hh" +#include "sim/system.hh" + +using namespace TheISA; + +void +SkipFuncEvent::process(ExecContext *xc) +{ + Addr newpc = xc->readIntReg(ReturnAddressReg); + + DPRINTF(PCEvent, "skipping %s: pc=%x, newpc=%x\n", description, + xc->readPC(), newpc); + + xc->setPC(newpc); + xc->setNextPC(xc->readPC() + sizeof(TheISA::MachInst)); +/* + BranchPred *bp = xc->getCpuPtr()->getBranchPred(); + if (bp != NULL) { + bp->popRAS(xc->getThreadNum()); + } +*/ +} + + +FnEvent::FnEvent(PCEventQueue *q, const std::string &desc, Addr addr, + Stats::MainBin *bin) + : PCEvent(q, desc, addr), _name(desc), mybin(bin) +{ +} + +void +FnEvent::process(ExecContext *xc) +{ + if (xc->misspeculating()) + return; + + xc->getSystemPtr()->kernelBinning->call(xc, mybin); +} + +void +IdleStartEvent::process(ExecContext *xc) +{ + if (xc->getKernelStats()) + xc->getKernelStats()->setIdleProcess( + xc->readMiscReg(AlphaISA::IPR_PALtemp23), xc); + remove(); +} + +void +InterruptStartEvent::process(ExecContext *xc) +{ + if (xc->getKernelStats()) + xc->getKernelStats()->mode(Kernel::interrupt, xc); +} + +void +InterruptEndEvent::process(ExecContext *xc) +{ + // We go back to kernel, if we are user, inside the rti + // pal code we will get switched to user because of the ICM write + if (xc->getKernelStats()) + xc->getKernelStats()->mode(Kernel::kernel, xc); +} diff --git a/kern/system_events.hh b/src/kern/system_events.hh index 246140a09..246140a09 100644 --- a/kern/system_events.hh +++ b/src/kern/system_events.hh diff --git a/kern/tru64/dump_mbuf.cc b/src/kern/tru64/dump_mbuf.cc index c3c37531a..c3c37531a 100644 --- a/kern/tru64/dump_mbuf.cc +++ b/src/kern/tru64/dump_mbuf.cc diff --git a/src/kern/tru64/dump_mbuf.hh b/src/kern/tru64/dump_mbuf.hh new file mode 100644 index 000000000..9e1698ff1 --- /dev/null +++ b/src/kern/tru64/dump_mbuf.hh @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __DUMP_MBUF_HH__ +#define __DUMP_MBUF_HH__ + +#include "arch/arguments.hh" + +namespace tru64 { + void DumpMbuf(AlphaISA::AlphaArguments args); +} + +#endif // __DUMP_MBUF_HH__ diff --git a/kern/tru64/mbuf.hh b/src/kern/tru64/mbuf.hh index 93424858f..93424858f 100644 --- a/kern/tru64/mbuf.hh +++ b/src/kern/tru64/mbuf.hh diff --git a/src/kern/tru64/printf.cc b/src/kern/tru64/printf.cc new file mode 100644 index 000000000..319d36673 --- /dev/null +++ b/src/kern/tru64/printf.cc @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <algorithm> + +#include "base/cprintf.hh" +#include "base/trace.hh" +#include "sim/host.hh" +#include "arch/arguments.hh" +#include "arch/vtophys.hh" + +using namespace std; + +namespace tru64 { + +void +Printf(AlphaISA::AlphaArguments args) +{ + char *p = (char *)args++; + + ios::fmtflags saved_flags = DebugOut().flags(); + char old_fill = DebugOut().fill(); + int old_precision = DebugOut().precision(); + + while (*p) { + switch (*p) { + case '%': { + bool more = true; + bool islong = false; + bool leftjustify = false; + bool format = false; + bool zero = false; + int width = 0; + while (more && *++p) { + switch (*p) { + case 'l': + case 'L': + islong = true; + break; + case '-': + leftjustify = true; + break; + case '#': + format = true; + break; + case '0': + if (width) + width *= 10; + else + zero = true; + break; + default: + if (*p >= '1' && *p <= '9') + width = 10 * width + *p - '0'; + else + more = false; + break; + } + } + + bool hexnum = false; + bool octal = false; + bool sign = false; + switch (*p) { + case 'X': + case 'x': + hexnum = true; + break; + case 'O': + case 'o': + octal = true; + break; + case 'D': + case 'd': + sign = true; + break; + case 'P': + format = true; + case 'p': + hexnum = true; + break; + } + + switch (*p) { + case 'D': + case 'd': + case 'U': + case 'u': + case 'X': + case 'x': + case 'O': + case 'o': + case 'P': + case 'p': { + if (hexnum) + DebugOut() << hex; + + if (octal) + DebugOut() << oct; + + if (format) { + if (!zero) + DebugOut().setf(ios::showbase); + else { + if (hexnum) { + DebugOut() << "0x"; + width -= 2; + } else if (octal) { + DebugOut() << "0"; + width -= 1; + } + } + } + + if (zero) + DebugOut().fill('0'); + + if (width > 0) + DebugOut().width(width); + + if (leftjustify && !zero) + DebugOut().setf(ios::left); + + if (sign) { + if (islong) + DebugOut() << (int64_t)args; + else + DebugOut() << (int32_t)args; + } else { + if (islong) + DebugOut() << (uint64_t)args; + else + DebugOut() << (uint32_t)args; + } + + if (zero) + DebugOut().fill(' '); + + if (width > 0) + DebugOut().width(0); + + DebugOut() << dec; + + ++args; + } + break; + + case 's': { + char *s = (char *)args; + if (!s) + s = "<NULL>"; + + if (width > 0) + DebugOut().width(width); + if (leftjustify) + DebugOut().setf(ios::left); + + DebugOut() << s; + ++args; + } + break; + case 'C': + case 'c': { + uint64_t mask = (*p == 'C') ? 0xffL : 0x7fL; + uint64_t num; + int width; + + if (islong) { + num = (uint64_t)args; + width = sizeof(uint64_t); + } else { + num = (uint32_t)args; + width = sizeof(uint32_t); + } + + while (width-- > 0) { + char c = (char)(num & mask); + if (c) + DebugOut() << c; + num >>= 8; + } + + ++args; + } + break; + case 'b': { + uint64_t n = (uint64_t)args++; + char *s = (char *)args++; + DebugOut() << s << ": " << n; + } + break; + case 'n': + case 'N': { + args += 2; +#if 0 + uint64_t n = (uint64_t)args++; + struct reg_values *rv = (struct reg_values *)args++; +#endif + } + break; + case 'r': + case 'R': { + args += 2; +#if 0 + uint64_t n = (uint64_t)args++; + struct reg_desc *rd = (struct reg_desc *)args++; +#endif + } + break; + case '%': + DebugOut() << '%'; + break; + } + ++p; + } + break; + case '\n': + DebugOut() << endl; + ++p; + break; + case '\r': + ++p; + if (*p != '\n') + DebugOut() << endl; + break; + + default: { + size_t len = strcspn(p, "%\n\r\0"); + DebugOut().write(p, len); + p += len; + } + } + } + + DebugOut().flags(saved_flags); + DebugOut().fill(old_fill); + DebugOut().precision(old_precision); +} + +} // namespace Tru64 diff --git a/src/kern/tru64/printf.hh b/src/kern/tru64/printf.hh new file mode 100644 index 000000000..61236e83a --- /dev/null +++ b/src/kern/tru64/printf.hh @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __PRINTF_HH__ +#define __PRINTF_HH__ + +#include "arch/arguments.hh" + +namespace tru64 { + void Printf(AlphaISA::AlphaArguments args); +} + +#endif // __PRINTF_HH__ diff --git a/src/kern/tru64/tru64.hh b/src/kern/tru64/tru64.hh new file mode 100644 index 000000000..fff91f8ca --- /dev/null +++ b/src/kern/tru64/tru64.hh @@ -0,0 +1,1240 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __TRU64_HH__ +#define __TRU64_HH__ +#include "config/full_system.hh" + +#if FULL_SYSTEM + +class Tru64 {}; + +#else //!FULL_SYSTEM + +#include <sys/types.h> +#include <sys/stat.h> +#if defined(__OpenBSD__) || defined(__APPLE__) || defined(__FreeBSD__) +#include <sys/param.h> +#include <sys/mount.h> +#else +#include <sys/statfs.h> +#endif + +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <string.h> // for memset() +#include <unistd.h> + +#include "cpu/base.hh" +#include "sim/root.hh" +#include "sim/syscall_emul.hh" + +typedef struct stat global_stat; +typedef struct statfs global_statfs; +typedef struct dirent global_dirent; + +class TranslatingPort; + +/// +/// This class encapsulates the types, structures, constants, +/// functions, and syscall-number mappings specific to the Alpha Tru64 +/// syscall interface. +/// +class Tru64 { + + public: + + //@{ + /// Basic Tru64 types. + typedef uint64_t size_t; + typedef uint64_t off_t; + typedef uint16_t nlink_t; + typedef int32_t dev_t; + typedef uint32_t uid_t; + typedef uint32_t gid_t; + typedef uint32_t time_t; + typedef uint32_t mode_t; + typedef uint32_t ino_t; + typedef struct { int val[2]; } quad; + typedef quad fsid_t; + //@} + + /// Stat buffer. Note that Tru64 v5.0+ use a new "F64" stat + /// structure, and a new set of syscall numbers for stat calls. + /// On some hosts (notably Linux) define st_atime, st_mtime, and + /// st_ctime as macros, so we append an X to get around this. + struct F64_stat { + dev_t st_dev; //!< st_dev + int32_t st_retired1; //!< st_retired1 + mode_t st_mode; //!< st_mode + nlink_t st_nlink; //!< st_nlink + uint16_t st_nlink_reserved; //!< st_nlink_reserved + uid_t st_uid; //!< st_uid + gid_t st_gid; //!< st_gid + dev_t st_rdev; //!< st_rdev + dev_t st_ldev; //!< st_ldev + off_t st_size; //!< st_size + time_t st_retired2; //!< st_retired2 + int32_t st_uatime; //!< st_uatime + time_t st_retired3; //!< st_retired3 + int32_t st_umtime; //!< st_umtime + time_t st_retired4; //!< st_retired4 + int32_t st_uctime; //!< st_uctime + int32_t st_retired5; //!< st_retired5 + int32_t st_retired6; //!< st_retired6 + uint32_t st_flags; //!< st_flags + uint32_t st_gen; //!< st_gen + uint64_t st_spare[4]; //!< st_spare[4] + ino_t st_ino; //!< st_ino + int32_t st_ino_reserved; //!< st_ino_reserved + time_t st_atimeX; //!< st_atime + int32_t st_atime_reserved; //!< st_atime_reserved + time_t st_mtimeX; //!< st_mtime + int32_t st_mtime_reserved; //!< st_mtime_reserved + time_t st_ctimeX; //!< st_ctime + int32_t st_ctime_reserved; //!< st_ctime_reserved + uint64_t st_blksize; //!< st_blksize + uint64_t st_blocks; //!< st_blocks + }; + + + /// Old Tru64 v4.x stat struct. + /// Tru64 maintains backwards compatibility with v4.x by + /// implementing another set of stat functions using the old + /// structure definition and binding them to the old syscall + /// numbers. + + struct pre_F64_stat { + dev_t st_dev; + ino_t st_ino; + mode_t st_mode; + nlink_t st_nlink; + uid_t st_uid __attribute__ ((aligned(sizeof(uid_t)))); + gid_t st_gid; + dev_t st_rdev; + off_t st_size __attribute__ ((aligned(sizeof(off_t)))); + time_t st_atimeX; + int32_t st_uatime; + time_t st_mtimeX; + int32_t st_umtime; + time_t st_ctimeX; + int32_t st_uctime; + uint32_t st_blksize; + int32_t st_blocks; + uint32_t st_flags; + uint32_t st_gen; + }; + + /// For statfs(). + struct F64_statfs { + int16_t f_type; + int16_t f_flags; + int32_t f_retired1; + int32_t f_retired2; + int32_t f_retired3; + int32_t f_retired4; + int32_t f_retired5; + int32_t f_retired6; + int32_t f_retired7; + fsid_t f_fsid; + int32_t f_spare[9]; + char f_retired8[90]; + char f_retired9[90]; + uint64_t dummy[10]; // was union mount_info mount_info; + uint64_t f_flags2; + int64_t f_spare2[14]; + int64_t f_fsize; + int64_t f_bsize; + int64_t f_blocks; + int64_t f_bfree; + int64_t f_bavail; + int64_t f_files; + int64_t f_ffree; + char f_mntonname[1024]; + char f_mntfromname[1024]; + }; + + /// For old Tru64 v4.x statfs() + struct pre_F64_statfs { + int16_t f_type; + int16_t f_flags; + int32_t f_fsize; + int32_t f_bsize; + int32_t f_blocks; + int32_t f_bfree; + int32_t f_bavail; + int32_t f_files; + int32_t f_ffree; + fsid_t f_fsid; + int32_t f_spare[9]; + char f_mntonname[90]; + char f_mntfromname[90]; + uint64_t dummy[10]; // was union mount_info mount_info; + }; + + /// For getdirentries(). + struct dirent + { + ino_t d_ino; //!< file number of entry + uint16_t d_reclen; //!< length of this record + uint16_t d_namlen; //!< length of string in d_name + char d_name[256]; //!< dummy name length + }; + + + /// Length of strings in struct utsname (plus 1 for null char). + static const int _SYS_NMLN = 32; + + /// Interface struct for uname(). + struct utsname { + char sysname[_SYS_NMLN]; //!< System name. + char nodename[_SYS_NMLN]; //!< Node name. + char release[_SYS_NMLN]; //!< OS release. + char version[_SYS_NMLN]; //!< OS version. + char machine[_SYS_NMLN]; //!< Machine type. + }; + + /// Limit struct for getrlimit/setrlimit. + struct rlimit { + uint64_t rlim_cur; //!< soft limit + uint64_t rlim_max; //!< hard limit + }; + + + /// For getsysinfo() GSI_CPU_INFO option. + struct cpu_info { + uint32_t current_cpu; //!< current_cpu + uint32_t cpus_in_box; //!< cpus_in_box + uint32_t cpu_type; //!< cpu_type + uint32_t ncpus; //!< ncpus + uint64_t cpus_present; //!< cpus_present + uint64_t cpus_running; //!< cpus_running + uint64_t cpu_binding; //!< cpu_binding + uint64_t cpu_ex_binding; //!< cpu_ex_binding + uint32_t mhz; //!< mhz + uint32_t unused[3]; //!< future expansion + }; + + /// For gettimeofday. + struct timeval { + uint32_t tv_sec; //!< seconds + uint32_t tv_usec; //!< microseconds + }; + + /// For getrusage(). + struct rusage { + struct timeval ru_utime; //!< user time used + struct timeval ru_stime; //!< system time used + uint64_t ru_maxrss; //!< ru_maxrss + uint64_t ru_ixrss; //!< integral shared memory size + uint64_t ru_idrss; //!< integral unshared data " + uint64_t ru_isrss; //!< integral unshared stack " + uint64_t ru_minflt; //!< page reclaims - total vmfaults + uint64_t ru_majflt; //!< page faults + uint64_t ru_nswap; //!< swaps + uint64_t ru_inblock; //!< block input operations + uint64_t ru_oublock; //!< block output operations + uint64_t ru_msgsnd; //!< messages sent + uint64_t ru_msgrcv; //!< messages received + uint64_t ru_nsignals; //!< signals received + uint64_t ru_nvcsw; //!< voluntary context switches + uint64_t ru_nivcsw; //!< involuntary " + }; + + /// For sigreturn(). + struct sigcontext { + int64_t sc_onstack; //!< sigstack state to restore + int64_t sc_mask; //!< signal mask to restore + int64_t sc_pc; //!< pc at time of signal + int64_t sc_ps; //!< psl to retore + int64_t sc_regs[32]; //!< processor regs 0 to 31 + int64_t sc_ownedfp; //!< fp has been used + int64_t sc_fpregs[32]; //!< fp regs 0 to 31 + uint64_t sc_fpcr; //!< floating point control reg + uint64_t sc_fp_control; //!< software fpcr + int64_t sc_reserved1; //!< reserved for kernel + uint32_t sc_kreserved1; //!< reserved for kernel + uint32_t sc_kreserved2; //!< reserved for kernel + size_t sc_ssize; //!< stack size + caddr_t sc_sbase; //!< stack start + uint64_t sc_traparg_a0; //!< a0 argument to trap on exc + uint64_t sc_traparg_a1; //!< a1 argument to trap on exc + uint64_t sc_traparg_a2; //!< a2 argument to trap on exc + uint64_t sc_fp_trap_pc; //!< imprecise pc + uint64_t sc_fp_trigger_sum; //!< Exception summary at trigg + uint64_t sc_fp_trigger_inst; //!< Instruction at trigger pc + }; + + + + /// For table(). + struct tbl_sysinfo { + uint64_t si_user; //!< User time + uint64_t si_nice; //!< Nice time + uint64_t si_sys; //!< System time + uint64_t si_idle; //!< Idle time + uint64_t si_hz; //!< hz + uint64_t si_phz; //!< phz + uint64_t si_boottime; //!< Boot time in seconds + uint64_t wait; //!< Wait time + uint32_t si_max_procs; //!< rpb->rpb_numprocs + uint32_t pad; //!< padding + }; + + + /// For stack_create. + struct vm_stack { + // was void * + Addr address; //!< address hint + size_t rsize; //!< red zone size + size_t ysize; //!< yellow zone size + size_t gsize; //!< green zone size + size_t swap; //!< amount of swap to reserve + size_t incr; //!< growth increment + uint64_t align; //!< address alignment + uint64_t flags; //!< MAP_FIXED etc. + // was struct memalloc_attr * + Addr attr; //!< allocation policy + uint64_t reserved; //!< reserved + }; + + /// Return values for nxm calls. + enum { + KERN_NOT_RECEIVER = 7, + KERN_NOT_IN_SET = 12 + }; + + /// For nxm_task_init. + static const int NXM_TASK_INIT_VP = 2; //!< initial thread is VP + + /// Task attribute structure. + struct nxm_task_attr { + int64_t nxm_callback; //!< nxm_callback + unsigned int nxm_version; //!< nxm_version + unsigned short nxm_uniq_offset; //!< nxm_uniq_offset + unsigned short flags; //!< flags + int nxm_quantum; //!< nxm_quantum + int pad1; //!< pad1 + int64_t pad2; //!< pad2 + }; + + /// Signal set. + typedef uint64_t sigset_t; + + /// Thread state shared between user & kernel. + struct ushared_state { + sigset_t sigmask; //!< thread signal mask + sigset_t sig; //!< thread pending mask + // struct nxm_pth_state * + Addr pth_id; //!< out-of-line state + int flags; //!< shared flags +#define US_SIGSTACK 0x1 // thread called sigaltstack +#define US_ONSTACK 0x2 // thread is running on altstack +#define US_PROFILE 0x4 // thread called profil +#define US_SYSCALL 0x8 // thread in syscall +#define US_TRAP 0x10 // thread has trapped +#define US_YELLOW 0x20 // thread has mellowed yellow +#define US_YZONE 0x40 // thread has zoned out +#define US_FP_OWNED 0x80 // thread used floating point + + int cancel_state; //!< thread's cancelation state +#define US_CANCEL 0x1 // cancel pending +#define US_NOCANCEL 0X2 // synch cancel disabled +#define US_SYS_NOCANCEL 0x4 // syscall cancel disabled +#define US_ASYNC_NOCANCEL 0x8 // asynch cancel disabled +#define US_CANCEL_BITS (US_NOCANCEL|US_SYS_NOCANCEL|US_ASYNC_NOCANCEL) +#define US_CANCEL_MASK (US_CANCEL|US_NOCANCEL|US_SYS_NOCANCEL| \ + US_ASYNC_NOCANCEL) + + // These are semi-shared. They are always visible to + // the kernel but are never context-switched by the library. + + int nxm_ssig; //!< scheduler's synchronous signals + int reserved1; //!< reserved1 + int64_t nxm_active; //!< scheduler active + int64_t reserved2; //!< reserved2 + }; + + struct nxm_sched_state { + struct ushared_state nxm_u; //!< state own by user thread + unsigned int nxm_bits; //!< scheduler state / slot + int nxm_quantum; //!< quantum count-down value + int nxm_set_quantum; //!< quantum reset value + int nxm_sysevent; //!< syscall state + // struct nxm_upcall * + Addr nxm_uc_ret; //!< stack ptr of null thread + // void * + Addr nxm_tid; //!< scheduler's thread id + int64_t nxm_va; //!< page fault address + // struct nxm_pth_state * + Addr nxm_pthid; //!< id of null thread + uint64_t nxm_bound_pcs_count; //!< bound PCS thread count + int64_t pad[2]; //!< pad + }; + + /// nxm_shared. + struct nxm_shared { + int64_t nxm_callback; //!< address of upcall routine + unsigned int nxm_version; //!< version number + unsigned short nxm_uniq_offset; //!< correction factor for TEB + unsigned short pad1; //!< pad1 + int64_t space[2]; //!< future growth + struct nxm_sched_state nxm_ss[1]; //!< array of shared areas + }; + + /// nxm_slot_state_t. + enum nxm_slot_state_t { + NXM_SLOT_AVAIL, + NXM_SLOT_BOUND, + NXM_SLOT_UNBOUND, + NXM_SLOT_EMPTY + }; + + /// nxm_config_info + struct nxm_config_info { + int nxm_nslots_per_rad; //!< max number of VP slots per RAD + int nxm_nrads; //!< max number of RADs + // nxm_slot_state_t * + Addr nxm_slot_state; //!< per-VP slot state + // struct nxm_shared * + Addr nxm_rad[1]; //!< per-RAD shared areas + }; + + /// For nxm_thread_create. + enum nxm_thread_type { + NXM_TYPE_SCS = 0, + NXM_TYPE_VP = 1, + NXM_TYPE_MANAGER = 2 + }; + + /// Thread attributes. + struct nxm_thread_attr { + int version; //!< version + int type; //!< type + int cancel_flags; //!< cancel_flags + int priority; //!< priority + int policy; //!< policy + int signal_type; //!< signal_type + // void * + Addr pthid; //!< pthid + sigset_t sigmask; //!< sigmask + /// Initial register values. + struct { + uint64_t pc; //!< pc + uint64_t sp; //!< sp + uint64_t a0; //!< a0 + } registers; + uint64_t pad2[2]; //!< pad2 + }; + + /// Helper function to convert a host stat buffer to a target stat + /// buffer. Also copies the target buffer out to the simulated + /// memory space. Used by stat(), fstat(), and lstat(). + template <class T> + static void + copyOutStatBuf(TranslatingPort *mem, Addr addr, global_stat *host) + { + using namespace TheISA; + + TypedBufferArg<T> tgt(addr); + + tgt->st_dev = htog(host->st_dev); + tgt->st_ino = htog(host->st_ino); + tgt->st_mode = htog(host->st_mode); + tgt->st_nlink = htog(host->st_nlink); + tgt->st_uid = htog(host->st_uid); + tgt->st_gid = htog(host->st_gid); + tgt->st_rdev = htog(host->st_rdev); + tgt->st_size = htog(host->st_size); + tgt->st_atimeX = htog(host->st_atime); + tgt->st_mtimeX = htog(host->st_mtime); + tgt->st_ctimeX = htog(host->st_ctime); + tgt->st_blksize = htog(host->st_blksize); + tgt->st_blocks = htog(host->st_blocks); + + tgt.copyOut(mem); + } + + /// Helper function to convert a host statfs buffer to a target statfs + /// buffer. Also copies the target buffer out to the simulated + /// memory space. Used by statfs() and fstatfs(). + template <class T> + static void + copyOutStatfsBuf(TranslatingPort *mem, Addr addr, global_statfs *host) + { + using namespace TheISA; + + TypedBufferArg<T> tgt(addr); + +#if defined(__OpenBSD__) || defined(__APPLE__) || defined(__FreeBSD__) + tgt->f_type = 0; +#else + tgt->f_type = htog(host->f_type); +#endif + tgt->f_bsize = htog(host->f_bsize); + tgt->f_blocks = htog(host->f_blocks); + tgt->f_bfree = htog(host->f_bfree); + tgt->f_bavail = htog(host->f_bavail); + tgt->f_files = htog(host->f_files); + tgt->f_ffree = htog(host->f_ffree); + + // Is this as string normally? + memcpy(&tgt->f_fsid, &host->f_fsid, sizeof(host->f_fsid)); + + tgt.copyOut(mem); + } + + class F64 { + public: + static void copyOutStatBuf(TranslatingPort *mem, Addr addr, + global_stat *host) + { + Tru64::copyOutStatBuf<Tru64::F64_stat>(mem, addr, host); + } + + static void copyOutStatfsBuf(TranslatingPort *mem, Addr addr, + global_statfs *host) + { + Tru64::copyOutStatfsBuf<Tru64::F64_statfs>(mem, addr, host); + } + }; + + class PreF64 { + public: + static void copyOutStatBuf(TranslatingPort *mem, Addr addr, + global_stat *host) + { + Tru64::copyOutStatBuf<Tru64::pre_F64_stat>(mem, addr, host); + } + + static void copyOutStatfsBuf(TranslatingPort *mem, Addr addr, + global_statfs *host) + { + Tru64::copyOutStatfsBuf<Tru64::pre_F64_statfs>(mem, addr, host); + } + }; + + /// Helper function to convert a host stat buffer to an old pre-F64 + /// (4.x) target stat buffer. Also copies the target buffer out to + /// the simulated memory space. Used by pre_F64_stat(), + /// pre_F64_fstat(), and pre_F64_lstat(). + static void + copyOutPreF64StatBuf(TranslatingPort *mem, Addr addr, struct stat *host) + { + using namespace TheISA; + + TypedBufferArg<Tru64::pre_F64_stat> tgt(addr); + + tgt->st_dev = htog(host->st_dev); + tgt->st_ino = htog(host->st_ino); + tgt->st_mode = htog(host->st_mode); + tgt->st_nlink = htog(host->st_nlink); + tgt->st_uid = htog(host->st_uid); + tgt->st_gid = htog(host->st_gid); + tgt->st_rdev = htog(host->st_rdev); + tgt->st_size = htog(host->st_size); + tgt->st_atimeX = htog(host->st_atime); + tgt->st_mtimeX = htog(host->st_mtime); + tgt->st_ctimeX = htog(host->st_ctime); + tgt->st_blksize = htog(host->st_blksize); + tgt->st_blocks = htog(host->st_blocks); + + tgt.copyOut(mem); + } + + + /// The target system's hostname. + static const char *hostname; + + + /// Target getdirentries() handler. + static SyscallReturn + getdirentriesFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) + { + using namespace TheISA; + +#ifdef __CYGWIN__ + panic("getdirent not implemented on cygwin!"); +#else + int fd = process->sim_fd(xc->getSyscallArg(0)); + Addr tgt_buf = xc->getSyscallArg(1); + int tgt_nbytes = xc->getSyscallArg(2); + Addr tgt_basep = xc->getSyscallArg(3); + + char * const host_buf = new char[tgt_nbytes]; + + // just pass basep through uninterpreted. + TypedBufferArg<int64_t> basep(tgt_basep); + basep.copyIn(xc->getMemPort()); + long host_basep = (off_t)htog((int64_t)*basep); + int host_result = getdirentries(fd, host_buf, tgt_nbytes, &host_basep); + + // check for error + if (host_result < 0) { + delete [] host_buf; + return -errno; + } + + // no error: copy results back to target space + Addr tgt_buf_ptr = tgt_buf; + char *host_buf_ptr = host_buf; + char *host_buf_end = host_buf + host_result; + while (host_buf_ptr < host_buf_end) { + global_dirent *host_dp = (global_dirent *)host_buf_ptr; + int namelen = strlen(host_dp->d_name); + + // Actual size includes padded string rounded up for alignment. + // Subtract 256 for dummy char array in Tru64::dirent definition. + // Add 1 to namelen for terminating null char. + int tgt_bufsize = sizeof(Tru64::dirent) - 256 + roundUp(namelen+1, 8); + TypedBufferArg<Tru64::dirent> tgt_dp(tgt_buf_ptr, tgt_bufsize); + tgt_dp->d_ino = host_dp->d_ino; + tgt_dp->d_reclen = tgt_bufsize; + tgt_dp->d_namlen = namelen; + strcpy(tgt_dp->d_name, host_dp->d_name); + tgt_dp.copyOut(xc->getMemPort()); + + tgt_buf_ptr += tgt_bufsize; + host_buf_ptr += host_dp->d_reclen; + } + + delete [] host_buf; + + *basep = htog((int64_t)host_basep); + basep.copyOut(xc->getMemPort()); + + return tgt_buf_ptr - tgt_buf; +#endif + } + + /// Target sigreturn() handler. + static SyscallReturn + sigreturnFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) + { + using namespace TheISA; + + using TheISA::RegFile; + TypedBufferArg<Tru64::sigcontext> sc(xc->getSyscallArg(0)); + + sc.copyIn(xc->getMemPort()); + + // Restore state from sigcontext structure. + // Note that we'll advance PC <- NPC before the end of the cycle, + // so we need to restore the desired PC into NPC. + // The current regs->pc will get clobbered. + xc->setNextPC(htog(sc->sc_pc)); + + for (int i = 0; i < 31; ++i) { + xc->setIntReg(i, htog(sc->sc_regs[i])); + xc->setFloatRegBits(i, htog(sc->sc_fpregs[i])); + } + + xc->setMiscReg(TheISA::Fpcr_DepTag, htog(sc->sc_fpcr)); + + return 0; + } + + + // + // Mach syscalls -- identified by negated syscall numbers + // + + /// Create a stack region for a thread. + static SyscallReturn + stack_createFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) + { + using namespace TheISA; + + TypedBufferArg<Tru64::vm_stack> argp(xc->getSyscallArg(0)); + + argp.copyIn(xc->getMemPort()); + + // if the user chose an address, just let them have it. Otherwise + // pick one for them. + if (htog(argp->address) == 0) { + argp->address = htog(process->next_thread_stack_base); + int stack_size = (htog(argp->rsize) + htog(argp->ysize) + + htog(argp->gsize)); + process->next_thread_stack_base -= stack_size; + argp.copyOut(xc->getMemPort()); + } + + return 0; + } + + /// NXM library version stamp. + static + const int NXM_LIB_VERSION = 301003; + + /// This call sets up the interface between the user and kernel + /// schedulers by creating a shared-memory region. The shared memory + /// region has several structs, some global, some per-RAD, some per-VP. + static SyscallReturn + nxm_task_initFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) + { + using namespace std; + using namespace TheISA; + + TypedBufferArg<Tru64::nxm_task_attr> attrp(xc->getSyscallArg(0)); + TypedBufferArg<Addr> configptr_ptr(xc->getSyscallArg(1)); + + attrp.copyIn(xc->getMemPort()); + + if (gtoh(attrp->nxm_version) != NXM_LIB_VERSION) { + cerr << "nxm_task_init: thread library version mismatch! " + << "got " << attrp->nxm_version + << ", expected " << NXM_LIB_VERSION << endl; + abort(); + } + + if (gtoh(attrp->flags) != Tru64::NXM_TASK_INIT_VP) { + cerr << "nxm_task_init: bad flag value " << attrp->flags + << " (expected " << Tru64::NXM_TASK_INIT_VP << ")" << endl; + abort(); + } + + const Addr base_addr = 0x12000; // was 0x3f0000000LL; + Addr cur_addr = base_addr; // next addresses to use + // first comes the config_info struct + Addr config_addr = cur_addr; + cur_addr += sizeof(Tru64::nxm_config_info); + // next comes the per-cpu state vector + Addr slot_state_addr = cur_addr; + int slot_state_size = + process->numCpus() * sizeof(Tru64::nxm_slot_state_t); + cur_addr += slot_state_size; + // now the per-RAD state struct (we only support one RAD) + cur_addr = 0x14000; // bump up addr for alignment + Addr rad_state_addr = cur_addr; + int rad_state_size = + (sizeof(Tru64::nxm_shared) + + (process->numCpus()-1) * sizeof(Tru64::nxm_sched_state)); + cur_addr += rad_state_size; + + // now initialize a config_info struct and copy it out to user space + TypedBufferArg<Tru64::nxm_config_info> config(config_addr); + + config->nxm_nslots_per_rad = htog(process->numCpus()); + config->nxm_nrads = htog(1); // only one RAD in our system! + config->nxm_slot_state = htog(slot_state_addr); + config->nxm_rad[0] = htog(rad_state_addr); + + config.copyOut(xc->getMemPort()); + + // initialize the slot_state array and copy it out + TypedBufferArg<Tru64::nxm_slot_state_t> slot_state(slot_state_addr, + slot_state_size); + for (int i = 0; i < process->numCpus(); ++i) { + // CPU 0 is bound to the calling process; all others are available + // XXX this code should have an endian conversion, but I don't think + // it works anyway + slot_state[i] = + (i == 0) ? Tru64::NXM_SLOT_BOUND : Tru64::NXM_SLOT_AVAIL; + } + + slot_state.copyOut(xc->getMemPort()); + + // same for the per-RAD "shared" struct. Note that we need to + // allocate extra bytes for the per-VP array which is embedded at + // the end. + TypedBufferArg<Tru64::nxm_shared> rad_state(rad_state_addr, + rad_state_size); + + rad_state->nxm_callback = attrp->nxm_callback; + rad_state->nxm_version = attrp->nxm_version; + rad_state->nxm_uniq_offset = attrp->nxm_uniq_offset; + for (int i = 0; i < process->numCpus(); ++i) { + Tru64::nxm_sched_state *ssp = &rad_state->nxm_ss[i]; + ssp->nxm_u.sigmask = htog(0); + ssp->nxm_u.sig = htog(0); + ssp->nxm_u.flags = htog(0); + ssp->nxm_u.cancel_state = htog(0); + ssp->nxm_u.nxm_ssig = 0; + ssp->nxm_bits = htog(0); + ssp->nxm_quantum = attrp->nxm_quantum; + ssp->nxm_set_quantum = attrp->nxm_quantum; + ssp->nxm_sysevent = htog(0); + + if (i == 0) { + uint64_t uniq = xc->readMiscReg(TheISA::Uniq_DepTag); + ssp->nxm_u.pth_id = htog(uniq + gtoh(attrp->nxm_uniq_offset)); + ssp->nxm_u.nxm_active = htog(uniq | 1); + } + else { + ssp->nxm_u.pth_id = htog(0); + ssp->nxm_u.nxm_active = htog(0); + } + } + + rad_state.copyOut(xc->getMemPort()); + + // + // copy pointer to shared config area out to user + // + *configptr_ptr = htog(config_addr); + configptr_ptr.copyOut(xc->getMemPort()); + + // Register this as a valid address range with the process + process->nxm_start = base_addr; + process->nxm_end = cur_addr; + + return 0; + } + + /// Initialize execution context. + static void + init_exec_context(ExecContext *ec, + Tru64::nxm_thread_attr *attrp, uint64_t uniq_val) + { + using namespace TheISA; + + ec->clearArchRegs(); + + ec->setIntReg(TheISA::ArgumentReg0, gtoh(attrp->registers.a0)); + ec->setIntReg(27/*t12*/, gtoh(attrp->registers.pc)); + ec->setIntReg(TheISA::StackPointerReg, gtoh(attrp->registers.sp)); + ec->setMiscReg(TheISA::Uniq_DepTag, uniq_val); + + ec->setPC(gtoh(attrp->registers.pc)); + ec->setNextPC(gtoh(attrp->registers.pc) + sizeof(TheISA::MachInst)); + + ec->activate(); + } + + /// Create thread. + static SyscallReturn + nxm_thread_createFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) + { + using namespace std; + using namespace TheISA; + + TypedBufferArg<Tru64::nxm_thread_attr> attrp(xc->getSyscallArg(0)); + TypedBufferArg<uint64_t> kidp(xc->getSyscallArg(1)); + int thread_index = xc->getSyscallArg(2); + + // get attribute args + attrp.copyIn(xc->getMemPort()); + + if (gtoh(attrp->version) != NXM_LIB_VERSION) { + cerr << "nxm_thread_create: thread library version mismatch! " + << "got " << attrp->version + << ", expected " << NXM_LIB_VERSION << endl; + abort(); + } + + if (thread_index < 0 | thread_index > process->numCpus()) { + cerr << "nxm_thread_create: bad thread index " << thread_index + << endl; + abort(); + } + + // On a real machine, the per-RAD shared structure is in + // shared memory, so both the user and kernel can get at it. + // We don't have that luxury, so we just copy it in and then + // back out again. + int rad_state_size = + (sizeof(Tru64::nxm_shared) + + (process->numCpus()-1) * sizeof(Tru64::nxm_sched_state)); + + TypedBufferArg<Tru64::nxm_shared> rad_state(0x14000, + rad_state_size); + rad_state.copyIn(xc->getMemPort()); + + uint64_t uniq_val = gtoh(attrp->pthid) - gtoh(rad_state->nxm_uniq_offset); + + if (gtoh(attrp->type) == Tru64::NXM_TYPE_MANAGER) { + // DEC pthreads seems to always create one of these (in + // addition to N application threads), but we don't use it, + // so don't bother creating it. + + // This is supposed to be a port number. Make something up. + *kidp = htog(99); + kidp.copyOut(xc->getMemPort()); + + return 0; + } else if (gtoh(attrp->type) == Tru64::NXM_TYPE_VP) { + // A real "virtual processor" kernel thread. Need to fork + // this thread on another CPU. + Tru64::nxm_sched_state *ssp = &rad_state->nxm_ss[thread_index]; + + if (gtoh(ssp->nxm_u.nxm_active) != 0) + return (int) Tru64::KERN_NOT_RECEIVER; + + ssp->nxm_u.pth_id = attrp->pthid; + ssp->nxm_u.nxm_active = htog(uniq_val | 1); + + rad_state.copyOut(xc->getMemPort()); + + Addr slot_state_addr = 0x12000 + sizeof(Tru64::nxm_config_info); + int slot_state_size = + process->numCpus() * sizeof(Tru64::nxm_slot_state_t); + + TypedBufferArg<Tru64::nxm_slot_state_t> + slot_state(slot_state_addr, + slot_state_size); + + slot_state.copyIn(xc->getMemPort()); + + if (slot_state[thread_index] != Tru64::NXM_SLOT_AVAIL) { + cerr << "nxm_thread_createFunc: requested VP slot " + << thread_index << " not available!" << endl; + fatal(""); + } + + // XXX This should have an endian conversion but I think this code + // doesn't work anyway + slot_state[thread_index] = Tru64::NXM_SLOT_BOUND; + + slot_state.copyOut(xc->getMemPort()); + + // Find a free simulator execution context. + for (int i = 0; i < process->numCpus(); ++i) { + ExecContext *xc = process->execContexts[i]; + + if (xc->status() == ExecContext::Suspended) { + // inactive context... grab it + init_exec_context(xc, attrp, uniq_val); + + // This is supposed to be a port number, but we'll try + // and get away with just sticking the thread index + // here. + *kidp = htog(thread_index); + kidp.copyOut(xc->getMemPort()); + + return 0; + } + } + + // fell out of loop... no available inactive context + cerr << "nxm_thread_create: no idle contexts available." << endl; + abort(); + } else { + cerr << "nxm_thread_create: can't handle thread type " + << attrp->type << endl; + abort(); + } + + return 0; + } + + /// Thread idle call (like yield()). + static SyscallReturn + nxm_idleFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) + { + return 0; + } + + /// Block thread. + static SyscallReturn + nxm_thread_blockFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) + { + using namespace std; + + uint64_t tid = xc->getSyscallArg(0); + uint64_t secs = xc->getSyscallArg(1); + uint64_t flags = xc->getSyscallArg(2); + uint64_t action = xc->getSyscallArg(3); + uint64_t usecs = xc->getSyscallArg(4); + + cout << xc->getCpuPtr()->name() << ": nxm_thread_block " << tid << " " + << secs << " " << flags << " " << action << " " << usecs << endl; + + return 0; + } + + /// block. + static SyscallReturn + nxm_blockFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) + { + using namespace std; + + Addr uaddr = xc->getSyscallArg(0); + uint64_t val = xc->getSyscallArg(1); + uint64_t secs = xc->getSyscallArg(2); + uint64_t usecs = xc->getSyscallArg(3); + uint64_t flags = xc->getSyscallArg(4); + + BaseCPU *cpu = xc->getCpuPtr(); + + cout << cpu->name() << ": nxm_block " + << hex << uaddr << dec << " " << val + << " " << secs << " " << usecs + << " " << flags << endl; + + return 0; + } + + /// Unblock thread. + static SyscallReturn + nxm_unblockFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) + { + using namespace std; + + Addr uaddr = xc->getSyscallArg(0); + + cout << xc->getCpuPtr()->name() << ": nxm_unblock " + << hex << uaddr << dec << endl; + + return 0; + } + + /// Switch thread priority. + static SyscallReturn + swtch_priFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) + { + // Attempts to switch to another runnable thread (if there is + // one). Returns false if there are no other threads to run + // (i.e., the thread can reasonably spin-wait) or true if there + // are other threads. + // + // Since we assume at most one "kernel" thread per CPU, it's + // always safe to return false here. + return 0; //false; + } + + + /// Activate exec context waiting on a channel. Just activate one + /// by default. + static int + activate_waiting_context(Addr uaddr, Process *process, + bool activate_all = false) + { + using namespace std; + + int num_activated = 0; + + list<Process::WaitRec>::iterator i = process->waitList.begin(); + list<Process::WaitRec>::iterator end = process->waitList.end(); + + while (i != end && (num_activated == 0 || activate_all)) { + if (i->waitChan == uaddr) { + // found waiting process: make it active + ExecContext *newCtx = i->waitingContext; + assert(newCtx->status() == ExecContext::Suspended); + newCtx->activate(); + + // get rid of this record + i = process->waitList.erase(i); + + ++num_activated; + } else { + ++i; + } + } + + return num_activated; + } + + /// M5 hacked-up lock acquire. + static void + m5_lock_mutex(Addr uaddr, Process *process, ExecContext *xc) + { + using namespace TheISA; + + TypedBufferArg<uint64_t> lockp(uaddr); + + lockp.copyIn(xc->getMemPort()); + + if (gtoh(*lockp) == 0) { + // lock is free: grab it + *lockp = htog(1); + lockp.copyOut(xc->getMemPort()); + } else { + // lock is busy: disable until free + process->waitList.push_back(Process::WaitRec(uaddr, xc)); + xc->suspend(); + } + } + + /// M5 unlock call. + static void + m5_unlock_mutex(Addr uaddr, Process *process, ExecContext *xc) + { + TypedBufferArg<uint64_t> lockp(uaddr); + + lockp.copyIn(xc->getMemPort()); + assert(*lockp != 0); + + // Check for a process waiting on the lock. + int num_waiting = activate_waiting_context(uaddr, process); + + // clear lock field if no waiting context is taking over the lock + if (num_waiting == 0) { + *lockp = 0; + lockp.copyOut(xc->getMemPort()); + } + } + + /// Lock acquire syscall handler. + static SyscallReturn + m5_mutex_lockFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) + { + Addr uaddr = xc->getSyscallArg(0); + + m5_lock_mutex(uaddr, process, xc); + + // Return 0 since we will always return to the user with the lock + // acquired. We will just keep the context inactive until that is + // true. + return 0; + } + + /// Try lock (non-blocking). + static SyscallReturn + m5_mutex_trylockFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) + { + using namespace TheISA; + + Addr uaddr = xc->getSyscallArg(0); + TypedBufferArg<uint64_t> lockp(uaddr); + + lockp.copyIn(xc->getMemPort()); + + if (gtoh(*lockp) == 0) { + // lock is free: grab it + *lockp = htog(1); + lockp.copyOut(xc->getMemPort()); + return 0; + } else { + return 1; + } + } + + /// Unlock syscall handler. + static SyscallReturn + m5_mutex_unlockFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) + { + Addr uaddr = xc->getSyscallArg(0); + + m5_unlock_mutex(uaddr, process, xc); + + return 0; + } + + /// Signal ocndition. + static SyscallReturn + m5_cond_signalFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) + { + Addr cond_addr = xc->getSyscallArg(0); + + // Wake up one process waiting on the condition variable. + activate_waiting_context(cond_addr, process); + + return 0; + } + + /// Wake up all processes waiting on the condition variable. + static SyscallReturn + m5_cond_broadcastFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) + { + Addr cond_addr = xc->getSyscallArg(0); + + activate_waiting_context(cond_addr, process, true); + + return 0; + } + + /// Wait on a condition. + static SyscallReturn + m5_cond_waitFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) + { + using namespace TheISA; + + Addr cond_addr = xc->getSyscallArg(0); + Addr lock_addr = xc->getSyscallArg(1); + TypedBufferArg<uint64_t> condp(cond_addr); + TypedBufferArg<uint64_t> lockp(lock_addr); + + // user is supposed to acquire lock before entering + lockp.copyIn(xc->getMemPort()); + assert(gtoh(*lockp) != 0); + + m5_unlock_mutex(lock_addr, process, xc); + + process->waitList.push_back(Process::WaitRec(cond_addr, xc)); + xc->suspend(); + + return 0; + } + + /// Thread exit. + static SyscallReturn + m5_thread_exitFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) + { + assert(xc->status() == ExecContext::Active); + xc->deallocate(); + + return 0; + } + + /// Indirect syscall invocation (call #0). + static SyscallReturn + indirectSyscallFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) + { + int new_callnum = xc->getSyscallArg(0); + LiveProcess *lp = dynamic_cast<LiveProcess*>(process); + assert(lp); + + for (int i = 0; i < 5; ++i) + xc->setSyscallArg(i, xc->getSyscallArg(i+1)); + + + SyscallDesc *new_desc = lp->getDesc(new_callnum); + if (desc == NULL) + fatal("Syscall %d out of range", callnum); + + new_desc->doSyscall(new_callnum, process, xc); + + return 0; + } + +}; // class Tru64 + + +#endif // FULL_SYSTEM + +#endif // __TRU64_HH__ diff --git a/src/kern/tru64/tru64_events.cc b/src/kern/tru64/tru64_events.cc new file mode 100644 index 000000000..69fc5c55d --- /dev/null +++ b/src/kern/tru64/tru64_events.cc @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "cpu/exec_context.hh" +#include "cpu/base.hh" +#include "kern/system_events.hh" +#include "kern/tru64/tru64_events.hh" +#include "kern/tru64/dump_mbuf.hh" +#include "kern/tru64/printf.hh" +#include "arch/alpha/ev5.hh" +#include "arch/arguments.hh" +#include "arch/isa_traits.hh" +#include "sim/system.hh" + +using namespace TheISA; + +//void SkipFuncEvent::process(ExecContext *xc); + +void +BadAddrEvent::process(ExecContext *xc) +{ + // The following gross hack is the equivalent function to the + // annotation for vmunix::badaddr in: + // simos/simulation/apps/tcl/osf/tlaser.tcl + + uint64_t a0 = xc->readIntReg(ArgumentReg0); + + AddrRangeList resp; + AddrRangeList snoop; + AddrRangeIter iter; + bool found = false; + + xc->getPhysPort()->getPeerAddressRanges(resp, snoop); + for(iter = resp.begin(); iter != resp.end(); iter++) + { + if (*iter == (TheISA::K0Seg2Phys(a0) & EV5::PAddrImplMask)) + found = true; + } + + if (!TheISA::IsK0Seg(a0) || found ) { + + DPRINTF(BADADDR, "badaddr arg=%#x bad\n", a0); + xc->setIntReg(ReturnValueReg, 0x1); + SkipFuncEvent::process(xc); + } + else + DPRINTF(BADADDR, "badaddr arg=%#x good\n", a0); +} + +void +PrintfEvent::process(ExecContext *xc) +{ + if (DTRACE(Printf)) { + DebugOut() << curTick << ": " << xc->getCpuPtr()->name() << ": "; + + AlphaArguments args(xc); + tru64::Printf(args); + } +} + +void +DebugPrintfEvent::process(ExecContext *xc) +{ + if (DTRACE(DebugPrintf)) { + if (!raw) + DebugOut() << curTick << ": " << xc->getCpuPtr()->name() << ": "; + + AlphaArguments args(xc); + tru64::Printf(args); + } +} + +void +DumpMbufEvent::process(ExecContext *xc) +{ + if (DTRACE(DebugPrintf)) { + AlphaArguments args(xc); + tru64::DumpMbuf(args); + } +} diff --git a/kern/tru64/tru64_events.hh b/src/kern/tru64/tru64_events.hh index 9b5bcfea2..9b5bcfea2 100644 --- a/kern/tru64/tru64_events.hh +++ b/src/kern/tru64/tru64_events.hh diff --git a/kern/tru64/tru64_syscalls.cc b/src/kern/tru64/tru64_syscalls.cc index 8aa57dbaa..8aa57dbaa 100644 --- a/kern/tru64/tru64_syscalls.cc +++ b/src/kern/tru64/tru64_syscalls.cc diff --git a/kern/tru64/tru64_syscalls.hh b/src/kern/tru64/tru64_syscalls.hh index 69fa9101c..69fa9101c 100644 --- a/kern/tru64/tru64_syscalls.hh +++ b/src/kern/tru64/tru64_syscalls.hh diff --git a/src/mem/bridge.cc b/src/mem/bridge.cc new file mode 100644 index 000000000..736e8dc81 --- /dev/null +++ b/src/mem/bridge.cc @@ -0,0 +1,263 @@ + +/* + * Copyright (c) 2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file Definition of a simple bus bridge without buffering. + */ + +#include <algorithm> + +#include "base/trace.hh" +#include "mem/bridge.hh" +#include "sim/builder.hh" + +Bridge::BridgePort::BridgePort(const std::string &_name, + Bridge *_bridge, BridgePort *_otherPort, + int _delay, int _queueLimit) + : Port(_name), bridge(_bridge), otherPort(_otherPort), + delay(_delay), outstandingResponses(0), + queueLimit(_queueLimit), sendEvent(this) +{ +} + +Bridge::Bridge(const std::string &n, int qsa, int qsb, + Tick _delay, int write_ack) + : MemObject(n), + portA(n + "-portA", this, &portB, _delay, qsa), + portB(n + "-portB", this, &portA, _delay, qsa), + ackWrites(write_ack) +{ +} + +Port * +Bridge::getPort(const std::string &if_name) +{ + BridgePort *port; + + if (if_name == "side_a") + port = &portA; + else if (if_name == "side_b") + port = &portB; + else + return NULL; + + if (port->getPeer() != NULL) + panic("bridge side %s already connected to.", if_name); + return port; +} + + +void +Bridge::init() +{ + // Make sure that both sides are connected to. + if (portA.getPeer() == NULL || portB.getPeer() == NULL) + panic("Both ports of bus bridge are not connected to a bus.\n"); +} + + +/** Function called by the port when the bus is receiving a Timing + * transaction.*/ +bool +Bridge::BridgePort::recvTiming(Packet *pkt) +{ + DPRINTF(BusBridge, "recvTiming: src %d dest %d addr 0x%x\n", + pkt->getSrc(), pkt->getDest(), pkt->getAddr()); + + if (pkt->isResponse()) { + // This is a response for a request we forwarded earlier. The + // corresponding PacketBuffer should be stored in the packet's + // senderState field. + PacketBuffer *buf = dynamic_cast<PacketBuffer*>(pkt->senderState); + assert(buf != NULL); + // set up new packet dest & senderState based on values saved + // from original request + buf->fixResponse(pkt); + DPRINTF(BusBridge, " is response, new dest %d\n", pkt->getDest()); + delete buf; + } + + return otherPort->queueForSendTiming(pkt); +} + + +bool +Bridge::BridgePort::queueForSendTiming(Packet *pkt) +{ + if (queueFull()) + return false; + + Tick readyTime = curTick + delay; + PacketBuffer *buf = new PacketBuffer(pkt, readyTime); + + // If we're about to put this packet at the head of the queue, we + // need to schedule an event to do the transmit. Otherwise there + // should already be an event scheduled for sending the head + // packet. + if (sendQueue.empty()) { + sendEvent.schedule(readyTime); + } + + sendQueue.push_back(buf); + + // Did we just become blocked? If yes, let other side know. + if (queueFull()) + otherPort->sendStatusChange(Port::Blocked); + + return true; +} + + +void +Bridge::BridgePort::finishSend(PacketBuffer *buf) +{ + if (buf->expectResponse) { + // Must wait for response. We just need to count outstanding + // responses (in case we want to cap them); PacketBuffer + // pointer will be recovered on response. + ++outstandingResponses; + DPRINTF(BusBridge, " successful: awaiting response (%d)\n", + outstandingResponses); + } else { + // no response expected... deallocate packet buffer now. + DPRINTF(BusBridge, " successful: no response expected\n"); + delete buf; + } + + // If there are more packets to send, schedule event to try again. + if (!sendQueue.empty()) { + buf = sendQueue.front(); + sendEvent.schedule(std::max(buf->ready, curTick + 1)); + } +} + + +void +Bridge::BridgePort::trySend() +{ + assert(!sendQueue.empty()); + + PacketBuffer *buf = sendQueue.front(); + + assert(buf->ready <= curTick); + + Packet *pkt = buf->pkt; + + DPRINTF(BusBridge, "trySend: origSrc %d dest %d addr 0x%x\n", + buf->origSrc, pkt->getDest(), pkt->getAddr()); + + if (sendTiming(pkt)) { + // send successful + sendQueue.pop_front(); + buf->pkt = NULL; // we no longer own packet, so it's not safe to look at it + finishSend(buf); + } else { + DPRINTF(BusBridge, " unsuccessful\n"); + } +} + + +Packet * +Bridge::BridgePort::recvRetry() +{ + PacketBuffer *buf = sendQueue.front(); + Packet *pkt = buf->pkt; + finishSend(buf); + return pkt; +} + +/** Function called by the port when the bus is receiving a Atomic + * transaction.*/ +Tick +Bridge::BridgePort::recvAtomic(Packet *pkt) +{ + return otherPort->sendAtomic(pkt) + delay; +} + +/** Function called by the port when the bus is receiving a Functional + * transaction.*/ +void +Bridge::BridgePort::recvFunctional(Packet *pkt) +{ + std::list<PacketBuffer*>::iterator i; + bool pktContinue = true; + + for (i = sendQueue.begin(); i != sendQueue.end(); ++i) { + if (pkt->intersect((*i)->pkt)) { + pktContinue &= fixPacket(pkt, (*i)->pkt); + } + } + + if (pktContinue) { + otherPort->sendFunctional(pkt); + } +} + +/** Function called by the port when the bus is receiving a status change.*/ +void +Bridge::BridgePort::recvStatusChange(Port::Status status) +{ + if (status == Port::Blocked || status == Port::Unblocked) + return; + + otherPort->sendStatusChange(status); +} + +void +Bridge::BridgePort::getDeviceAddressRanges(AddrRangeList &resp, + AddrRangeList &snoop) +{ + otherPort->getPeerAddressRanges(resp, snoop); +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bridge) + + Param<int> queue_size_a; + Param<int> queue_size_b; + Param<Tick> delay; + Param<bool> write_ack; + +END_DECLARE_SIM_OBJECT_PARAMS(Bridge) + +BEGIN_INIT_SIM_OBJECT_PARAMS(Bridge) + + INIT_PARAM(queue_size_a, "The size of the queue for data coming into side a"), + INIT_PARAM(queue_size_b, "The size of the queue for data coming into side b"), + INIT_PARAM(delay, "The miminum delay to cross this bridge"), + INIT_PARAM(write_ack, "Acknowledge any writes that are received.") + +END_INIT_SIM_OBJECT_PARAMS(Bridge) + +CREATE_SIM_OBJECT(Bridge) +{ + return new Bridge(getInstanceName(), queue_size_a, queue_size_b, delay, + write_ack); +} + +REGISTER_SIM_OBJECT("Bridge", Bridge) diff --git a/src/mem/bridge.hh b/src/mem/bridge.hh new file mode 100644 index 000000000..8a5cbf92a --- /dev/null +++ b/src/mem/bridge.hh @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file Decleration of a simple bus bridge object with no buffering + */ + +#ifndef __MEM_BRIDGE_HH__ +#define __MEM_BRIDGE_HH__ + +#include <string> +#include <list> +#include <inttypes.h> +#include <queue> + + +#include "mem/mem_object.hh" +#include "mem/packet.hh" +#include "mem/port.hh" +#include "sim/eventq.hh" + +class Bridge : public MemObject +{ + protected: + /** Decleration of the buses port type, one will be instantiated for each + of the interfaces connecting to the bus. */ + class BridgePort : public Port + { + /** A pointer to the bridge to which this port belongs. */ + Bridge *bridge; + + /** + * Pointer to the port on the other side of the bridge + * (connected to the other bus). + */ + BridgePort *otherPort; + + /** Minimum delay though this bridge. */ + Tick delay; + + class PacketBuffer : public Packet::SenderState { + + public: + Tick ready; + Packet *pkt; + Packet::SenderState *origSenderState; + short origSrc; + bool expectResponse; + + PacketBuffer(Packet *_pkt, Tick t) + : ready(t), pkt(_pkt), + origSenderState(_pkt->senderState), origSrc(_pkt->getSrc()), + expectResponse(_pkt->needsResponse()) + { + pkt->senderState = this; + } + + void fixResponse(Packet *pkt) + { + assert(pkt->senderState == this); + pkt->setDest(origSrc); + pkt->senderState = origSenderState; + } + }; + + /** + * Outbound packet queue. Packets are held in this queue for a + * specified delay to model the processing delay of the + * bridge. + */ + std::list<PacketBuffer*> sendQueue; + + int outstandingResponses; + + /** Max queue size for outbound packets */ + int queueLimit; + + /** + * Is this side blocked from accepting outbound packets? + */ + bool queueFull() { return (sendQueue.size() == queueLimit); } + + bool queueForSendTiming(Packet *pkt); + + void finishSend(PacketBuffer *buf); + + /** + * Handle send event, scheduled when the packet at the head of + * the outbound queue is ready to transmit (for timing + * accesses only). + */ + void trySend(); + + class SendEvent : public Event + { + BridgePort *port; + + public: + SendEvent(BridgePort *p) + : Event(&mainEventQueue), port(p) {} + + virtual void process() { port->trySend(); } + + virtual const char *description() { return "bridge send event"; } + }; + + SendEvent sendEvent; + + public: + + /** Constructor for the BusPort.*/ + BridgePort(const std::string &_name, + Bridge *_bridge, BridgePort *_otherPort, + int _delay, int _queueLimit); + + protected: + + /** When receiving a timing request from the peer port, + pass it to the bridge. */ + virtual bool recvTiming(Packet *pkt); + + /** When receiving a retry request from the peer port, + pass it to the bridge. */ + virtual Packet* recvRetry(); + + /** When receiving a Atomic requestfrom the peer port, + pass it to the bridge. */ + virtual Tick recvAtomic(Packet *pkt); + + /** When receiving a Functional request from the peer port, + pass it to the bridge. */ + virtual void recvFunctional(Packet *pkt); + + /** When receiving a status changefrom the peer port, + pass it to the bridge. */ + virtual void recvStatusChange(Status status); + + /** When receiving a address range request the peer port, + pass it to the bridge. */ + virtual void getDeviceAddressRanges(AddrRangeList &resp, + AddrRangeList &snoop); + }; + + BridgePort portA, portB; + + /** If this bridge should acknowledge writes. */ + bool ackWrites; + + public: + + /** A function used to return the port associated with this bus object. */ + virtual Port *getPort(const std::string &if_name); + + virtual void init(); + + Bridge(const std::string &n, int qsa, int qsb, Tick _delay, int write_ack); +}; + +#endif //__MEM_BUS_HH__ diff --git a/src/mem/bus.cc b/src/mem/bus.cc new file mode 100644 index 000000000..cfc99a64f --- /dev/null +++ b/src/mem/bus.cc @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file Definition of a bus object. + */ + + +#include "base/trace.hh" +#include "mem/bus.hh" +#include "sim/builder.hh" + +Port * +Bus::getPort(const std::string &if_name) +{ + // if_name ignored? forced to be empty? + int id = interfaces.size(); + BusPort *bp = new BusPort(csprintf("%s-p%d", name(), id), this, id); + interfaces.push_back(bp); + return bp; +} + +/** Get the ranges of anyone that we are connected to. */ +void +Bus::init() +{ + std::vector<Port*>::iterator intIter; + for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++) + (*intIter)->sendStatusChange(Port::RangeChange); +} + + +/** Function called by the port when the bus is receiving a Timing + * transaction.*/ +bool +Bus::recvTiming(Packet *pkt) +{ + Port *port; + DPRINTF(Bus, "recvTiming: packet src %d dest %d addr 0x%x cmd %s\n", + pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); + + short dest = pkt->getDest(); + if (dest == Packet::Broadcast) { + port = findPort(pkt->getAddr(), pkt->getSrc()); + } else { + assert(dest >= 0 && dest < interfaces.size()); + assert(dest != pkt->getSrc()); // catch infinite loops + port = interfaces[dest]; + } + return port->sendTiming(pkt); +} + +Port * +Bus::findPort(Addr addr, int id) +{ + /* An interval tree would be a better way to do this. --ali. */ + int dest_id = -1; + int i = 0; + bool found = false; + + while (i < portList.size() && !found) + { + if (portList[i].range == addr) { + dest_id = portList[i].portId; + found = true; + DPRINTF(Bus, " found addr 0x%llx on device %d\n", addr, dest_id); + } + i++; + } + if (dest_id == -1) + panic("Unable to find destination for addr: %llx", addr); + + // we shouldn't be sending this back to where it came from + assert(dest_id != id); + + return interfaces[dest_id]; +} + +/** Function called by the port when the bus is receiving a Atomic + * transaction.*/ +Tick +Bus::recvAtomic(Packet *pkt) +{ + DPRINTF(Bus, "recvAtomic: packet src %d dest %d addr 0x%x cmd %s\n", + pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); + assert(pkt->getDest() == Packet::Broadcast); + return findPort(pkt->getAddr(), pkt->getSrc())->sendAtomic(pkt); +} + +/** Function called by the port when the bus is receiving a Functional + * transaction.*/ +void +Bus::recvFunctional(Packet *pkt) +{ + DPRINTF(Bus, "recvFunctional: packet src %d dest %d addr 0x%x cmd %s\n", + pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); + assert(pkt->getDest() == Packet::Broadcast); + findPort(pkt->getAddr(), pkt->getSrc())->sendFunctional(pkt); +} + +/** Function called by the port when the bus is receiving a status change.*/ +void +Bus::recvStatusChange(Port::Status status, int id) +{ + assert(status == Port::RangeChange && + "The other statuses need to be implemented."); + + DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", id); + + assert(id < interfaces.size() && id >= 0); + int x; + Port *port = interfaces[id]; + AddrRangeList ranges; + AddrRangeList snoops; + AddrRangeIter iter; + std::vector<DevMap>::iterator portIter; + + // Clean out any previously existent ids + for (portIter = portList.begin(); portIter != portList.end(); ) { + if (portIter->portId == id) + portIter = portList.erase(portIter); + else + portIter++; + } + + port->getPeerAddressRanges(ranges, snoops); + + // not dealing with snooping yet either + assert(snoops.size() == 0); + for(iter = ranges.begin(); iter != ranges.end(); iter++) { + DevMap dm; + dm.portId = id; + dm.range = *iter; + + DPRINTF(BusAddrRanges, "Adding range %llx - %llx for id %d\n", + dm.range.start, dm.range.end, id); + portList.push_back(dm); + } + DPRINTF(MMU, "port list has %d entries\n", portList.size()); + + // tell all our peers that our address range has changed. + // Don't tell the device that caused this change, it already knows + for (x = 0; x < interfaces.size(); x++) + if (x != id) + interfaces[x]->sendStatusChange(Port::RangeChange); +} + +void +Bus::addressRanges(AddrRangeList &resp, AddrRangeList &snoop, int id) +{ + std::vector<DevMap>::iterator portIter; + + resp.clear(); + snoop.clear(); + + DPRINTF(BusAddrRanges, "received address range request, returning:\n"); + for (portIter = portList.begin(); portIter != portList.end(); portIter++) { + if (portIter->portId != id) { + resp.push_back(portIter->range); + DPRINTF(BusAddrRanges, " -- %#llX : %#llX\n", + portIter->range.start, portIter->range.end); + } + } +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bus) + + Param<int> bus_id; + +END_DECLARE_SIM_OBJECT_PARAMS(Bus) + +BEGIN_INIT_SIM_OBJECT_PARAMS(Bus) + INIT_PARAM(bus_id, "a globally unique bus id") +END_INIT_SIM_OBJECT_PARAMS(Bus) + +CREATE_SIM_OBJECT(Bus) +{ + return new Bus(getInstanceName(), bus_id); +} + +REGISTER_SIM_OBJECT("Bus", Bus) diff --git a/src/mem/bus.hh b/src/mem/bus.hh new file mode 100644 index 000000000..5eeb07904 --- /dev/null +++ b/src/mem/bus.hh @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file Decleration of a bus object. + */ + +#ifndef __MEM_BUS_HH__ +#define __MEM_BUS_HH__ + +#include <string> +#include <list> +#include <inttypes.h> + +#include "base/range.hh" +#include "mem/mem_object.hh" +#include "mem/packet.hh" +#include "mem/port.hh" +#include "mem/request.hh" + +class Bus : public MemObject +{ + /** a globally unique id for this bus. */ + int busId; + + struct DevMap { + int portId; + Range<Addr> range; + }; + std::vector<DevMap> portList; + + + /** Function called by the port when the bus is recieving a Timing + transaction.*/ + bool recvTiming(Packet *pkt); + + /** Function called by the port when the bus is recieving a Atomic + transaction.*/ + Tick recvAtomic(Packet *pkt); + + /** Function called by the port when the bus is recieving a Functional + transaction.*/ + void recvFunctional(Packet *pkt); + + /** Function called by the port when the bus is recieving a status change.*/ + void recvStatusChange(Port::Status status, int id); + + /** Find which port connected to this bus (if any) should be given a packet + * with this address. + * @param addr Address to find port for. + * @param id Id of the port this packet was received from (to prevent + * loops) + * @return pointer to port that the packet should be sent out of. + */ + Port *findPort(Addr addr, int id); + + /** Process address range request. + * @param resp addresses that we can respond to + * @param snoop addresses that we would like to snoop + * @param id ide of the busport that made the request. + */ + void addressRanges(AddrRangeList &resp, AddrRangeList &snoop, int id); + + + /** Decleration of the buses port type, one will be instantiated for each + of the interfaces connecting to the bus. */ + class BusPort : public Port + { + /** A pointer to the bus to which this port belongs. */ + Bus *bus; + + /** A id to keep track of the intercafe ID this port is connected to. */ + int id; + + public: + + /** Constructor for the BusPort.*/ + BusPort(const std::string &_name, Bus *_bus, int _id) + : Port(_name), bus(_bus), id(_id) + { } + + protected: + + /** When reciving a timing request from the peer port (at id), + pass it to the bus. */ + virtual bool recvTiming(Packet *pkt) + { pkt->setSrc(id); return bus->recvTiming(pkt); } + + /** When reciving a Atomic requestfrom the peer port (at id), + pass it to the bus. */ + virtual Tick recvAtomic(Packet *pkt) + { pkt->setSrc(id); return bus->recvAtomic(pkt); } + + /** When reciving a Functional requestfrom the peer port (at id), + pass it to the bus. */ + virtual void recvFunctional(Packet *pkt) + { pkt->setSrc(id); bus->recvFunctional(pkt); } + + /** When reciving a status changefrom the peer port (at id), + pass it to the bus. */ + virtual void recvStatusChange(Status status) + { bus->recvStatusChange(status, id); } + + // This should return all the 'owned' addresses that are + // downstream from this bus, yes? That is, the union of all + // the 'owned' address ranges of all the other interfaces on + // this bus... + virtual void getDeviceAddressRanges(AddrRangeList &resp, + AddrRangeList &snoop) + { bus->addressRanges(resp, snoop, id); } + + // Hack to make translating port work without changes + virtual int deviceBlockSize() { return 32; } + + }; + + /** An array of pointers to the peer port interfaces + connected to this bus.*/ + std::vector<Port*> interfaces; + + public: + + /** A function used to return the port associated with this bus object. */ + virtual Port *getPort(const std::string &if_name); + + virtual void init(); + + Bus(const std::string &n, int bus_id) + : MemObject(n), busId(bus_id) {} + +}; + +#endif //__MEM_BUS_HH__ diff --git a/mem/cache/prefetch/tagged_prefetcher_impl.hh b/src/mem/cache/prefetch/tagged_prefetcher_impl.hh index 6c27256a9..6c27256a9 100644 --- a/mem/cache/prefetch/tagged_prefetcher_impl.hh +++ b/src/mem/cache/prefetch/tagged_prefetcher_impl.hh diff --git a/mem/config/prefetch.hh b/src/mem/config/prefetch.hh index 03eb570f0..03eb570f0 100644 --- a/mem/config/prefetch.hh +++ b/src/mem/config/prefetch.hh diff --git a/src/mem/mem_object.cc b/src/mem/mem_object.cc new file mode 100644 index 000000000..f579a0727 --- /dev/null +++ b/src/mem/mem_object.cc @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mem/mem_object.hh" +#include "sim/param.hh" + +MemObject::MemObject(const std::string &name) + : SimObject(name) +{ +} + +DEFINE_SIM_OBJECT_CLASS_NAME("MemObject", MemObject) diff --git a/src/mem/mem_object.hh b/src/mem/mem_object.hh new file mode 100644 index 000000000..58930eccc --- /dev/null +++ b/src/mem/mem_object.hh @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * Base Memory Object decleration. + */ + +#ifndef __MEM_MEM_OBJECT_HH__ +#define __MEM_MEM_OBJECT_HH__ + +#include "sim/sim_object.hh" +#include "mem/port.hh" + +/** + * The base MemoryObject class, allows for an accesor function to a + * simobj that returns the Port. + */ +class MemObject : public SimObject +{ + public: + MemObject(const std::string &name); + + public: + /** Additional function to return the Port of a memory object. */ + virtual Port *getPort(const std::string &if_name) = 0; +}; + +#endif //__MEM_MEM_OBJECT_HH__ diff --git a/src/mem/packet.cc b/src/mem/packet.cc new file mode 100644 index 000000000..3b415d77f --- /dev/null +++ b/src/mem/packet.cc @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * Definition of the Packet Class, a packet is a transaction occuring + * between a single level of the memory heirarchy (ie L1->L2). + */ +#include "base/misc.hh" +#include "mem/packet.hh" + +static const std::string ReadReqString("ReadReq"); +static const std::string WriteReqString("WriteReq"); +static const std::string WriteReqNoAckString("WriteReqNoAck"); +static const std::string ReadRespString("ReadResp"); +static const std::string WriteRespString("WriteResp"); +static const std::string OtherCmdString("<other>"); + +const std::string & +Packet::cmdString() const +{ + switch (cmd) { + case ReadReq: return ReadReqString; + case WriteReq: return WriteReqString; + case WriteReqNoAck: return WriteReqNoAckString; + case ReadResp: return ReadRespString; + case WriteResp: return WriteRespString; + default: return OtherCmdString; + } +} + +/** delete the data pointed to in the data pointer. Ok to call to matter how + * data was allocted. */ +void +Packet::deleteData() +{ + assert(staticData || dynamicData); + if (staticData) + return; + + if (arrayData) + delete [] data; + else + delete data; +} + +/** If there isn't data in the packet, allocate some. */ +void +Packet::allocate() +{ + if (data) + return; + assert(!staticData); + dynamicData = true; + arrayData = true; + data = new uint8_t[getSize()]; +} + +/** Do the packet modify the same addresses. */ +bool +Packet::intersect(Packet *p) +{ + Addr s1 = getAddr(); + Addr e1 = getAddr() + getSize(); + Addr s2 = p->getAddr(); + Addr e2 = p->getAddr() + p->getSize(); + + if (s1 >= s2 && s1 < e2) + return true; + if (e1 >= s2 && e1 < e2) + return true; + return false; +} + +/** Minimally reset a packet so something like simple cpu can reuse it. */ +void +Packet::reset() +{ + result = Unknown; + if (dynamicData) { + deleteData(); + dynamicData = false; + arrayData = false; + time = curTick; + } +} + + +bool +fixPacket(Packet *func, Packet *timing) +{ + panic("Need to implement!"); +} diff --git a/src/mem/packet.hh b/src/mem/packet.hh new file mode 100644 index 000000000..83f52ede5 --- /dev/null +++ b/src/mem/packet.hh @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * Declaration of the Packet Class, a packet is a transaction occuring + * between a single level of the memory heirarchy (ie L1->L2). + */ + +#ifndef __MEM_PACKET_HH__ +#define __MEM_PACKET_HH__ + +#include "mem/request.hh" +#include "arch/isa_traits.hh" +#include "sim/root.hh" + +struct Packet; +typedef Packet* PacketPtr; +typedef uint8_t* PacketDataPtr; + +/** + * A Packet is the structure to handle requests between two levels + * of the memory system. The Request is a global object that trancends + * all of the memory heirarchy, but at each levels interface a packet + * is created to transfer data/requests. For example, a request would + * be used to initiate a request to go to memory/IOdevices, as the request + * passes through the memory system several packets will be created. One + * will be created to go between the L1 and L2 caches and another to go to + * the next level and so forth. + * + * Packets are assumed to be returned in the case of a single response. If + * the transaction has no response, then the consumer will delete the packet. + */ +class Packet +{ + private: + /** A pointer to the data being transfered. It can be differnt sizes + at each level of the heirarchy so it belongs in the packet, + not request. This may or may not be populated when a responder recieves + the packet. If not populated it memory should be allocated. + */ + PacketDataPtr data; + + /** Is the data pointer set to a value that shouldn't be freed when the + * packet is destroyed? */ + bool staticData; + /** The data pointer points to a value that should be freed when the packet + * is destroyed. */ + bool dynamicData; + /** the data pointer points to an array (thus delete [] ) needs to be called + * on it rather than simply delete.*/ + bool arrayData; + + + /** The address of the request, could be virtual or physical (depending on + cache configurations). */ + Addr addr; + + /** Indicates the size of the request. */ + int size; + + /** A index of the source of the transaction. */ + short src; + + /** A index to the destination of the transaction. */ + short dest; + + bool addrValid; + bool sizeValid; + bool srcValid; + + public: + + static const short Broadcast = -1; + + /** A pointer to the overall request. */ + RequestPtr req; + + class CoherenceState { + public: + virtual ~CoherenceState() {} + }; + + /** A virtual base opaque structure used to hold + coherence status messages. */ + CoherenceState *coherence; // virtual base opaque, + // assert(dynamic_cast<Foo>) etc. + + class SenderState { + public: + virtual ~SenderState() {} + }; + + /** A virtual base opaque structure used to hold the senders state. */ + SenderState *senderState; // virtual base opaque, + // assert(dynamic_cast<Foo>) etc. + + private: + /** List of command attributes. */ + enum CommandAttribute + { + IsRead = 1 << 0, + IsWrite = 1 << 1, + IsPrefetch = 1 << 2, + IsInvalidate = 1 << 3, + IsRequest = 1 << 4, + IsResponse = 1 << 5, + NeedsResponse = 1 << 6, + }; + + public: + /** List of all commands associated with a packet. */ + enum Command + { + ReadReq = IsRead | IsRequest | NeedsResponse, + WriteReq = IsWrite | IsRequest | NeedsResponse, + WriteReqNoAck = IsWrite | IsRequest, + ReadResp = IsRead | IsResponse, + WriteResp = IsWrite | IsResponse + }; + + const std::string &cmdString() const; + + /** The command of the transaction. */ + Command cmd; + + bool isRead() { return (cmd & IsRead) != 0; } + bool isRequest() { return (cmd & IsRequest) != 0; } + bool isResponse() { return (cmd & IsResponse) != 0; } + bool needsResponse() { return (cmd & NeedsResponse) != 0; } + + void makeTimingResponse() { + assert(needsResponse()); + int icmd = (int)cmd; + icmd &= ~(IsRequest | NeedsResponse); + icmd |= IsResponse; + cmd = (Command)icmd; + dest = src; + srcValid = false; + } + + /** The time this request was responded to. Used to calculate latencies. */ + Tick time; + + /** The result of a particular packets request. */ + enum Result + { + Success, + BadAddress, + Unknown + }; + + /** The result of the packet transaction. */ + Result result; + + /** Accessor function that returns the source index of the packet. */ + short getSrc() const { assert(srcValid); return src; } + void setSrc(short _src) { src = _src; srcValid = true; } + + /** Accessor function that returns the destination index of + the packet. */ + short getDest() const { return dest; } + void setDest(short _dest) { dest = _dest; } + + Addr getAddr() const { assert(addrValid); return addr; } + void setAddr(Addr _addr) { addr = _addr; addrValid = true; } + + int getSize() const { assert(sizeValid); return size; } + void setSize(int _size) { size = _size; sizeValid = true; } + + + Packet(Request *_req, Command _cmd, short _dest) + : data(NULL), staticData(false), dynamicData(false), arrayData(false), + addr(_req->paddr), size(_req->size), dest(_dest), + addrValid(_req->validPaddr), sizeValid(_req->validSize), + srcValid(false), + req(_req), coherence(NULL), senderState(NULL), cmd(_cmd), + time(curTick), result(Unknown) + { + } + + ~Packet() + { deleteData(); } + + + /** Minimally reset a packet so something like simple cpu can reuse it. */ + void reset(); + + void reinitFromRequest() { + if (req->validPaddr) setAddr(req->paddr); + if (req->validSize) setSize(req->size); + } + + /** Set the data pointer to the following value that should not be freed. */ + template <typename T> + void dataStatic(T *p); + + /** Set the data pointer to a value that should have delete [] called on it. + */ + template <typename T> + void dataDynamicArray(T *p); + + /** set the data pointer to a value that should have delete called on it. */ + template <typename T> + void dataDynamic(T *p); + + /** return the value of what is pointed to in the packet. */ + template <typename T> + T get(); + + /** get a pointer to the data ptr. */ + template <typename T> + T* getPtr(); + + /** set the value in the data pointer to v. */ + template <typename T> + void set(T v); + + /** delete the data pointed to in the data pointer. Ok to call to matter how + * data was allocted. */ + void deleteData(); + + /** If there isn't data in the packet, allocate some. */ + void allocate(); + + /** Do the packet modify the same addresses. */ + bool intersect(Packet *p); +}; + +bool fixPacket(Packet *func, Packet *timing); +#endif //__MEM_PACKET_HH diff --git a/src/mem/page_table.cc b/src/mem/page_table.cc new file mode 100644 index 000000000..c4e1ea193 --- /dev/null +++ b/src/mem/page_table.cc @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * Definitions of page table. + */ +#include <string> +#include <map> +#include <fstream> + +#include "arch/faults.hh" +#include "base/bitfield.hh" +#include "base/intmath.hh" +#include "base/trace.hh" +#include "mem/page_table.hh" +#include "sim/builder.hh" +#include "sim/sim_object.hh" +#include "sim/system.hh" + +using namespace std; +using namespace TheISA; + +PageTable::PageTable(System *_system, Addr _pageSize) + : pageSize(_pageSize), offsetMask(mask(floorLog2(_pageSize))), + system(_system) +{ + assert(isPowerOf2(pageSize)); +} + +PageTable::~PageTable() +{ +} + +Fault +PageTable::page_check(Addr addr, int size) const +{ + if (size < sizeof(uint64_t)) { + if (!isPowerOf2(size)) { + panic("Invalid request size!\n"); + return genMachineCheckFault(); + } + + if ((size - 1) & addr) + return genAlignmentFault(); + } + else { + if ((addr & (VMPageSize - 1)) + size > VMPageSize) { + panic("Invalid request size!\n"); + return genMachineCheckFault(); + } + + if ((sizeof(uint64_t) - 1) & addr) + return genAlignmentFault(); + } + + return NoFault; +} + + + + +void +PageTable::allocate(Addr vaddr, int size) +{ + // starting address must be page aligned + assert(pageOffset(vaddr) == 0); + + for (; size > 0; size -= pageSize, vaddr += pageSize) { + std::map<Addr,Addr>::iterator iter = pTable.find(vaddr); + + if (iter != pTable.end()) { + // already mapped + fatal("PageTable::allocate: address 0x%x already mapped", vaddr); + } + + pTable[vaddr] = system->new_page(); + } +} + + + +bool +PageTable::translate(Addr vaddr, Addr &paddr) +{ + Addr page_addr = pageAlign(vaddr); + std::map<Addr,Addr>::iterator iter = pTable.find(page_addr); + + if (iter == pTable.end()) { + return false; + } + + paddr = iter->second + pageOffset(vaddr); + return true; +} + + +Fault +PageTable::translate(RequestPtr &req) +{ + Addr paddr; + assert(pageAlign(req->getVaddr() + req->getSize() - 1) + == pageAlign(req->getVaddr())); + if (!translate(req->getVaddr(), paddr)) { + return genMachineCheckFault(); + } + req->setPaddr(paddr); + return page_check(req->getPaddr(), req->getSize()); +} diff --git a/src/mem/page_table.hh b/src/mem/page_table.hh new file mode 100644 index 000000000..26248261a --- /dev/null +++ b/src/mem/page_table.hh @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * Declaration of a non-full system Page Table. + */ + +#ifndef __PAGE_TABLE__ +#define __PAGE_TABLE__ + +#include <string> +#include <map> + +#include "arch/isa_traits.hh" +#include "base/trace.hh" +#include "mem/request.hh" +#include "mem/packet.hh" +#include "sim/sim_object.hh" + +class System; + +/** + * Page Table Decleration. + */ +class PageTable +{ + protected: + std::map<Addr,Addr> pTable; + + const Addr pageSize; + const Addr offsetMask; + + System *system; + + public: + + PageTable(System *_system, Addr _pageSize = TheISA::VMPageSize); + + ~PageTable(); + + Addr pageAlign(Addr a) { return (a & ~offsetMask); } + Addr pageOffset(Addr a) { return (a & offsetMask); } + + Fault page_check(Addr addr, int size) const; + + void allocate(Addr vaddr, int size); + + /** + * Translate function + * @param vaddr The virtual address. + * @return Physical address from translation. + */ + bool translate(Addr vaddr, Addr &paddr); + + /** + * Perform a translation on the memory request, fills in paddr + * field of mem_req. + * @param req The memory request. + */ + Fault translate(RequestPtr &req); + +}; + +#endif diff --git a/src/mem/physical.cc b/src/mem/physical.cc new file mode 100644 index 000000000..26dbef0cd --- /dev/null +++ b/src/mem/physical.cc @@ -0,0 +1,377 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <sys/mman.h> +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <zlib.h> + +#include <iostream> +#include <string> + + +#include "base/misc.hh" +#include "config/full_system.hh" +#include "mem/packet_impl.hh" +#include "mem/physical.hh" +#include "sim/host.hh" +#include "sim/builder.hh" +#include "sim/eventq.hh" +#include "arch/isa_traits.hh" + + +using namespace std; +using namespace TheISA; + +PhysicalMemory::MemResponseEvent::MemResponseEvent(Packet *pkt, MemoryPort* _m) + : Event(&mainEventQueue, CPU_Tick_Pri), pkt(pkt), memoryPort(_m) +{ + + this->setFlags(AutoDelete); +} + +void +PhysicalMemory::MemResponseEvent::process() +{ + memoryPort->sendTiming(pkt); +} + +const char * +PhysicalMemory::MemResponseEvent::description() +{ + return "Physical Memory Timing Access respnse event"; +} + +PhysicalMemory::PhysicalMemory(const string &n, Tick latency) + : MemObject(n),base_addr(0), pmem_addr(NULL), port(NULL), lat(latency) +{ + // Hardcoded to 128 MB for now. + pmem_size = 1 << 27; + + if (pmem_size % TheISA::PageBytes != 0) + panic("Memory Size not divisible by page size\n"); + + int map_flags = MAP_ANON | MAP_PRIVATE; + pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE, + map_flags, -1, 0); + + if (pmem_addr == (void *)MAP_FAILED) { + perror("mmap"); + fatal("Could not mmap!\n"); + } + + page_ptr = 0; +} + +void +PhysicalMemory::init() +{ + if (!port) + panic("PhysicalMemory not connected to anything!"); + port->sendStatusChange(Port::RangeChange); +} + +PhysicalMemory::~PhysicalMemory() +{ + if (pmem_addr) + munmap(pmem_addr, pmem_size); + //Remove memPorts? +} + +Addr +PhysicalMemory::new_page() +{ + Addr return_addr = page_ptr << LogVMPageSize; + return_addr += base_addr; + + ++page_ptr; + return return_addr; +} + +int +PhysicalMemory::deviceBlockSize() +{ + //Can accept anysize request + return 0; +} + +bool +PhysicalMemory::doTimingAccess (Packet *pkt, MemoryPort* memoryPort) +{ + doFunctionalAccess(pkt); + + // turn packet around to go back to requester + pkt->makeTimingResponse(); + MemResponseEvent* response = new MemResponseEvent(pkt, memoryPort); + response->schedule(curTick + lat); + + return true; +} + +Tick +PhysicalMemory::doAtomicAccess(Packet *pkt) +{ + doFunctionalAccess(pkt); + pkt->time = curTick + lat; + return curTick + lat; +} + +void +PhysicalMemory::doFunctionalAccess(Packet *pkt) +{ + assert(pkt->getAddr() + pkt->getSize() < pmem_size); + + switch (pkt->cmd) { + case Packet::ReadReq: + memcpy(pkt->getPtr<uint8_t>(), + pmem_addr + pkt->getAddr() - base_addr, + pkt->getSize()); + break; + case Packet::WriteReq: + memcpy(pmem_addr + pkt->getAddr() - base_addr, + pkt->getPtr<uint8_t>(), + pkt->getSize()); + // temporary hack: will need to add real LL/SC implementation + // for cacheless systems later. + if (pkt->req->getFlags() & LOCKED) { + pkt->req->setScResult(1); + } + break; + default: + panic("unimplemented"); + } + + pkt->result = Packet::Success; +} + +Port * +PhysicalMemory::getPort(const std::string &if_name) +{ + if (if_name == "") { + if (port != NULL) + panic("PhysicalMemory::getPort: additional port requested to memory!"); + port = new MemoryPort(name() + "-port", this); + return port; + } else if (if_name == "functional") { + /* special port for functional writes at startup. */ + return new MemoryPort(name() + "-funcport", this); + } else { + panic("PhysicalMemory::getPort: unknown port %s requested", if_name); + } +} + +void +PhysicalMemory::recvStatusChange(Port::Status status) +{ +} + +PhysicalMemory::MemoryPort::MemoryPort(const std::string &_name, + PhysicalMemory *_memory) + : Port(_name), memory(_memory) +{ } + +void +PhysicalMemory::MemoryPort::recvStatusChange(Port::Status status) +{ + memory->recvStatusChange(status); +} + +void +PhysicalMemory::MemoryPort::getDeviceAddressRanges(AddrRangeList &resp, + AddrRangeList &snoop) +{ + memory->getAddressRanges(resp, snoop); +} + +void +PhysicalMemory::getAddressRanges(AddrRangeList &resp, AddrRangeList &snoop) +{ + snoop.clear(); + resp.clear(); + resp.push_back(RangeSize(base_addr, pmem_size)); +} + +int +PhysicalMemory::MemoryPort::deviceBlockSize() +{ + return memory->deviceBlockSize(); +} + +bool +PhysicalMemory::MemoryPort::recvTiming(Packet *pkt) +{ + return memory->doTimingAccess(pkt, this); +} + +Tick +PhysicalMemory::MemoryPort::recvAtomic(Packet *pkt) +{ + return memory->doAtomicAccess(pkt); +} + +void +PhysicalMemory::MemoryPort::recvFunctional(Packet *pkt) +{ + memory->doFunctionalAccess(pkt); +} + + + +void +PhysicalMemory::serialize(ostream &os) +{ + gzFile compressedMem; + string filename = name() + ".physmem"; + + SERIALIZE_SCALAR(pmem_size); + SERIALIZE_SCALAR(filename); + + // write memory file + string thefile = Checkpoint::dir() + "/" + filename.c_str(); + int fd = creat(thefile.c_str(), 0664); + if (fd < 0) { + perror("creat"); + fatal("Can't open physical memory checkpoint file '%s'\n", filename); + } + + compressedMem = gzdopen(fd, "wb"); + if (compressedMem == NULL) + fatal("Insufficient memory to allocate compression state for %s\n", + filename); + + if (gzwrite(compressedMem, pmem_addr, pmem_size) != pmem_size) { + fatal("Write failed on physical memory checkpoint file '%s'\n", + filename); + } + + if (gzclose(compressedMem)) + fatal("Close failed on physical memory checkpoint file '%s'\n", + filename); +} + +void +PhysicalMemory::unserialize(Checkpoint *cp, const string §ion) +{ + gzFile compressedMem; + long *tempPage; + long *pmem_current; + uint64_t curSize; + uint32_t bytesRead; + const int chunkSize = 16384; + + + // unmap file that was mmaped in the constructor + munmap(pmem_addr, pmem_size); + + string filename; + + UNSERIALIZE_SCALAR(pmem_size); + UNSERIALIZE_SCALAR(filename); + + filename = cp->cptDir + "/" + filename; + + // mmap memoryfile + int fd = open(filename.c_str(), O_RDONLY); + if (fd < 0) { + perror("open"); + fatal("Can't open physical memory checkpoint file '%s'", filename); + } + + compressedMem = gzdopen(fd, "rb"); + if (compressedMem == NULL) + fatal("Insufficient memory to allocate compression state for %s\n", + filename); + + + pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE, + MAP_ANON | MAP_PRIVATE, -1, 0); + + if (pmem_addr == (void *)MAP_FAILED) { + perror("mmap"); + fatal("Could not mmap physical memory!\n"); + } + + curSize = 0; + tempPage = (long*)malloc(chunkSize); + if (tempPage == NULL) + fatal("Unable to malloc memory to read file %s\n", filename); + + /* Only copy bytes that are non-zero, so we don't give the VM system hell */ + while (curSize < pmem_size) { + bytesRead = gzread(compressedMem, tempPage, chunkSize); + if (bytesRead != chunkSize && bytesRead != pmem_size - curSize) + fatal("Read failed on physical memory checkpoint file '%s'" + " got %d bytes, expected %d or %d bytes\n", + filename, bytesRead, chunkSize, pmem_size-curSize); + + assert(bytesRead % sizeof(long) == 0); + + for (int x = 0; x < bytesRead/sizeof(long); x++) + { + if (*(tempPage+x) != 0) { + pmem_current = (long*)(pmem_addr + curSize + x * sizeof(long)); + *pmem_current = *(tempPage+x); + } + } + curSize += bytesRead; + } + + free(tempPage); + + if (gzclose(compressedMem)) + fatal("Close failed on physical memory checkpoint file '%s'\n", + filename); + +} + + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory) + + Param<string> file; + Param<Range<Addr> > range; + Param<Tick> latency; + +END_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory) + +BEGIN_INIT_SIM_OBJECT_PARAMS(PhysicalMemory) + + INIT_PARAM_DFLT(file, "memory mapped file", ""), + INIT_PARAM(range, "Device Address Range"), + INIT_PARAM(latency, "Memory access latency") + +END_INIT_SIM_OBJECT_PARAMS(PhysicalMemory) + +CREATE_SIM_OBJECT(PhysicalMemory) +{ + + return new PhysicalMemory(getInstanceName(), latency); +} + +REGISTER_SIM_OBJECT("PhysicalMemory", PhysicalMemory) diff --git a/src/mem/physical.hh b/src/mem/physical.hh new file mode 100644 index 000000000..2ced79045 --- /dev/null +++ b/src/mem/physical.hh @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* @file + */ + +#ifndef __PHYSICAL_MEMORY_HH__ +#define __PHYSICAL_MEMORY_HH__ + +#include "base/range.hh" +#include "mem/mem_object.hh" +#include "mem/packet.hh" +#include "mem/port.hh" +#include "sim/eventq.hh" +#include <map> +#include <string> + +// +// Functional model for a contiguous block of physical memory. (i.e. RAM) +// +class PhysicalMemory : public MemObject +{ + class MemoryPort : public Port + { + PhysicalMemory *memory; + + public: + + MemoryPort(const std::string &_name, PhysicalMemory *_memory); + + protected: + + virtual bool recvTiming(Packet *pkt); + + virtual Tick recvAtomic(Packet *pkt); + + virtual void recvFunctional(Packet *pkt); + + virtual void recvStatusChange(Status status); + + virtual void getDeviceAddressRanges(AddrRangeList &resp, + AddrRangeList &snoop); + + virtual int deviceBlockSize(); + }; + + int numPorts; + + + struct MemResponseEvent : public Event + { + Packet *pkt; + MemoryPort *memoryPort; + + MemResponseEvent(Packet *pkt, MemoryPort *memoryPort); + void process(); + const char *description(); + }; + + private: + // prevent copying of a MainMemory object + PhysicalMemory(const PhysicalMemory &specmem); + const PhysicalMemory &operator=(const PhysicalMemory &specmem); + + protected: + Addr base_addr; + Addr pmem_size; + uint8_t *pmem_addr; + MemoryPort *port; + int page_ptr; + Tick lat; + + public: + Addr new_page(); + uint64_t size() { return pmem_size; } + + public: + PhysicalMemory(const std::string &n, Tick latency); + virtual ~PhysicalMemory(); + + public: + int deviceBlockSize(); + void getAddressRanges(AddrRangeList &resp, AddrRangeList &snoop); + virtual Port *getPort(const std::string &if_name); + void virtual init(); + + // fast back-door memory access for vtophys(), remote gdb, etc. + // uint64_t phys_read_qword(Addr addr) const; + private: + bool doTimingAccess(Packet *pkt, MemoryPort *memoryPort); + Tick doAtomicAccess(Packet *pkt); + void doFunctionalAccess(Packet *pkt); + + void recvStatusChange(Port::Status status); + + public: + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); + +}; + +#endif //__PHYSICAL_MEMORY_HH__ diff --git a/src/mem/port.cc b/src/mem/port.cc new file mode 100644 index 000000000..651cb739a --- /dev/null +++ b/src/mem/port.cc @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file Port object definitions. + */ + +#include "base/chunk_generator.hh" +#include "base/trace.hh" +#include "mem/packet_impl.hh" +#include "mem/port.hh" + +void +Port::setPeer(Port *port) +{ + DPRINTF(Config, "setting peer to %s\n", port->name()); + peer = port; +} + +void +Port::blobHelper(Addr addr, uint8_t *p, int size, Packet::Command cmd) +{ + Request req(false); + Packet pkt(&req, cmd, Packet::Broadcast); + + for (ChunkGenerator gen(addr, size, peerBlockSize()); + !gen.done(); gen.next()) { + req.setPaddr(gen.addr()); + req.setSize(gen.size()); + pkt.reinitFromRequest(); + pkt.dataStatic(p); + sendFunctional(&pkt); + p += gen.size(); + } +} + +void +Port::writeBlob(Addr addr, uint8_t *p, int size) +{ + blobHelper(addr, p, size, Packet::WriteReq); +} + +void +Port::readBlob(Addr addr, uint8_t *p, int size) +{ + blobHelper(addr, p, size, Packet::ReadReq); +} + +void +Port::memsetBlob(Addr addr, uint8_t val, int size) +{ + // quick and dirty... + uint8_t *buf = new uint8_t[size]; + + memset(buf, val, size); + blobHelper(addr, buf, size, Packet::WriteReq); + + delete [] buf; +} diff --git a/src/mem/port.hh b/src/mem/port.hh new file mode 100644 index 000000000..f9103865e --- /dev/null +++ b/src/mem/port.hh @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * Port Object Decleration. Ports are used to interface memory objects to + * each other. They will always come in pairs, and we refer to the other + * port object as the peer. These are used to make the design more + * modular so that a specific interface between every type of objcet doesn't + * have to be created. + */ + +#ifndef __MEM_PORT_HH__ +#define __MEM_PORT_HH__ + +#include <list> +#include <inttypes.h> + +#include "base/misc.hh" +#include "base/range.hh" +#include "mem/packet.hh" +#include "mem/request.hh" + +/** This typedef is used to clean up the parameter list of + * getDeviceAddressRanges() and getPeerAddressRanges(). It's declared + * outside the Port object since it's also used by some mem objects. + * Eventually we should move this typedef to wherever Addr is + * defined. + */ + +typedef std::list<Range<Addr> > AddrRangeList; +typedef std::list<Range<Addr> >::iterator AddrRangeIter; + +/** + * Ports are used to interface memory objects to + * each other. They will always come in pairs, and we refer to the other + * port object as the peer. These are used to make the design more + * modular so that a specific interface between every type of objcet doesn't + * have to be created. + * + * Recv accesor functions are being called from the peer interface. + * Send accessor functions are being called from the device the port is + * associated with, and it will call the peer recv. accessor function. + */ +class Port +{ + private: + + /** Descriptive name (for DPRINTF output) */ + const std::string portName; + + public: + + /** + * Constructor. + * + * @param _name Port name for DPRINTF output. Should include name + * of memory system object to which the port belongs. + */ + Port(const std::string &_name) + : portName(_name) + { } + + /** Return port name (for DPRINTF). */ + const std::string &name() const { return portName; } + + virtual ~Port() {}; + + // mey be better to use subclasses & RTTI? + /** Holds the ports status. Keeps track if it is blocked, or has + calculated a range change. */ + enum Status { + Blocked, + Unblocked, + RangeChange + }; + + private: + + /** A pointer to the peer port. Ports always come in pairs, that way they + can use a standardized interface to communicate between different + memory objects. */ + Port *peer; + + public: + + /** Function to set the pointer for the peer port. + @todo should be called by the configuration stuff (python). + */ + void setPeer(Port *port); + + /** Function to set the pointer for the peer port. + @todo should be called by the configuration stuff (python). + */ + Port *getPeer() { return peer; } + + protected: + + /** These functions are protected because they should only be + * called by a peer port, never directly by any outside object. */ + + /** Called to recive a timing call from the peer port. */ + virtual bool recvTiming(Packet *pkt) = 0; + + /** Called to recive a atomic call from the peer port. */ + virtual Tick recvAtomic(Packet *pkt) = 0; + + /** Called to recive a functional call from the peer port. */ + virtual void recvFunctional(Packet *pkt) = 0; + + /** Called to recieve a status change from the peer port. */ + virtual void recvStatusChange(Status status) = 0; + + /** Called by a peer port if the send was unsuccesful, and had to + wait. This shouldn't be valid for response paths (IO Devices). + so it is set to panic if it isn't already defined. + */ + virtual Packet *recvRetry() { panic("??"); } + + /** Called by a peer port in order to determine the block size of the + device connected to this port. It sometimes doesn't make sense for + this function to be called, a DMA interface doesn't really have a + block size, so it is defaulted to a panic. + */ + virtual int deviceBlockSize() { panic("??"); } + + /** The peer port is requesting us to reply with a list of the ranges we + are responsible for. + @param resp is a list of ranges responded to + @param snoop is a list of ranges snooped + */ + virtual void getDeviceAddressRanges(AddrRangeList &resp, + AddrRangeList &snoop) + { panic("??"); } + + public: + + /** Function called by associated memory device (cache, memory, iodevice) + in order to send a timing request to the port. Simply calls the peer + port receive function. + @return This function returns if the send was succesful in it's + recieve. If it was a failure, then the port will wait for a recvRetry + at which point it can issue a successful sendTiming. This is used in + case a cache has a higher priority request come in while waiting for + the bus to arbitrate. + */ + bool sendTiming(Packet *pkt) { return peer->recvTiming(pkt); } + + /** Function called by the associated device to send an atomic access, + an access in which the data is moved and the state is updated in one + cycle, without interleaving with other memory accesses. + */ + Tick sendAtomic(Packet *pkt) + { return peer->recvAtomic(pkt); } + + /** Function called by the associated device to send a functional access, + an access in which the data is instantly updated everywhere in the + memory system, without affecting the current state of any block or + moving the block. + */ + void sendFunctional(Packet *pkt) + { return peer->recvFunctional(pkt); } + + /** Called by the associated device to send a status change to the device + connected to the peer interface. + */ + void sendStatusChange(Status status) {peer->recvStatusChange(status); } + + /** When a timing access doesn't return a success, some time later the + Retry will be sent. + */ + Packet *sendRetry() { return peer->recvRetry(); } + + /** Called by the associated device if it wishes to find out the blocksize + of the device on attached to the peer port. + */ + int peerBlockSize() { return peer->deviceBlockSize(); } + + /** Called by the associated device if it wishes to find out the address + ranges connected to the peer ports devices. + */ + void getPeerAddressRanges(AddrRangeList &resp, AddrRangeList &snoop) + { peer->getDeviceAddressRanges(resp, snoop); } + + /** This function is a wrapper around sendFunctional() + that breaks a larger, arbitrarily aligned access into + appropriate chunks. The default implementation can use + getBlockSize() to determine the block size and go from there. + */ + virtual void readBlob(Addr addr, uint8_t *p, int size); + + /** This function is a wrapper around sendFunctional() + that breaks a larger, arbitrarily aligned access into + appropriate chunks. The default implementation can use + getBlockSize() to determine the block size and go from there. + */ + virtual void writeBlob(Addr addr, uint8_t *p, int size); + + /** Fill size bytes starting at addr with byte value val. This + should not need to be virtual, since it can be implemented in + terms of writeBlob(). However, it shouldn't be + performance-critical either, so it could be if we wanted to. + */ + virtual void memsetBlob(Addr addr, uint8_t val, int size); + + private: + + /** Internal helper function for read/writeBlob(). + */ + void blobHelper(Addr addr, uint8_t *p, int size, Packet::Command cmd); +}; + +/** A simple functional port that is only meant for one way communication to + * physical memory. It is only meant to be used to load data into memory before + * the simulation begins. + */ + +class FunctionalPort : public Port +{ + public: + FunctionalPort(const std::string &_name) + : Port(_name) + {} + + virtual bool recvTiming(Packet *pkt) { panic("FuncPort is UniDir"); } + virtual Tick recvAtomic(Packet *pkt) { panic("FuncPort is UniDir"); } + virtual void recvFunctional(Packet *pkt) { panic("FuncPort is UniDir"); } + virtual void recvStatusChange(Status status) {} + + template <typename T> + inline void write(Addr addr, T d) + { + writeBlob(addr, (uint8_t*)&d, sizeof(T)); + } + + template <typename T> + inline T read(Addr addr) + { + T d; + readBlob(addr, (uint8_t*)&d, sizeof(T)); + return d; + } +}; + +#endif //__MEM_PORT_HH__ diff --git a/src/mem/request.hh b/src/mem/request.hh new file mode 100644 index 000000000..10550e859 --- /dev/null +++ b/src/mem/request.hh @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file Decleration of a request, the overall memory request consisting of + the parts of the request that are persistent throughout the transaction. + */ + +#ifndef __MEM_REQUEST_HH__ +#define __MEM_REQUEST_HH__ + +#include "arch/isa_traits.hh" + +class Request; + +typedef Request* RequestPtr; + +/** The request is a Load locked/store conditional. */ +const unsigned LOCKED = 0x001; +/** The virtual address is also the physical address. */ +const unsigned PHYSICAL = 0x002; +/** The request is an ALPHA VPTE pal access (hw_ld). */ +const unsigned VPTE = 0x004; +/** Use the alternate mode bits in ALPHA. */ +const unsigned ALTMODE = 0x008; +/** The request is to an uncacheable address. */ +const unsigned UNCACHEABLE = 0x010; +/** The request should not cause a page fault. */ +const unsigned NO_FAULT = 0x020; +/** The request should be prefetched into the exclusive state. */ +const unsigned PF_EXCLUSIVE = 0x100; +/** The request should be marked as LRU. */ +const unsigned EVICT_NEXT = 0x200; +/** The request should ignore unaligned access faults */ +const unsigned NO_ALIGN_FAULT = 0x400; + +class Request +{ + //@todo Make Accesor functions, make these private. + public: + /** Constructor, needs a bool to signify if it is/isn't Cpu Request. */ + Request(bool isCpu); + + /** reset the request to it's initial state so it can be reused.*/ + void resetAll(bool isCpu); + + /** reset the request's addrs times, etc, so but not everything to same + * time. */ + void resetMin(); + +//First non-cpu request fields + private: + /** The physical address of the request. */ + Addr paddr; + /** Wether or not paddr is valid (has been written yet). */ + bool validPaddr; + + /** The size of the request. */ + int size; + /** Wether or not size is valid (has been written yet). */ + bool validSize; + + /** The time this request was started. Used to calculate latencies. */ + Tick time; + /** Wether or not time is valid (has been written yet). */ + bool validTime; + + /** Destination address if this is a block copy. */ + Addr copyDest; + /** Wether or not copyDest is valid (has been written yet). */ + bool validCopyDest; + + /** Flag structure for the request. */ + uint32_t flags; + +//Accsesors for non-cpu request fields + public: + /** Accesor for paddr. */ + Addr getPaddr(); + /** Accesor for paddr. */ + void setPaddr(Addr _paddr); + + /** Accesor for size. */ + int getSize(); + /** Accesor for size. */ + void setSize(int _size); + + /** Accesor for time. */ + Tick getTime(); + /** Accesor for time. */ + void setTime(Tick _time); + + /** Accesor for copy dest. */ + Addr getCopyDest(); + /** Accesor for copy dest. */ + void setCopyDest(Addr _copyDest); + + /** Accesor for flags. */ + uint32_t getFlags(); + /** Accesor for paddr. */ + void setFlags(uint32_t _flags); + +//Now cpu-request fields + private: + /** Bool to signify if this is a cpuRequest. */ + bool cpuReq; + + /** The virtual address of the request. */ + Addr vaddr; + /** Wether or not the vaddr is valid. */ + bool validVaddr; + + /** The address space ID. */ + int asid; + /** Wether or not the asid is valid. */ + bool validAsid; + + /** The return value of store conditional. */ + uint64_t scResult; + /** Wether or not the sc result is valid. */ + bool validScResult; + + /** The cpu number for statistics. */ + int cpuNum; + /** Wether or not the cpu number is valid. */ + bool validCpuNum; + + /** The requesting thread id. */ + int threadNum; + /** Wether or not the thread id is valid. */ + bool validThreadNum; + + /** program counter of initiating access; for tracing/debugging */ + Addr pc; + /** Wether or not the pc is valid. */ + bool validPC; + +//Accessor Functions for cpu request fields + public: + /** Accesor function to determine if this is a cpu request or not.*/ + bool isCpuRequest(); + + /** Accesor function for vaddr.*/ + Addr getVaddr(); + /** Accesor function for vaddr.*/ + void setVaddr(Addr _vaddr); + + /** Accesor function for asid.*/ + int getAsid(); + /** Accesor function for asid.*/ + void setAsid(int _asid); + + /** Accesor function for store conditional return value.*/ + uint64_t getScResult(); + /** Accesor function for store conditional return value.*/ + void setScResult(uint64_t _scResult); + + /** Accesor function for cpu number.*/ + int getCpuNum(); + /** Accesor function for cpu number.*/ + void setCpuNum(int _cpuNum); + + /** Accesor function for thread number.*/ + int getThreadNum(); + /** Accesor function for thread number.*/ + void setThreadNum(int _threadNum); + + /** Accesor function for pc.*/ + Addr getPC(); + /** Accesor function for pc.*/ + void setPC(Addr _pc); + + friend class Packet; +}; + +#endif // __MEM_REQUEST_HH__ diff --git a/src/mem/translating_port.cc b/src/mem/translating_port.cc new file mode 100644 index 000000000..ee4d277b6 --- /dev/null +++ b/src/mem/translating_port.cc @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <string> +#include "base/chunk_generator.hh" +#include "mem/port.hh" +#include "mem/translating_port.hh" +#include "mem/page_table.hh" + +using namespace TheISA; + +TranslatingPort::TranslatingPort(const std::string &_name, + PageTable *p_table, bool alloc) + : FunctionalPort(_name), pTable(p_table), allocating(alloc) +{ } + +TranslatingPort::~TranslatingPort() +{ } + +bool +TranslatingPort::tryReadBlob(Addr addr, uint8_t *p, int size) +{ + Addr paddr; + int prevSize = 0; + + for (ChunkGenerator gen(addr, size, VMPageSize); !gen.done(); gen.next()) { + + if (!pTable->translate(gen.addr(),paddr)) + return false; + + Port::readBlob(paddr, p + prevSize, gen.size()); + prevSize += gen.size(); + } + + return true; +} + +void +TranslatingPort::readBlob(Addr addr, uint8_t *p, int size) +{ + if (!tryReadBlob(addr, p, size)) + fatal("readBlob(0x%x, ...) failed", addr); +} + + +bool +TranslatingPort::tryWriteBlob(Addr addr, uint8_t *p, int size) +{ + + Addr paddr; + int prevSize = 0; + + for (ChunkGenerator gen(addr, size, VMPageSize); !gen.done(); gen.next()) { + + if (!pTable->translate(gen.addr(), paddr)) { + if (allocating) { + pTable->allocate(roundDown(gen.addr(), VMPageSize), + VMPageSize); + pTable->translate(gen.addr(), paddr); + } else { + return false; + } + } + + Port::writeBlob(paddr, p + prevSize, gen.size()); + prevSize += gen.size(); + } + + return true; +} + + +void +TranslatingPort::writeBlob(Addr addr, uint8_t *p, int size) +{ + if (!tryWriteBlob(addr, p, size)) + fatal("writeBlob(0x%x, ...) failed", addr); +} + +bool +TranslatingPort::tryMemsetBlob(Addr addr, uint8_t val, int size) +{ + Addr paddr; + + for (ChunkGenerator gen(addr, size, VMPageSize); !gen.done(); gen.next()) { + + if (!pTable->translate(gen.addr(), paddr)) { + if (allocating) { + pTable->allocate(roundDown(gen.addr(), VMPageSize), + VMPageSize); + pTable->translate(gen.addr(), paddr); + } else { + return false; + } + } + + Port::memsetBlob(paddr, val, gen.size()); + } + + return true; +} + +void +TranslatingPort::memsetBlob(Addr addr, uint8_t val, int size) +{ + if (!tryMemsetBlob(addr, val, size)) + fatal("memsetBlob(0x%x, ...) failed", addr); +} + + +bool +TranslatingPort::tryWriteString(Addr addr, const char *str) +{ + Addr paddr,vaddr; + uint8_t c; + + vaddr = addr; + + do { + c = *str++; + if (!pTable->translate(vaddr++,paddr)) + return false; + + Port::writeBlob(paddr, &c, 1); + } while (c); + + return true; +} + +void +TranslatingPort::writeString(Addr addr, const char *str) +{ + if (!tryWriteString(addr, str)) + fatal("writeString(0x%x, ...) failed", addr); +} + +bool +TranslatingPort::tryReadString(std::string &str, Addr addr) +{ + Addr paddr,vaddr; + uint8_t c; + + vaddr = addr; + + do { + if (!pTable->translate(vaddr++,paddr)) + return false; + + Port::readBlob(paddr, &c, 1); + str += c; + } while (c); + + return true; +} + +void +TranslatingPort::readString(std::string &str, Addr addr) +{ + if (!tryReadString(str, addr)) + fatal("readString(0x%x, ...) failed", addr); +} + diff --git a/src/mem/translating_port.hh b/src/mem/translating_port.hh new file mode 100644 index 000000000..d078158a3 --- /dev/null +++ b/src/mem/translating_port.hh @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MEM_TRANSLATING_PROT_HH__ +#define __MEM_TRANSLATING_PROT_HH__ + +#include "mem/port.hh" + +class PageTable; + +class TranslatingPort : public FunctionalPort +{ + private: + PageTable *pTable; + bool allocating; + + public: + TranslatingPort(const std::string &_name, + PageTable *p_table, bool alloc = false); + virtual ~TranslatingPort(); + + bool tryReadBlob(Addr addr, uint8_t *p, int size); + bool tryWriteBlob(Addr addr, uint8_t *p, int size); + bool tryMemsetBlob(Addr addr, uint8_t val, int size); + bool tryWriteString(Addr addr, const char *str); + bool tryReadString(std::string &str, Addr addr); + + virtual void readBlob(Addr addr, uint8_t *p, int size); + virtual void writeBlob(Addr addr, uint8_t *p, int size); + virtual void memsetBlob(Addr addr, uint8_t val, int size); + + void writeString(Addr addr, const char *str); + void readString(std::string &str, Addr addr); +}; + +#endif diff --git a/src/mem/vport.cc b/src/mem/vport.cc new file mode 100644 index 000000000..cc569acf3 --- /dev/null +++ b/src/mem/vport.cc @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file Port object definitions. + */ + +#include "base/chunk_generator.hh" +#include "mem/vport.hh" + +void +VirtualPort::readBlob(Addr addr, uint8_t *p, int size) +{ + Addr paddr; + for (ChunkGenerator gen(addr, size, TheISA::PageBytes); !gen.done(); + gen.next()) + { + if (xc) + paddr = TheISA::vtophys(xc,gen.addr()); + else + paddr = TheISA::vtophys(gen.addr()); + + FunctionalPort::readBlob(paddr, p, gen.size()); + p += gen.size(); + } +} + +void +VirtualPort::writeBlob(Addr addr, uint8_t *p, int size) +{ + Addr paddr; + for (ChunkGenerator gen(addr, size, TheISA::PageBytes); !gen.done(); + gen.next()) + { + if (xc) + paddr = TheISA::vtophys(xc,gen.addr()); + else + paddr = TheISA::vtophys(gen.addr()); + + FunctionalPort::writeBlob(paddr, p, gen.size()); + p += gen.size(); + } +} + diff --git a/src/mem/vport.hh b/src/mem/vport.hh new file mode 100644 index 000000000..0f3b1f09e --- /dev/null +++ b/src/mem/vport.hh @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * Virtual Port Object Decleration. These ports incorporate some translation + * into their access methods. Thus you can use one to read and write data + * to/from virtual addresses. + */ + +#ifndef __MEM_VPORT_HH__ +#define __MEM_VPORT_HH__ + +#include "mem/port.hh" +#include "config/full_system.hh" +#include "arch/vtophys.hh" + + +/** A class that translates a virtual address to a physical address and then + * calls the above read/write functions. If an execution context is provided the + * address can alway be translated, If not it can only be translated if it is a + * simple address masking operation (such as alpha super page accesses). + */ + +class VirtualPort : public FunctionalPort +{ + private: + ExecContext *xc; + + public: + VirtualPort(const std::string &_name, ExecContext *_xc = NULL) + : FunctionalPort(_name), xc(_xc) + {} + + /** Return true if we have an exec context. This is used to prevent someone + * from accidently deleting the cpus statically allocated vport. + * @return true if an execution context isn't valid + */ + bool nullExecContext() { return xc != NULL; } + + /** Version of readblob that translates virt->phys and deals + * with page boundries. */ + virtual void readBlob(Addr addr, uint8_t *p, int size); + + /** Version of writeBlob that translates virt->phys and deals + * with page boundries. */ + virtual void writeBlob(Addr addr, uint8_t *p, int size); +}; + +#endif //__MEM_VPORT_HH__ + diff --git a/src/python/SConscript b/src/python/SConscript new file mode 100644 index 000000000..4407e403d --- /dev/null +++ b/src/python/SConscript @@ -0,0 +1,207 @@ +# -*- mode:python -*- + +# Copyright (c) 2004-2005 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +import os, os.path, re, sys + +Import('env') + +import scons_helper + +def WriteEmbeddedPyFile(target, source, path, name, ext, filename): + if isinstance(source, str): + source = file(source, 'r') + + if isinstance(target, str): + target = file(target, 'w') + + print >>target, "AddModule(%s, %s, %s, %s, '''\\" % \ + (`path`, `name`, `ext`, `filename`) + + for line in source: + line = line + # escape existing backslashes + line = line.replace('\\', '\\\\') + # escape existing triple quotes + line = line.replace("'''", r"\'\'\'") + + print >>target, line, + + print >>target, "''')" + print >>target + +def WriteCFile(target, source, name): + if isinstance(source, str): + source = file(source, 'r') + + if isinstance(target, str): + target = file(target, 'w') + + print >>target, 'const char %s_string[] = {' % name + + count = 0 + from array import array + try: + while True: + foo = array('B') + foo.fromfile(source, 10000) + l = [ str(i) for i in foo.tolist() ] + count += len(l) + for i in xrange(0,9999,20): + print >>target, ','.join(l[i:i+20]) + ',' + except EOFError: + l = [ str(i) for i in foo.tolist() ] + count += len(l) + for i in xrange(0,len(l),20): + print >>target, ','.join(l[i:i+20]) + ',' + print >>target, ','.join(l[i:]) + ',' + + print >>target, '};' + print >>target, 'const int %s_length = %d;' % (name, count) + print >>target + +def splitpath(path): + dir,file = os.path.split(path) + path = [] + assert(file) + while dir: + dir,base = os.path.split(dir) + path.insert(0, base) + return path, file + +def MakeEmbeddedPyFile(target, source, env): + target = file(str(target[0]), 'w') + + tree = {} + for src in source: + src = str(src) + path,pyfile = splitpath(src) + node = tree + for dir in path: + if not node.has_key(dir): + node[dir] = { } + node = node[dir] + + name,ext = pyfile.split('.') + if name == '__init__': + node['.hasinit'] = True + node[pyfile] = (src,name,ext,src) + + done = False + while not done: + done = True + for name,entry in tree.items(): + if not isinstance(entry, dict): continue + if entry.has_key('.hasinit'): continue + + done = False + del tree[name] + for key,val in entry.iteritems(): + if tree.has_key(key): + raise NameError, \ + "dir already has %s can't add it again" % key + tree[key] = val + + files = [] + def populate(node, path = []): + names = node.keys() + names.sort() + for name in names: + if name == '.hasinit': + continue + + entry = node[name] + if isinstance(entry, dict): + if not entry.has_key('.hasinit'): + raise NameError, 'package directory missing __init__.py' + populate(entry, path + [ name ]) + else: + pyfile,name,ext,filename = entry + files.append((pyfile, path, name, ext, filename)) + populate(tree) + + for pyfile, path, name, ext, filename in files: + WriteEmbeddedPyFile(target, pyfile, path, name, ext, filename) + +def MakeDefinesPyFile(target, source, env): + f = file(str(target[0]), 'w') + print >>f, "import __main__" + print >>f, "__main__.m5_build_env = ", + print >>f, source[0] + f.close() + +CFileCounter = 0 +def MakePythonCFile(target, source, env): + global CFileCounter + target = file(str(target[0]), 'w') + + print >>target, '''\ +#include "base/embedfile.hh" + +namespace { +''' + for src in source: + src = str(src) + fname = os.path.basename(src) + name = 'embedded_file%d' % CFileCounter + CFileCounter += 1 + WriteCFile(target, src, name) + print >>target, '''\ +EmbedMap %(name)s("%(fname)s", + %(name)s_string, %(name)s_length); + +''' % locals() + print >>target, '''\ + +/* namespace */ } +''' + +# base list of .py files to embed +embedded_py_files = [ os.path.join(env['ROOT'], 'util/pbs/jobfile.py') ] +# add all .py files in python/m5 +objpath = os.path.join(env['SRCDIR'], 'python', 'm5') +for root, dirs, files in os.walk(objpath, topdown=True): + for i,dir in enumerate(dirs): + if dir == 'SCCS': + del dirs[i] + break + + assert(root.startswith(objpath)) + for f in files: + if f.endswith('.py'): + embedded_py_files.append(os.path.join(root, f)) + +embedfile_hh = os.path.join(env['SRCDIR'], 'base/embedfile.hh') + +optionDict = dict([(opt, env[opt]) for opt in env.ExportOptions]) +env.Command('defines.py', Value(optionDict), MakeDefinesPyFile) + +env.Command('embedded_py.py', embedded_py_files, MakeEmbeddedPyFile) +env.Depends('embedded_py.cc', embedfile_hh) +env.Command('embedded_py.cc', + ['string_importer.py', 'defines.py', 'embedded_py.py'], + MakePythonCFile) diff --git a/python/m5/__init__.py b/src/python/m5/__init__.py index 9bb68a090..9bb68a090 100644 --- a/python/m5/__init__.py +++ b/src/python/m5/__init__.py diff --git a/python/m5/config.py b/src/python/m5/config.py index 1e25e0d09..1e25e0d09 100644 --- a/python/m5/config.py +++ b/src/python/m5/config.py diff --git a/python/m5/convert.py b/src/python/m5/convert.py index 73181e985..73181e985 100644 --- a/python/m5/convert.py +++ b/src/python/m5/convert.py diff --git a/python/m5/multidict.py b/src/python/m5/multidict.py index fd40ebbbd..fd40ebbbd 100644 --- a/python/m5/multidict.py +++ b/src/python/m5/multidict.py diff --git a/src/python/m5/objects/AlphaConsole.py b/src/python/m5/objects/AlphaConsole.py new file mode 100644 index 000000000..68e6089ab --- /dev/null +++ b/src/python/m5/objects/AlphaConsole.py @@ -0,0 +1,9 @@ +from m5 import * +from Device import BasicPioDevice + +class AlphaConsole(BasicPioDevice): + type = 'AlphaConsole' + cpu = Param.BaseCPU(Parent.any, "Processor") + disk = Param.SimpleDisk("Simple Disk") + sim_console = Param.SimConsole(Parent.any, "The Simulator Console") + system = Param.AlphaSystem(Parent.any, "system object") diff --git a/python/m5/objects/AlphaFullCPU.py b/src/python/m5/objects/AlphaFullCPU.py index d719bf783..d719bf783 100644 --- a/python/m5/objects/AlphaFullCPU.py +++ b/src/python/m5/objects/AlphaFullCPU.py diff --git a/python/m5/objects/AlphaTLB.py b/src/python/m5/objects/AlphaTLB.py index 5edf8e13d..5edf8e13d 100644 --- a/python/m5/objects/AlphaTLB.py +++ b/src/python/m5/objects/AlphaTLB.py diff --git a/src/python/m5/objects/BadDevice.py b/src/python/m5/objects/BadDevice.py new file mode 100644 index 000000000..9cb9a8f03 --- /dev/null +++ b/src/python/m5/objects/BadDevice.py @@ -0,0 +1,6 @@ +from m5 import * +from Device import BasicPioDevice + +class BadDevice(BasicPioDevice): + type = 'BadDevice' + devicename = Param.String("Name of device to error on") diff --git a/src/python/m5/objects/BaseCPU.py b/src/python/m5/objects/BaseCPU.py new file mode 100644 index 000000000..49cb2a8f3 --- /dev/null +++ b/src/python/m5/objects/BaseCPU.py @@ -0,0 +1,27 @@ +from m5 import * +class BaseCPU(SimObject): + type = 'BaseCPU' + abstract = True + mem = Param.MemObject("memory") + + if build_env['FULL_SYSTEM']: + dtb = Param.AlphaDTB("Data TLB") + itb = Param.AlphaITB("Instruction TLB") + system = Param.System(Parent.any, "system object") + cpu_id = Param.Int(-1, "CPU identifier") + else: + workload = VectorParam.Process("processes to run") + + max_insts_all_threads = Param.Counter(0, + "terminate when all threads have reached this inst count") + max_insts_any_thread = Param.Counter(0, + "terminate when any thread reaches this inst count") + max_loads_all_threads = Param.Counter(0, + "terminate when all threads have reached this load count") + max_loads_any_thread = Param.Counter(0, + "terminate when any thread reaches this load count") + + defer_registration = Param.Bool(False, + "defer registration with system (for sampling)") + + clock = Param.Clock(Parent.clock, "clock speed") diff --git a/python/m5/objects/BaseCache.py b/src/python/m5/objects/BaseCache.py index 79d21572a..79d21572a 100644 --- a/python/m5/objects/BaseCache.py +++ b/src/python/m5/objects/BaseCache.py diff --git a/src/python/m5/objects/Bridge.py b/src/python/m5/objects/Bridge.py new file mode 100644 index 000000000..ada715ce9 --- /dev/null +++ b/src/python/m5/objects/Bridge.py @@ -0,0 +1,9 @@ +from m5 import * +from MemObject import MemObject + +class Bridge(MemObject): + type = 'Bridge' + queue_size_a = Param.Int(16, "The number of requests to buffer") + queue_size_b = Param.Int(16, "The number of requests to buffer") + delay = Param.Latency('0ns', "The latency of this bridge") + write_ack = Param.Bool(False, "Should this bridge ack writes") diff --git a/src/python/m5/objects/Bus.py b/src/python/m5/objects/Bus.py new file mode 100644 index 000000000..8c5397281 --- /dev/null +++ b/src/python/m5/objects/Bus.py @@ -0,0 +1,6 @@ +from m5 import * +from MemObject import MemObject + +class Bus(MemObject): + type = 'Bus' + bus_id = Param.Int(0, "blah") diff --git a/python/m5/objects/CoherenceProtocol.py b/src/python/m5/objects/CoherenceProtocol.py index 7013000d6..7013000d6 100644 --- a/python/m5/objects/CoherenceProtocol.py +++ b/src/python/m5/objects/CoherenceProtocol.py diff --git a/src/python/m5/objects/Device.py b/src/python/m5/objects/Device.py new file mode 100644 index 000000000..2a71bbc65 --- /dev/null +++ b/src/python/m5/objects/Device.py @@ -0,0 +1,18 @@ +from m5 import * +from MemObject import MemObject + +class PioDevice(MemObject): + type = 'PioDevice' + abstract = True + platform = Param.Platform(Parent.any, "Platform this device is part of") + system = Param.System(Parent.any, "System this device is part of") + +class BasicPioDevice(PioDevice): + type = 'BasicPioDevice' + abstract = True + pio_addr = Param.Addr("Device Address") + pio_latency = Param.Tick(1, "Programmed IO latency in simticks") + +class DmaDevice(PioDevice): + type = 'DmaDevice' + abstract = True diff --git a/python/m5/objects/DiskImage.py b/src/python/m5/objects/DiskImage.py index 0d55e9329..0d55e9329 100644 --- a/python/m5/objects/DiskImage.py +++ b/src/python/m5/objects/DiskImage.py diff --git a/src/python/m5/objects/Ethernet.py b/src/python/m5/objects/Ethernet.py new file mode 100644 index 000000000..4286c71c8 --- /dev/null +++ b/src/python/m5/objects/Ethernet.py @@ -0,0 +1,115 @@ +from m5 import * +from Device import DmaDevice +from Pci import PciDevice + +class EtherInt(SimObject): + type = 'EtherInt' + abstract = True + peer = Param.EtherInt(NULL, "peer interface") + +class EtherLink(SimObject): + type = 'EtherLink' + int1 = Param.EtherInt("interface 1") + int2 = Param.EtherInt("interface 2") + delay = Param.Latency('0us', "packet transmit delay") + delay_var = Param.Latency('0ns', "packet transmit delay variability") + speed = Param.NetworkBandwidth('1Gbps', "link speed") + dump = Param.EtherDump(NULL, "dump object") + +class EtherBus(SimObject): + type = 'EtherBus' + loopback = Param.Bool(True, "send packet back to the sending interface") + dump = Param.EtherDump(NULL, "dump object") + speed = Param.NetworkBandwidth('100Mbps', "bus speed in bits per second") + +class EtherTap(EtherInt): + type = 'EtherTap' + bufsz = Param.Int(10000, "tap buffer size") + dump = Param.EtherDump(NULL, "dump object") + port = Param.UInt16(3500, "tap port") + +class EtherDump(SimObject): + type = 'EtherDump' + file = Param.String("dump file") + maxlen = Param.Int(96, "max portion of packet data to dump") + +if build_env['ALPHA_TLASER']: + + class EtherDev(DmaDevice): + type = 'EtherDev' + hardware_address = Param.EthernetAddr(NextEthernetAddr, + "Ethernet Hardware Address") + + dma_data_free = Param.Bool(False, "DMA of Data is free") + dma_desc_free = Param.Bool(False, "DMA of Descriptors is free") + dma_read_delay = Param.Latency('0us', "fixed delay for dma reads") + dma_read_factor = Param.Latency('0us', "multiplier for dma reads") + dma_write_delay = Param.Latency('0us', "fixed delay for dma writes") + dma_write_factor = Param.Latency('0us', "multiplier for dma writes") + dma_no_allocate = Param.Bool(True, "Should we allocate cache on read") + + rx_filter = Param.Bool(True, "Enable Receive Filter") + rx_delay = Param.Latency('1us', "Receive Delay") + tx_delay = Param.Latency('1us', "Transmit Delay") + + intr_delay = Param.Latency('0us', "Interrupt Delay") + payload_bus = Param.Bus(NULL, "The IO Bus to attach to for payload") + physmem = Param.PhysicalMemory(Parent.any, "Physical Memory") + tlaser = Param.Turbolaser(Parent.any, "Turbolaser") + + class EtherDevInt(EtherInt): + type = 'EtherDevInt' + device = Param.EtherDev("Ethernet device of this interface") + +class EtherDevBase(PciDevice): + hardware_address = Param.EthernetAddr(NextEthernetAddr, + "Ethernet Hardware Address") + + clock = Param.Clock('0ns', "State machine processor frequency") + + dma_read_delay = Param.Latency('0us', "fixed delay for dma reads") + dma_read_factor = Param.Latency('0us', "multiplier for dma reads") + dma_write_delay = Param.Latency('0us', "fixed delay for dma writes") + dma_write_factor = Param.Latency('0us', "multiplier for dma writes") + + rx_delay = Param.Latency('1us', "Receive Delay") + tx_delay = Param.Latency('1us', "Transmit Delay") + rx_fifo_size = Param.MemorySize('512kB', "max size of rx fifo") + tx_fifo_size = Param.MemorySize('512kB', "max size of tx fifo") + + rx_filter = Param.Bool(True, "Enable Receive Filter") + intr_delay = Param.Latency('10us', "Interrupt propagation delay") + rx_thread = Param.Bool(False, "dedicated kernel thread for transmit") + tx_thread = Param.Bool(False, "dedicated kernel threads for receive") + rss = Param.Bool(False, "Receive Side Scaling") + +class NSGigE(EtherDevBase): + type = 'NSGigE' + + dma_data_free = Param.Bool(False, "DMA of Data is free") + dma_desc_free = Param.Bool(False, "DMA of Descriptors is free") + dma_no_allocate = Param.Bool(True, "Should we allocate cache on read") + + +class NSGigEInt(EtherInt): + type = 'NSGigEInt' + device = Param.NSGigE("Ethernet device of this interface") + +class Sinic(EtherDevBase): + type = 'Sinic' + + rx_max_copy = Param.MemorySize('1514B', "rx max copy") + tx_max_copy = Param.MemorySize('16kB', "tx max copy") + rx_max_intr = Param.UInt32(10, "max rx packets per interrupt") + rx_fifo_threshold = Param.MemorySize('384kB', "rx fifo high threshold") + rx_fifo_low_mark = Param.MemorySize('128kB', "rx fifo low threshold") + tx_fifo_high_mark = Param.MemorySize('384kB', "tx fifo high threshold") + tx_fifo_threshold = Param.MemorySize('128kB', "tx fifo low threshold") + virtual_count = Param.UInt32(1, "Virtualized SINIC") + zero_copy = Param.Bool(False, "Zero copy receive") + delay_copy = Param.Bool(False, "Delayed copy transmit") + virtual_addr = Param.Bool(False, "Virtual addressing") + +class SinicInt(EtherInt): + type = 'SinicInt' + device = Param.Sinic("Ethernet device of this interface") diff --git a/src/python/m5/objects/Ide.py b/src/python/m5/objects/Ide.py new file mode 100644 index 000000000..2403e6d36 --- /dev/null +++ b/src/python/m5/objects/Ide.py @@ -0,0 +1,14 @@ +from m5 import * +from Pci import PciDevice + +class IdeID(Enum): vals = ['master', 'slave'] + +class IdeDisk(SimObject): + type = 'IdeDisk' + delay = Param.Latency('1us', "Fixed disk delay in microseconds") + driveID = Param.IdeID('master', "Drive ID") + image = Param.DiskImage("Disk image") + +class IdeController(PciDevice): + type = 'IdeController' + disks = VectorParam.IdeDisk("IDE disks attached to this controller") diff --git a/python/m5/objects/IntrControl.py b/src/python/m5/objects/IntrControl.py index 66c82c182..66c82c182 100644 --- a/python/m5/objects/IntrControl.py +++ b/src/python/m5/objects/IntrControl.py diff --git a/src/python/m5/objects/MemObject.py b/src/python/m5/objects/MemObject.py new file mode 100644 index 000000000..4d68243e6 --- /dev/null +++ b/src/python/m5/objects/MemObject.py @@ -0,0 +1,5 @@ +from m5 import * + +class MemObject(SimObject): + type = 'MemObject' + abstract = True diff --git a/python/m5/objects/MemTest.py b/src/python/m5/objects/MemTest.py index 34299faf0..34299faf0 100644 --- a/python/m5/objects/MemTest.py +++ b/src/python/m5/objects/MemTest.py diff --git a/src/python/m5/objects/Pci.py b/src/python/m5/objects/Pci.py new file mode 100644 index 000000000..85cefcd44 --- /dev/null +++ b/src/python/m5/objects/Pci.py @@ -0,0 +1,55 @@ +from m5 import * +from Device import BasicPioDevice, DmaDevice + +class PciConfigData(SimObject): + type = 'PciConfigData' + VendorID = Param.UInt16("Vendor ID") + DeviceID = Param.UInt16("Device ID") + Command = Param.UInt16(0, "Command") + Status = Param.UInt16(0, "Status") + Revision = Param.UInt8(0, "Device") + ProgIF = Param.UInt8(0, "Programming Interface") + SubClassCode = Param.UInt8(0, "Sub-Class Code") + ClassCode = Param.UInt8(0, "Class Code") + CacheLineSize = Param.UInt8(0, "System Cacheline Size") + LatencyTimer = Param.UInt8(0, "PCI Latency Timer") + HeaderType = Param.UInt8(0, "PCI Header Type") + BIST = Param.UInt8(0, "Built In Self Test") + + BAR0 = Param.UInt32(0x00, "Base Address Register 0") + BAR1 = Param.UInt32(0x00, "Base Address Register 1") + BAR2 = Param.UInt32(0x00, "Base Address Register 2") + BAR3 = Param.UInt32(0x00, "Base Address Register 3") + BAR4 = Param.UInt32(0x00, "Base Address Register 4") + BAR5 = Param.UInt32(0x00, "Base Address Register 5") + BAR0Size = Param.MemorySize32('0B', "Base Address Register 0 Size") + BAR1Size = Param.MemorySize32('0B', "Base Address Register 1 Size") + BAR2Size = Param.MemorySize32('0B', "Base Address Register 2 Size") + BAR3Size = Param.MemorySize32('0B', "Base Address Register 3 Size") + BAR4Size = Param.MemorySize32('0B', "Base Address Register 4 Size") + BAR5Size = Param.MemorySize32('0B', "Base Address Register 5 Size") + + CardbusCIS = Param.UInt32(0x00, "Cardbus Card Information Structure") + SubsystemID = Param.UInt16(0x00, "Subsystem ID") + SubsystemVendorID = Param.UInt16(0x00, "Subsystem Vendor ID") + ExpansionROM = Param.UInt32(0x00, "Expansion ROM Base Address") + InterruptLine = Param.UInt8(0x00, "Interrupt Line") + InterruptPin = Param.UInt8(0x00, "Interrupt Pin") + MaximumLatency = Param.UInt8(0x00, "Maximum Latency") + MinimumGrant = Param.UInt8(0x00, "Minimum Grant") + +class PciConfigAll(BasicPioDevice): + type = 'PciConfigAll' + +class PciDevice(DmaDevice): + type = 'PciDevice' + abstract = True + pci_bus = Param.Int("PCI bus") + pci_dev = Param.Int("PCI device number") + pci_func = Param.Int("PCI function code") + pio_latency = Param.Tick(1, "Programmed IO latency in simticks") + configdata = Param.PciConfigData(Parent.any, "PCI Config data") + configspace = Param.PciConfigAll(Parent.any, "PCI Configspace") + +class PciFake(PciDevice): + type = 'PciFake' diff --git a/src/python/m5/objects/PhysicalMemory.py b/src/python/m5/objects/PhysicalMemory.py new file mode 100644 index 000000000..c59910093 --- /dev/null +++ b/src/python/m5/objects/PhysicalMemory.py @@ -0,0 +1,8 @@ +from m5 import * +from MemObject import * + +class PhysicalMemory(MemObject): + type = 'PhysicalMemory' + range = Param.AddrRange("Device Address") + file = Param.String('', "memory mapped file") + latency = Param.Latency(Parent.clock, "latency of an access") diff --git a/python/m5/objects/Platform.py b/src/python/m5/objects/Platform.py index 4da0ffab4..4da0ffab4 100644 --- a/python/m5/objects/Platform.py +++ b/src/python/m5/objects/Platform.py diff --git a/src/python/m5/objects/Process.py b/src/python/m5/objects/Process.py new file mode 100644 index 000000000..60b00229e --- /dev/null +++ b/src/python/m5/objects/Process.py @@ -0,0 +1,27 @@ +from m5 import * +class Process(SimObject): + type = 'Process' + abstract = True + output = Param.String('cout', 'filename for stdout/stderr') + system = Param.System(Parent.any, "system process will run on") + +class LiveProcess(Process): + type = 'LiveProcess' + executable = Param.String('', "executable (overrides cmd[0] if set)") + cmd = VectorParam.String("command line (executable plus arguments)") + env = VectorParam.String('', "environment settings") + input = Param.String('cin', "filename for stdin") + +class AlphaLiveProcess(LiveProcess): + type = 'AlphaLiveProcess' + +class SparcLiveProcess(LiveProcess): + type = 'SparcLiveProcess' + +class MipsLiveProcess(LiveProcess): + type = 'MipsLiveProcess' + +class EioProcess(Process): + type = 'EioProcess' + chkpt = Param.String('', "EIO checkpoint file name (optional)") + file = Param.String("EIO trace file name") diff --git a/python/m5/objects/Repl.py b/src/python/m5/objects/Repl.py index afd256082..afd256082 100644 --- a/python/m5/objects/Repl.py +++ b/src/python/m5/objects/Repl.py diff --git a/src/python/m5/objects/Root.py b/src/python/m5/objects/Root.py new file mode 100644 index 000000000..205a93c76 --- /dev/null +++ b/src/python/m5/objects/Root.py @@ -0,0 +1,23 @@ +from m5 import * +from Serialize import Serialize +from Statistics import Statistics +from Trace import Trace +from ExeTrace import ExecutionTrace +from Debug import Debug + +class Root(SimObject): + type = 'Root' + clock = Param.RootClock('200MHz', "tick frequency") + max_tick = Param.Tick('0', "maximum simulation ticks (0 = infinite)") + progress_interval = Param.Tick('0', + "print a progress message every n ticks (0 = never)") + output_file = Param.String('cout', "file to dump simulator output to") + checkpoint = Param.String('', "checkpoint file to load") +# stats = Param.Statistics(Statistics(), "statistics object") +# trace = Param.Trace(Trace(), "trace object") +# serialize = Param.Serialize(Serialize(), "checkpoint generation options") + stats = Statistics() + trace = Trace() + exetrace = ExecutionTrace() + serialize = Serialize() + debug = Debug() diff --git a/python/m5/objects/SimConsole.py b/src/python/m5/objects/SimConsole.py index df3061908..df3061908 100644 --- a/python/m5/objects/SimConsole.py +++ b/src/python/m5/objects/SimConsole.py diff --git a/src/python/m5/objects/SimpleDisk.py b/src/python/m5/objects/SimpleDisk.py new file mode 100644 index 000000000..e34155ace --- /dev/null +++ b/src/python/m5/objects/SimpleDisk.py @@ -0,0 +1,5 @@ +from m5 import * +class SimpleDisk(SimObject): + type = 'SimpleDisk' + disk = Param.DiskImage("Disk Image") + system = Param.System(Parent.any, "Sysetm Pointer") diff --git a/src/python/m5/objects/System.py b/src/python/m5/objects/System.py new file mode 100644 index 000000000..622b5a870 --- /dev/null +++ b/src/python/m5/objects/System.py @@ -0,0 +1,21 @@ +from m5 import * + +class System(SimObject): + type = 'System' + physmem = Param.PhysicalMemory(Parent.any, "phsyical memory") + if build_env['FULL_SYSTEM']: + boot_cpu_frequency = Param.Frequency(Self.cpu[0].clock.frequency, + "boot processor frequency") + init_param = Param.UInt64(0, "numerical value to pass into simulator") + bin = Param.Bool(False, "is this system binned") + binned_fns = VectorParam.String([], "functions broken down and binned") + boot_osflags = Param.String("a", "boot flags to pass to the kernel") + kernel = Param.String("file that contains the kernel code") + readfile = Param.String("", "file to read startup script from") + +class AlphaSystem(System): + type = 'AlphaSystem' + console = Param.String("file that contains the console code") + pal = Param.String("file that contains palcode") + system_type = Param.UInt64("Type of system we are emulating") + system_rev = Param.UInt64("Revision of system we are emulating") diff --git a/src/python/m5/objects/Tsunami.py b/src/python/m5/objects/Tsunami.py new file mode 100644 index 000000000..27ea0bce8 --- /dev/null +++ b/src/python/m5/objects/Tsunami.py @@ -0,0 +1,27 @@ +from m5 import * +from Device import BasicPioDevice +from Platform import Platform + +class Tsunami(Platform): + type = 'Tsunami' +# pciconfig = Param.PciConfigAll("PCI configuration") + system = Param.System(Parent.any, "system") + +class TsunamiCChip(BasicPioDevice): + type = 'TsunamiCChip' + tsunami = Param.Tsunami(Parent.any, "Tsunami") + +class IsaFake(BasicPioDevice): + type = 'IsaFake' + pio_size = Param.Addr(0x8, "Size of address range") + +class TsunamiIO(BasicPioDevice): + type = 'TsunamiIO' + time = Param.UInt64(1136073600, + "System time to use (0 for actual time, default is 1/1/06)") + tsunami = Param.Tsunami(Parent.any, "Tsunami") + frequency = Param.Frequency('1024Hz', "frequency of interrupts") + +class TsunamiPChip(BasicPioDevice): + type = 'TsunamiPChip' + tsunami = Param.Tsunami(Parent.any, "Tsunami") diff --git a/src/python/m5/objects/Uart.py b/src/python/m5/objects/Uart.py new file mode 100644 index 000000000..54754aeb9 --- /dev/null +++ b/src/python/m5/objects/Uart.py @@ -0,0 +1,15 @@ +from m5 import * +from Device import BasicPioDevice + +class Uart(BasicPioDevice): + type = 'Uart' + abstract = True + sim_console = Param.SimConsole(Parent.any, "The console") + +class Uart8250(Uart): + type = 'Uart8250' + +if build_env['ALPHA_TLASER']: + class Uart8530(Uart): + type = 'Uart8530' + diff --git a/python/m5/smartdict.py b/src/python/m5/smartdict.py index cd38d7326..cd38d7326 100644 --- a/python/m5/smartdict.py +++ b/src/python/m5/smartdict.py diff --git a/sim/async.hh b/src/sim/async.hh index e0190a133..e0190a133 100644 --- a/sim/async.hh +++ b/src/sim/async.hh diff --git a/sim/builder.cc b/src/sim/builder.cc index 7dc118985..7dc118985 100644 --- a/sim/builder.cc +++ b/src/sim/builder.cc diff --git a/sim/builder.hh b/src/sim/builder.hh index b32e00e76..b32e00e76 100644 --- a/sim/builder.hh +++ b/src/sim/builder.hh diff --git a/src/sim/byteswap.hh b/src/sim/byteswap.hh new file mode 100644 index 000000000..a8c5da9d7 --- /dev/null +++ b/src/sim/byteswap.hh @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2004 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +//The purpose of this file is to provide endainness conversion utility +//functions. Depending on the endianness of the guest system, either +//the LittleEndianGuest or BigEndianGuest namespace is used. + +#ifndef __SIM_BYTE_SWAP_HH__ +#define __SIM_BYTE_SWAP_HH__ + +#include "sim/host.hh" + +// This lets us figure out what the byte order of the host system is +#if defined(linux) +#include <endian.h> +// If this is a linux system, lets used the optimized definitions if they exist. +// If one doesn't exist, we pretty much get what is listed below, so it all +// works out +#include <byteswap.h> +#else +#include <machine/endian.h> +#endif + +//These functions actually perform the swapping for parameters +//of various bit lengths +static inline uint64_t +swap_byte64(uint64_t x) +{ +#if defined(linux) + return bswap_64(x); +#else + return (uint64_t)((((uint64_t)(x) & 0xff) << 56) | + ((uint64_t)(x) & 0xff00ULL) << 40 | + ((uint64_t)(x) & 0xff0000ULL) << 24 | + ((uint64_t)(x) & 0xff000000ULL) << 8 | + ((uint64_t)(x) & 0xff00000000ULL) >> 8 | + ((uint64_t)(x) & 0xff0000000000ULL) >> 24 | + ((uint64_t)(x) & 0xff000000000000ULL) >> 40 | + ((uint64_t)(x) & 0xff00000000000000ULL) >> 56) ; +#endif +} + +static inline uint32_t +swap_byte32(uint32_t x) +{ +#if defined(linux) + return bswap_32(x); +#else + return (uint32_t)(((uint32_t)(x) & 0xff) << 24 | + ((uint32_t)(x) & 0xff00) << 8 | ((uint32_t)(x) & 0xff0000) >> 8 | + ((uint32_t)(x) & 0xff000000) >> 24); +#endif +} + +static inline uint16_t +swap_byte16(uint16_t x) +{ +#if defined(linux) + return bswap_16(x); +#else + return (uint16_t)(((uint16_t)(x) & 0xff) << 8 | + ((uint16_t)(x) & 0xff00) >> 8); +#endif +} + +//This lets the compiler figure out how to call the swap_byte functions above +//for different data types. +static inline uint64_t swap_byte(uint64_t x) {return swap_byte64(x);} +static inline int64_t swap_byte(int64_t x) {return swap_byte64((uint64_t)x);} +static inline uint32_t swap_byte(uint32_t x) {return swap_byte32(x);} +static inline int32_t swap_byte(int32_t x) {return swap_byte32((uint32_t)x);} +//This is to prevent the following two functions from compiling on +//64bit machines. It won't detect everything, so it should be changed. +#ifndef __x86_64__ +static inline long swap_byte(long x) {return swap_byte32((long)x);} +static inline unsigned long swap_byte(unsigned long x) + { return swap_byte32((unsigned long)x);} +#endif +static inline uint16_t swap_byte(uint16_t x) {return swap_byte32(x);} +static inline int16_t swap_byte(int16_t x) {return swap_byte16((uint16_t)x);} +static inline uint8_t swap_byte(uint8_t x) {return x;} +static inline int8_t swap_byte(int8_t x) {return x;} +static inline double swap_byte(double x) {return swap_byte64((uint64_t)x);} +static inline float swap_byte(float x) {return swap_byte32((uint32_t)x);} + +//The conversion functions with fixed endianness on both ends don't need to +//be in a namespace +template <typename T> static inline T betole(T value) {return swap_byte(value);} +template <typename T> static inline T letobe(T value) {return swap_byte(value);} + +//For conversions not involving the guest system, we can define the functions +//conditionally based on the BYTE_ORDER macro and outside of the namespaces +#if BYTE_ORDER == BIG_ENDIAN +template <typename T> static inline T htole(T value) {return swap_byte(value);} +template <typename T> static inline T letoh(T value) {return swap_byte(value);} +template <typename T> static inline T htobe(T value) {return value;} +template <typename T> static inline T betoh(T value) {return value;} +#elif BYTE_ORDER == LITTLE_ENDIAN +template <typename T> static inline T htole(T value) {return value;} +template <typename T> static inline T letoh(T value) {return value;} +template <typename T> static inline T htobe(T value) {return swap_byte(value);} +template <typename T> static inline T betoh(T value) {return swap_byte(value);} +#else + #error Invalid Endianess +#endif + +namespace BigEndianGuest +{ + template <typename T> + static inline T gtole(T value) {return betole(value);} + template <typename T> + static inline T letog(T value) {return letobe(value);} + template <typename T> + static inline T gtobe(T value) {return value;} + template <typename T> + static inline T betog(T value) {return value;} + template <typename T> + static inline T htog(T value) {return htobe(value);} + template <typename T> + static inline T gtoh(T value) {return betoh(value);} +} + +namespace LittleEndianGuest +{ + template <typename T> + static inline T gtole(T value) {return value;} + template <typename T> + static inline T letog(T value) {return value;} + template <typename T> + static inline T gtobe(T value) {return letobe(value);} + template <typename T> + static inline T betog(T value) {return betole(value);} + template <typename T> + static inline T htog(T value) {return htole(value);} + template <typename T> + static inline T gtoh(T value) {return letoh(value);} +} +#endif // __SIM_BYTE_SWAP_HH__ diff --git a/sim/debug.cc b/src/sim/debug.cc index 09e5346a8..09e5346a8 100644 --- a/sim/debug.cc +++ b/src/sim/debug.cc diff --git a/sim/debug.hh b/src/sim/debug.hh index 75b261d80..75b261d80 100644 --- a/sim/debug.hh +++ b/src/sim/debug.hh diff --git a/src/sim/eventq.cc b/src/sim/eventq.cc new file mode 100644 index 000000000..4bfd6face --- /dev/null +++ b/src/sim/eventq.cc @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2000-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <assert.h> + +#include <iostream> +#include <string> +#include <vector> + +#include "cpu/smt.hh" +#include "base/misc.hh" + +#include "sim/eventq.hh" +#include "base/trace.hh" +#include "sim/root.hh" + +using namespace std; + +// +// Main Event Queue +// +// Events on this queue are processed at the *beginning* of each +// cycle, before the pipeline simulation is performed. +// +EventQueue mainEventQueue("MainEventQueue"); + +void +EventQueue::insert(Event *event) +{ + if (head == NULL || event->when() < head->when() || + (event->when() == head->when() && + event->priority() <= head->priority())) { + event->next = head; + head = event; + } else { + Event *prev = head; + Event *curr = head->next; + + while (curr) { + if (event->when() <= curr->when() && + (event->when() < curr->when() || + event->priority() <= curr->priority())) + break; + + prev = curr; + curr = curr->next; + } + + event->next = curr; + prev->next = event; + } +} + +void +EventQueue::remove(Event *event) +{ + if (head == NULL) + return; + + if (head == event){ + head = event->next; + return; + } + + Event *prev = head; + Event *curr = head->next; + while (curr && curr != event) { + prev = curr; + curr = curr->next; + } + + if (curr == event) + prev->next = curr->next; +} + +void +EventQueue::serviceOne() +{ + Event *event = head; + event->clearFlags(Event::Scheduled); + head = event->next; + + // handle action + if (!event->squashed()) + event->process(); + else + event->clearFlags(Event::Squashed); + + if (event->getFlags(Event::AutoDelete) && !event->scheduled()) + delete event; +} + + +void +Event::serialize(std::ostream &os) +{ + SERIALIZE_SCALAR(_when); + SERIALIZE_SCALAR(_priority); + SERIALIZE_ENUM(_flags); +} + + +void +Event::unserialize(Checkpoint *cp, const string §ion) +{ + if (scheduled()) + deschedule(); + + UNSERIALIZE_SCALAR(_when); + UNSERIALIZE_SCALAR(_priority); + + // need to see if original event was in a scheduled, unsquashed + // state, but don't want to restore those flags in the current + // object itself (since they aren't immediately true) + UNSERIALIZE_ENUM(_flags); + bool wasScheduled = (_flags & Scheduled) && !(_flags & Squashed); + _flags &= ~(Squashed | Scheduled); + + if (wasScheduled) { + DPRINTF(Config, "rescheduling at %d\n", _when); + schedule(_when); + } +} + +void +EventQueue::serialize(ostream &os) +{ + std::list<Event *> eventPtrs; + + int numEvents = 0; + Event *event = head; + while (event) { + if (event->getFlags(Event::AutoSerialize)) { + eventPtrs.push_back(event); + paramOut(os, csprintf("event%d", numEvents++), event->name()); + } + event = event->next; + } + + SERIALIZE_SCALAR(numEvents); + + for (std::list<Event *>::iterator it=eventPtrs.begin(); + it != eventPtrs.end(); ++it) { + (*it)->nameOut(os); + (*it)->serialize(os); + } +} + +void +EventQueue::unserialize(Checkpoint *cp, const std::string §ion) +{ + int numEvents; + UNSERIALIZE_SCALAR(numEvents); + + std::string eventName; + for (int i = 0; i < numEvents; i++) { + // get the pointer value associated with the event + paramIn(cp, section, csprintf("event%d", i), eventName); + + // create the event based on its pointer value + Serializable::create(cp, eventName); + } +} + +void +EventQueue::dump() +{ + cprintf("============================================================\n"); + cprintf("EventQueue Dump (cycle %d)\n", curTick); + cprintf("------------------------------------------------------------\n"); + + if (empty()) + cprintf("<No Events>\n"); + else { + Event *event = head; + while (event) { + event->dump(); + event = event->next; + } + } + + cprintf("============================================================\n"); +} + +extern "C" +void +dumpMainQueue() +{ + mainEventQueue.dump(); +} + + +const char * +Event::description() +{ + return "generic"; +} + +#if TRACING_ON +void +Event::trace(const char *action) +{ + // This DPRINTF is unconditional because calls to this function + // are protected by an 'if (DTRACE(Event))' in the inlined Event + // methods. + // + // This is just a default implementation for derived classes where + // it's not worth doing anything special. If you want to put a + // more informative message in the trace, override this method on + // the particular subclass where you have the information that + // needs to be printed. + DPRINTFN("%s event %s @ %d\n", description(), action, when()); +} +#endif + +void +Event::dump() +{ + cprintf("Event (%s)\n", description()); + cprintf("Flags: %#x\n", _flags); +#if TRACING_ON + cprintf("Created: %d\n", when_created); +#endif + if (scheduled()) { +#if TRACING_ON + cprintf("Scheduled at %d\n", when_scheduled); +#endif + cprintf("Scheduled for %d, priority %d\n", when(), _priority); + } + else { + cprintf("Not Scheduled\n"); + } +} diff --git a/sim/eventq.hh b/src/sim/eventq.hh index 5fc73bb53..5fc73bb53 100644 --- a/sim/eventq.hh +++ b/src/sim/eventq.hh diff --git a/src/sim/faults.cc b/src/sim/faults.cc new file mode 100644 index 000000000..cb095f852 --- /dev/null +++ b/src/sim/faults.cc @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "base/misc.hh" +#include "sim/faults.hh" +#include "cpu/exec_context.hh" +#include "cpu/base.hh" + +#if !FULL_SYSTEM +void FaultBase::invoke(ExecContext * xc) +{ + fatal("fault (%s) detected @ PC 0x%08p", name(), xc->readPC()); +} +#else +void FaultBase::invoke(ExecContext * xc) +{ + DPRINTF(Fault, "Fault %s at PC: %#x\n", name(), xc->readPC()); + xc->getCpuPtr()->recordEvent(csprintf("Fault %s", name())); + + assert(!xc->misspeculating()); +} +#endif + +void UnimpFault::invoke(ExecContext * xc) +{ + panic("Unimpfault: %s\n", panicStr.c_str()); +} diff --git a/src/sim/faults.hh b/src/sim/faults.hh new file mode 100644 index 000000000..9b3bc9103 --- /dev/null +++ b/src/sim/faults.hh @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __FAULTS_HH__ +#define __FAULTS_HH__ + +#include "base/refcnt.hh" +#include "sim/stats.hh" +#include "config/full_system.hh" + +class ExecContext; +class FaultBase; +typedef RefCountingPtr<FaultBase> Fault; + +typedef const char * FaultName; +typedef Stats::Scalar<> FaultStat; + +// Each class has it's name statically define in _name, +// and has a virtual function to access it's name. +// The function is necessary because otherwise, all objects +// which are being accessed cast as a FaultBase * (namely +// all faults returned using the Fault type) will use the +// generic FaultBase name. + +class FaultBase : public RefCounted +{ + public: + virtual FaultName name() = 0; +#if FULL_SYSTEM + virtual void invoke(ExecContext * xc); +#else + virtual void invoke(ExecContext * xc); +#endif +// template<typename T> +// bool isA() {return dynamic_cast<T *>(this);} + virtual bool isMachineCheckFault() {return false;} + virtual bool isAlignmentFault() {return false;} +}; + +FaultBase * const NoFault = 0; + +class UnimpFault : public FaultBase +{ + private: + std::string panicStr; + public: + UnimpFault(std::string _str) + : panicStr(_str) + { } + + FaultName name() {return "Unimplemented simulator feature";} + void invoke(ExecContext * xc); +}; + +#endif // __FAULTS_HH__ diff --git a/src/sim/host.hh b/src/sim/host.hh new file mode 100644 index 000000000..48c977331 --- /dev/null +++ b/src/sim/host.hh @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * Defines host-dependent types: + * Counter, Tick, and (indirectly) {int,uint}{8,16,32,64}_t. + */ + +#ifndef __HOST_HH__ +#define __HOST_HH__ + +#include <inttypes.h> + +/** uint64_t constant */ +#define ULL(N) ((uint64_t)N##ULL) +/** int64_t constant */ +#define LL(N) (((int64_t)N##LL) + +/** Statistics counter type. Not much excuse for not using a 64-bit + * integer here, but if you're desperate and only run short + * simulations you could make this 32 bits. + */ +typedef int64_t Counter; + +/** + * Clock cycle count type. + * @note using an unsigned breaks the cache. + */ +typedef int64_t Tick; + +/** + * Address type + * This will probably be moved somewhere else in the near future. + * This should be at least as big as the biggest address width in use + * in the system, which will probably be 64 bits. + */ +typedef uint64_t Addr; + +const Addr MaxAddr = (Addr)-1; + +#endif // __HOST_H__ diff --git a/src/sim/main.cc b/src/sim/main.cc new file mode 100644 index 000000000..aecc171ed --- /dev/null +++ b/src/sim/main.cc @@ -0,0 +1,433 @@ +/* + * Copyright (c) 2000-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/// +/// @file sim/main.cc +/// +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> +#include <libgen.h> +#include <stdlib.h> +#include <signal.h> + +#include <list> +#include <string> +#include <vector> + +#include "base/copyright.hh" +#include "base/embedfile.hh" +#include "base/inifile.hh" +#include "base/misc.hh" +#include "base/output.hh" +#include "base/pollevent.hh" +#include "base/statistics.hh" +#include "base/str.hh" +#include "base/time.hh" +#include "cpu/base.hh" +#include "cpu/smt.hh" +#include "python/pyconfig.hh" +#include "sim/async.hh" +#include "sim/builder.hh" +#include "sim/configfile.hh" +#include "sim/host.hh" +#include "sim/sim_events.hh" +#include "sim/sim_exit.hh" +#include "sim/sim_object.hh" +#include "sim/stat_control.hh" +#include "sim/stats.hh" +#include "sim/root.hh" + +using namespace std; + +// See async.h. +volatile bool async_event = false; +volatile bool async_dump = false; +volatile bool async_dumpreset = false; +volatile bool async_exit = false; +volatile bool async_io = false; +volatile bool async_alarm = false; + +/// Stats signal handler. +void +dumpStatsHandler(int sigtype) +{ + async_event = true; + async_dump = true; +} + +void +dumprstStatsHandler(int sigtype) +{ + async_event = true; + async_dumpreset = true; +} + +/// Exit signal handler. +void +exitNowHandler(int sigtype) +{ + async_event = true; + async_exit = true; +} + +/// Abort signal handler. +void +abortHandler(int sigtype) +{ + cerr << "Program aborted at cycle " << curTick << endl; + +#if TRACING_ON + // dump trace buffer, if there is one + Trace::theLog.dump(cerr); +#endif +} + +/// Simulator executable name +char *myProgName = ""; + +/// Show brief help message. +void +showBriefHelp(ostream &out) +{ + char *prog = basename(myProgName); + + ccprintf(out, "Usage:\n"); + ccprintf(out, +"%s [-d <dir>] [-E <var>[=<val>]] [-I <dir>] [-P <python>]\n" +" [--<var>=<val>] <config file>\n" +"\n" +" -d set the output directory to <dir>\n" +" -E set the environment variable <var> to <val> (or 'True')\n" +" -I add the directory <dir> to python's path\n" +" -P execute <python> directly in the configuration\n" +" --var=val set the python variable <var> to '<val>'\n" +" <configfile> config file name (ends in .py)\n\n", + prog); + + ccprintf(out, "%s -X\n -X extract embedded files\n\n", prog); + ccprintf(out, "%s -h\n -h print short help\n\n", prog); +} + +/// Print welcome message. +void +sayHello(ostream &out) +{ + extern const char *compileDate; // from date.cc + + ccprintf(out, "M5 Simulator System\n"); + // display copyright + ccprintf(out, "%s\n", briefCopyright); + ccprintf(out, "M5 compiled on %d\n", compileDate); + + char *host = getenv("HOSTNAME"); + if (!host) + host = getenv("HOST"); + + if (host) + ccprintf(out, "M5 executing on %s\n", host); + + ccprintf(out, "M5 simulation started %s\n", Time::start); +} + +/// +/// Echo the command line for posterity in such a way that it can be +/// used to rerun the same simulation (given the same .ini files). +/// +void +echoCommandLine(int argc, char **argv, ostream &out) +{ + out << "command line: " << argv[0]; + for (int i = 1; i < argc; i++) { + string arg(argv[i]); + + out << ' '; + + // If the arg contains spaces, we need to quote it. + // The rest of this is overkill to make it look purty. + + // print dashes first outside quotes + int non_dash_pos = arg.find_first_not_of("-"); + out << arg.substr(0, non_dash_pos); // print dashes + string body = arg.substr(non_dash_pos); // the rest + + // if it's an assignment, handle the lhs & rhs separately + int eq_pos = body.find("="); + if (eq_pos == string::npos) { + out << quote(body); + } + else { + string lhs(body.substr(0, eq_pos)); + string rhs(body.substr(eq_pos + 1)); + + out << quote(lhs) << "=" << quote(rhs); + } + } + out << endl << endl; +} + +char * +getOptionString(int &index, int argc, char **argv) +{ + char *option = argv[index] + 2; + if (*option != '\0') + return option; + + // We didn't find an argument, it must be in the next variable. + if (++index >= argc) + panic("option string for option '%s' not found", argv[index - 1]); + + return argv[index]; +} + +int +main(int argc, char **argv) +{ + // Save off program name + myProgName = argv[0]; + + signal(SIGFPE, SIG_IGN); // may occur on misspeculated paths + signal(SIGTRAP, SIG_IGN); + signal(SIGUSR1, dumpStatsHandler); // dump intermediate stats + signal(SIGUSR2, dumprstStatsHandler); // dump and reset stats + signal(SIGINT, exitNowHandler); // dump final stats and exit + signal(SIGABRT, abortHandler); + + bool configfile_found = false; + PythonConfig pyconfig; + string outdir; + + if (argc < 2) { + showBriefHelp(cerr); + exit(1); + } + + sayHello(cerr); + + // Parse command-line options. + // Since most of the complex options are handled through the + // config database, we don't mess with getopts, and just parse + // manually. + for (int i = 1; i < argc; ++i) { + char *arg_str = argv[i]; + + // if arg starts with '--', parse as a special python option + // of the format --<python var>=<string value>, if the arg + // starts with '-', it should be a simulator option with a + // format similar to getopt. In any other case, treat the + // option as a configuration file name and load it. + if (arg_str[0] == '-' && arg_str[1] == '-') { + string str = &arg_str[2]; + string var, val; + + if (!split_first(str, var, val, '=')) + panic("Could not parse configuration argument '%s'\n" + "Expecting --<variable>=<value>\n", arg_str); + + pyconfig.setVariable(var, val); + } else if (arg_str[0] == '-') { + char *option; + string var, val; + + // switch on second char + switch (arg_str[1]) { + case 'd': + outdir = getOptionString(i, argc, argv); + break; + + case 'h': + showBriefHelp(cerr); + exit(1); + + case 'E': + option = getOptionString(i, argc, argv); + if (!split_first(option, var, val, '=')) + val = "True"; + + if (setenv(var.c_str(), val.c_str(), true) == -1) + panic("setenv: %s\n", strerror(errno)); + break; + + case 'I': + option = getOptionString(i, argc, argv); + pyconfig.addPath(option); + break; + + case 'P': + option = getOptionString(i, argc, argv); + pyconfig.writeLine(option); + break; + + case 'X': { + list<EmbedFile> lst; + EmbedMap::all(lst); + list<EmbedFile>::iterator i = lst.begin(); + list<EmbedFile>::iterator end = lst.end(); + + while (i != end) { + cprintf("Embedded File: %s\n", i->name); + cout.write(i->data, i->length); + ++i; + } + + return 0; + } + + default: + showBriefHelp(cerr); + panic("invalid argument '%s'\n", arg_str); + } + } else { + string file(arg_str); + string base, ext; + + if (!split_last(file, base, ext, '.') || ext != "py") + panic("Config file '%s' must end in '.py'\n", file); + + pyconfig.load(file); + configfile_found = true; + } + } + + if (outdir.empty()) { + char *env = getenv("OUTPUT_DIR"); + outdir = env ? env : "."; + } + + simout.setDirectory(outdir); + + char *env = getenv("CONFIG_OUTPUT"); + if (!env) + env = "config.out"; + configStream = simout.find(env); + + if (!configfile_found) + panic("no configuration file specified!"); + + // The configuration database is now complete; start processing it. + IniFile inifile; + if (!pyconfig.output(inifile)) + panic("Error processing python code"); + + // Initialize statistics database + Stats::InitSimStats(); + + // Now process the configuration hierarchy and create the SimObjects. + ConfigHierarchy configHierarchy(inifile); + configHierarchy.build(); + configHierarchy.createSimObjects(); + + // Parse and check all non-config-hierarchy parameters. + ParamContext::parseAllContexts(inifile); + ParamContext::checkAllContexts(); + + // Print hello message to stats file if it's actually a file. If + // it's not (i.e. it's cout or cerr) then we already did it above. + if (simout.isFile(*outputStream)) + sayHello(*outputStream); + + // Echo command line and all parameter settings to stats file as well. + echoCommandLine(argc, argv, *outputStream); + ParamContext::showAllContexts(*configStream); + + // Any objects that can't connect themselves until after construction should + // do so now + SimObject::connectAll(); + + // Do a second pass to finish initializing the sim objects + SimObject::initAll(); + + // Restore checkpointed state, if any. + configHierarchy.unserializeSimObjects(); + + // Done processing the configuration database. + // Check for unreferenced entries. + if (inifile.printUnreferenced()) + panic("unreferenced sections/entries in the intermediate ini file"); + + SimObject::regAllStats(); + + // uncomment the following to get PC-based execution-time profile +#ifdef DO_PROFILE + init_profile((char *)&_init, (char *)&_fini); +#endif + + // Check to make sure that the stats package is properly initialized + Stats::check(); + + // Reset to put the stats in a consistent state. + Stats::reset(); + + warn("Entering event queue. Starting simulation...\n"); + SimStartup(); + while (!mainEventQueue.empty()) { + assert(curTick <= mainEventQueue.nextTick() && + "event scheduled in the past"); + + // forward current cycle to the time of the first event on the + // queue + curTick = mainEventQueue.nextTick(); + mainEventQueue.serviceOne(); + + if (async_event) { + async_event = false; + if (async_dump) { + async_dump = false; + + using namespace Stats; + SetupEvent(Dump, curTick); + } + + if (async_dumpreset) { + async_dumpreset = false; + + using namespace Stats; + SetupEvent(Dump | Reset, curTick); + } + + if (async_exit) { + async_exit = false; + new SimExitEvent("User requested STOP"); + } + + if (async_io || async_alarm) { + async_io = false; + async_alarm = false; + pollQueue.service(); + } + } + } + + // This should never happen... every conceivable way for the + // simulation to terminate (hit max cycles/insts, signal, + // simulated system halts/exits) generates an exit event, so we + // should never run out of events on the queue. + exitNow("no events on event loop! All CPUs must be idle.", 1); + + return 0; +} diff --git a/src/sim/param.cc b/src/sim/param.cc new file mode 100644 index 000000000..8998d7d77 --- /dev/null +++ b/src/sim/param.cc @@ -0,0 +1,793 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <algorithm> +#include <cassert> +#include <list> +#include <string> +#include <vector> + +#include "base/inifile.hh" +#include "base/misc.hh" +#include "base/range.hh" +#include "base/str.hh" +#include "base/trace.hh" +#include "sim/config_node.hh" +#include "sim/configfile.hh" +#include "sim/param.hh" +#include "sim/sim_object.hh" + +using namespace std; + + +//////////////////////////////////////////////////////////////////////// +// +// BaseParam member definitions +// +//////////////////////////////////////////////////////////////////////// + +void +BaseParam::die(const string &err) const +{ + context->printErrorProlog(cerr); + cerr << " parameter '" << name << "': " + << err << endl; + abort(); +} + + +//////////////////////////////////////////////////////////////////////// +// +// Param<T> and VectorParam<T> member definitions +// +// We implement parsing & displaying values for various parameter +// types T using a set of overloaded functions: +// +// - parseParam(string s, T &value) parses s into value +// - showParam(ostream &os, T &value) displays value on os +// +// By making these independent functions, we can reuse the same code +// for type T in both Param<T> and VectorParam<T>. +// +// For enum types, the parseParam function requires additional +// arguments, in which case we must specialize the Param<T>::parse and +// VectorParam<T>::parse calls as well. +// +// Type-specific instances come first, followed by more generic +// templated versions and their instantiations. +// +//////////////////////////////////////////////////////////////////////// + +// +// The base implementations use to_number for parsing and '<<' for +// displaying, suitable for integer types. +// +template <class T> +bool +parseParam(const string &s, T &value) +{ + return to_number(s, value); +} + +template <class T> +void +showParam(ostream &os, T const &value) +{ + os << value; +} + +// +// Template specializations: +// - char (8-bit integer) +// - floating-point types +// - bool +// - string +// + +// Treat 8-bit ints (chars) as ints on output, not as chars +template <> +void +showParam(ostream &os, const char &value) +{ + os << (int)value; +} + + +template <> +void +showParam(ostream &os, const unsigned char &value) +{ + os << (unsigned int)value; +} + + +// Use sscanf() for FP types as to_number() only handles integers +template <> +bool +parseParam(const string &s, float &value) +{ + return (sscanf(s.c_str(), "%f", &value) == 1); +} + +template <> +bool +parseParam(const string &s, double &value) +{ + return (sscanf(s.c_str(), "%lf", &value) == 1); +} + +// Be flexible about what we take for bool +template <> +bool +parseParam(const string &s, bool &value) +{ + const string &ls = to_lower(s); + + if (ls == "true" || ls == "t" || ls == "yes" || ls == "y" || ls == "1") { + value = true; + return true; + } + + if (ls == "false" || ls == "f" || ls == "no" || ls == "n" || ls == "0") { + value = false; + return true; + } + + return false; +} + +// Display bools as strings +template <> +void +showParam(ostream &os, const bool &value) +{ + os << (value ? "true" : "false"); +} + + +// String requires no processing to speak of +template <> +bool +parseParam(const string &s, string &value) +{ + value = s; + return true; +} + +template <> +bool +parseParam(const string &s, Range<uint32_t> &value) +{ + value = s; + return value.valid(); +} + +template <> +bool +parseParam(const string &s, Range<uint64_t> &value) +{ + value = s; + return value.valid(); +} + +// +// End of parseParam/showParam definitions. Now we move on to +// incorporate them into the Param/VectorParam parse() and showValue() +// methods. +// + +// These definitions for Param<T>::parse and VectorParam<T>::parse +// work for any type for which parseParam() takes only two arguments +// (i.e., all the fundamental types like int, bool, etc.), thanks to +// overloading. +template <class T> +void +Param<T>::parse(const string &s) +{ + if (parseParam(s, value)) { + wasSet = true; + } + else { + string err("could not parse \""); + + err += s; + err += "\""; + + die(err); + } +} + +template <class T> +void +VectorParam<T>::parse(const string &s) +{ + if (s.empty()) { + wasSet = true; + return; + } + + vector<string> tokens; + + tokenize(tokens, s, ' '); + + value.resize(tokens.size()); + + for (int i = 0; i < tokens.size(); i++) { + // need to parse into local variable to handle vector<bool>, + // for which operator[] returns a special reference class + // that's not the same as 'bool&', (since it's a packed + // vector) + T scalar_value; + if (!parseParam(tokens[i], scalar_value)) { + string err("could not parse \""); + + err += s; + err += "\""; + + die(err); + } + + // assign parsed value to vector + value[i] = scalar_value; + } + + wasSet = true; +} + +// These definitions for Param<T>::showValue() and +// VectorParam<T>::showValue() work for any type where showParam() +// takes only two arguments (i.e., everything but the SimpleEnum and +// MappedEnum classes). +template <class T> +void +Param<T>::showValue(ostream &os) const +{ + showParam(os, value); +} + +template <class T> +void +VectorParam<T>::showValue(ostream &os) const +{ + for (int i = 0; i < value.size(); i++) { + if (i != 0) { + os << " "; + } + showParam(os, value[i]); + } +} + + +#ifdef INSURE_BUILD +#define INSTANTIATE_PARAM_TEMPLATES(type, typestr) \ +void Param<type>::showType(ostream &os) const { os << typestr; } \ +void VectorParam<type>::showType(ostream &os) const { \ + os << "vector of " << typestr; \ +} \ +template Param<type>; \ +template VectorParam<type>; + +#else +// instantiate all four methods (parse/show, scalar/vector) for basic +// types that can use the above templates +#define INSTANTIATE_PARAM_TEMPLATES(type, typestr) \ +template bool parseParam<type>(const string &s, type &value); \ +template void showParam<type>(ostream &os, type const &value); \ +template void Param<type>::parse(const string &); \ +template void VectorParam<type>::parse(const string &); \ +template void Param<type>::showValue(ostream &) const; \ +template void VectorParam<type>::showValue(ostream &) const; \ +template <> void Param<type>::showType(ostream &os) const { os << typestr; } \ +template <> void VectorParam<type>::showType(ostream &os) const { \ + os << "vector of " << typestr; \ +} +#endif + +INSTANTIATE_PARAM_TEMPLATES(unsigned long long, "ull") +INSTANTIATE_PARAM_TEMPLATES(signed long long, "sll") +INSTANTIATE_PARAM_TEMPLATES(unsigned long, "uns long") +INSTANTIATE_PARAM_TEMPLATES(signed long, "long") +INSTANTIATE_PARAM_TEMPLATES(unsigned int, "uns") +INSTANTIATE_PARAM_TEMPLATES(signed int, "int") +INSTANTIATE_PARAM_TEMPLATES(unsigned short, "uns short") +INSTANTIATE_PARAM_TEMPLATES(signed short, "short") +INSTANTIATE_PARAM_TEMPLATES(unsigned char, "uns char") +INSTANTIATE_PARAM_TEMPLATES(signed char, "char") + +INSTANTIATE_PARAM_TEMPLATES(float, "float") +INSTANTIATE_PARAM_TEMPLATES(double, "double") + +INSTANTIATE_PARAM_TEMPLATES(bool, "bool") +INSTANTIATE_PARAM_TEMPLATES(string, "string") + +INSTANTIATE_PARAM_TEMPLATES(Range<uint64_t>, "uint64 range") +INSTANTIATE_PARAM_TEMPLATES(Range<uint32_t>, "uint32 range") + +#undef INSTANTIATE_PARAM_TEMPLATES + +// +// SimpleEnumParam & MappedEnumParam must specialize their parse(), +// showValue(), and showType() methods. +// + +// +// SimpleEnumParam & SimpleEnumVectorParam +// +bool +parseEnumParam(const char *const *map, const int num_values, + const string &s, int &value) +{ + for (int i = 0; i < num_values; ++i) { + if (s == map[i]) { + value = i; + return true; + } + } + + return false; +} + +void +showEnumParam(ostream &os, + const char *const *map, const int num_values, + int value) +{ + assert(0 <= value && value < num_values); + os << map[value]; +} + +void +showEnumType(ostream &os, + const char *const *map, const int num_values) +{ + os << "{" << map[0]; + for (int i = 1; i < num_values; ++i) + os << "," << map[i]; + + os << "}"; +} + + +// +// MappedEnumParam & MappedEnumVectorParam +// +bool +parseEnumParam(const EnumParamMap *map, const int num_values, + const string &s, int &value) +{ + for (int i = 0; i < num_values; ++i) { + if (s == map[i].name) { + value = map[i].value; + return true; + } + } + + return false; +} + +void +showEnumParam(ostream &os, + const EnumParamMap *map, const int num_values, + int value) +{ + for (int i = 0; i < num_values; ++i) { + if (value == map[i].value) { + os << map[i].name; + return; + } + } + + // if we can't find a reverse mapping just print the int value + os << value; +} + +void +showEnumType(ostream &os, + const EnumParamMap *map, const int num_values) +{ + os << "{" << map[0].name; + for (int i = 1; i < num_values; ++i) + os << "," << map[i].name; + + os << "}"; +} + + +template <class Map> +void +EnumParam<Map>::parse(const string &s) +{ + if (parseEnumParam(map, num_values, s, value)) { + wasSet = true; + } else { + string err("no match for enum string \""); + + err += s; + err += "\""; + + die(err); + } +} + +template <class Map> +void +EnumVectorParam<Map>::parse(const string &s) +{ + vector<string> tokens; + + if (s.empty()) { + wasSet = true; + return; + } + + tokenize(tokens, s, ' '); + + value.resize(tokens.size()); + + for (int i = 0; i < tokens.size(); i++) { + if (!parseEnumParam(map, num_values, tokens[i], value[i])) { + string err("no match for enum string \""); + + err += s; + err += "\""; + + die(err); + } + } + + wasSet = true; +} + +template <class Map> +void +EnumParam<Map>::showValue(ostream &os) const +{ + showEnumParam(os, map, num_values, value); +} + +template <class Map> +void +EnumVectorParam<Map>::showValue(ostream &os) const +{ + for (int i = 0; i < value.size(); i++) { + if (i != 0) { + os << " "; + } + showEnumParam(os, map, num_values, value[i]); + } +} + +template <class Map> +void +EnumParam<Map>::showType(ostream &os) const +{ + showEnumType(os, map, num_values); +} + +template <class Map> +void +EnumVectorParam<Map>::showType(ostream &os) const +{ + os << "vector of"; + showEnumType(os, map, num_values); +} + +template class EnumParam<const char *>; +template class EnumVectorParam<const char *>; + +template class EnumParam<EnumParamMap>; +template class EnumVectorParam<EnumParamMap>; + +//////////////////////////////////////////////////////////////////////// +// +// SimObjectBaseParam methods +// +//////////////////////////////////////////////////////////////////////// + +bool +parseSimObjectParam(ParamContext *context, const string &s, SimObject *&value) +{ + SimObject *obj; + + if (to_lower(s) == "null") { + // explicitly set to null by user; assume that's OK + obj = NULL; + } + else { + obj = context->resolveSimObject(s); + + if (obj == NULL) + return false; + } + + value = obj; + return true; +} + + +void +SimObjectBaseParam::showValue(ostream &os, SimObject *value) const +{ + os << (value ? value->name() : "null"); +} + +void +SimObjectBaseParam::parse(const string &s, SimObject *&value) +{ + if (parseSimObjectParam(context, s, value)) { + wasSet = true; + } + else { + string err("could not resolve object name \""); + + err += s; + err += "\""; + + die(err); + } +} + +void +SimObjectBaseParam::parse(const string &s, vector<SimObject *>&value) +{ + vector<string> tokens; + + tokenize(tokens, s, ' '); + + value.resize(tokens.size()); + + for (int i = 0; i < tokens.size(); i++) { + if (!parseSimObjectParam(context, tokens[i], value[i])) { + string err("could not resolve object name \""); + + err += s; + err += "\""; + + die(err); + } + } + + wasSet = true; +} + +//////////////////////////////////////////////////////////////////////// +// +// ParamContext member definitions +// +//////////////////////////////////////////////////////////////////////// + +list<ParamContext *> *ParamContext::ctxList = NULL; + +ParamContext::ParamContext(const string &_iniSection, InitPhase _initPhase) + : iniFilePtr(NULL), // initialized on call to parseParams() + iniSection(_iniSection), paramList(NULL), + initPhase(_initPhase) +{ + // Put this context on global list for initialization + if (initPhase != NoAutoInit) { + if (ctxList == NULL) + ctxList = new list<ParamContext *>(); + + // keep list sorted by ascending initPhase values + list<ParamContext *>::iterator i = ctxList->begin(); + list<ParamContext *>::iterator end = ctxList->end(); + for (; i != end; ++i) { + if (initPhase <= (*i)->initPhase) { + // found where we want to insert + break; + } + } + // (fall through case: insert at end) + ctxList->insert(i, this); + } +} + + +void +ParamContext::addParam(BaseParam *param) +{ + getParamList()->push_back(param); +} + + +void +ParamContext::parseParams(IniFile &iniFile) +{ + iniFilePtr = &iniFile; // set object member + + ParamList::iterator i; + + for (i = getParamList()->begin(); i != getParamList()->end(); ++i) { + string string_value; + + if (iniFile.find(iniSection, (*i)->name, string_value)) + (*i)->parse(string_value); + } +} + + +// Check parameter values for validity & consistency. Default +// implementation is no-op; derive subclass & override to add +// actual functionality here. +void +ParamContext::checkParams() +{ + // nada +} + + +// Clean up context-related objects at end of execution. Default +// implementation is no-op; derive subclass & override to add actual +// functionality here. +void +ParamContext::cleanup() +{ + // nada +} + + +void +ParamContext::describeParams(ostream &os) +{ + ParamList::iterator i; + + for (i = getParamList()->begin(); i != getParamList()->end(); ++i) { + BaseParam *p = *i; + + os << p->name << " ("; + p->showType(os); + os << "): " << p->description << "\n"; + } +} + + + +void +ParamContext::showParams(ostream &os) +{ + ParamList::iterator i; + + for (i = getParamList()->begin(); i != getParamList()->end(); ++i) { + BaseParam *p = *i; + + if (p->isValid()) { + os << p->name << "="; + p->showValue(os); + os << endl; + } + else { + os << "// "<< p->name << " not specified" << endl; + } + } +} + + +void +ParamContext::printErrorProlog(ostream &os) +{ + os << "Parameter error in section [" << iniSection << "]: " << endl; +} + +// +// Resolve an object name to a SimObject pointer. The object will be +// created as a side-effect if necessary. If the name contains a +// colon (e.g., "iq:IQ"), then the object is local (invisible to +// outside this context). If there is no colon, the name needs to be +// resolved through the configuration hierarchy (only possible for +// SimObjectBuilder objects, which return non-NULL for configNode()). +// +SimObject * +ParamContext::resolveSimObject(const string &name) +{ + ConfigNode *n = getConfigNode(); + return n ? n->resolveSimObject(name) : NULL; +} + + +// +// static method: call parseParams() on all registered contexts +// +void +ParamContext::parseAllContexts(IniFile &iniFile) +{ + list<ParamContext *>::iterator iter; + + for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) { + ParamContext *pc = *iter; + + pc->parseParams(iniFile); + } +} + + +// +// static method: call checkParams() on all registered contexts +// +void +ParamContext::checkAllContexts() +{ + list<ParamContext *>::iterator iter; + + for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) { + ParamContext *pc = *iter; + + pc->checkParams(); + } +} + + +// +// static method: call showParams() on all registered contexts +// +void +ParamContext::showAllContexts(ostream &os) +{ + list<ParamContext *>::iterator iter; + + for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) { + ParamContext *pc = *iter; + + os << "[" << pc->iniSection << "]" << endl; + pc->showParams(os); + os << endl; + } +} + + +// +// static method: call cleanup() on all registered contexts +// +void +ParamContext::cleanupAllContexts() +{ + list<ParamContext *>::iterator iter; + + for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) { + ParamContext *pc = *iter; + + pc->cleanup(); + } +} + + +// +// static method: call describeParams() on all registered contexts +// +void +ParamContext::describeAllContexts(ostream &os) +{ + list<ParamContext *>::iterator iter; + + for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) { + ParamContext *pc = *iter; + + os << "[" << pc->iniSection << "]\n"; + pc->describeParams(os); + os << endl; + } +} diff --git a/sim/param.hh b/src/sim/param.hh index 4a1b8bda1..4a1b8bda1 100644 --- a/sim/param.hh +++ b/src/sim/param.hh diff --git a/src/sim/process.cc b/src/sim/process.cc new file mode 100644 index 000000000..1da525093 --- /dev/null +++ b/src/sim/process.cc @@ -0,0 +1,361 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <unistd.h> +#include <fcntl.h> + +#include <string> + +#include "base/intmath.hh" +#include "base/loader/object_file.hh" +#include "base/loader/symtab.hh" +#include "base/statistics.hh" +#include "config/full_system.hh" +#include "cpu/exec_context.hh" +#include "mem/page_table.hh" +#include "mem/physical.hh" +#include "mem/translating_port.hh" +#include "sim/builder.hh" +#include "sim/process.hh" +#include "sim/stats.hh" +#include "sim/syscall_emul.hh" +#include "sim/system.hh" + +using namespace std; +using namespace TheISA; + +// +// The purpose of this code is to fake the loader & syscall mechanism +// when there's no OS: thus there's no resone to use it in FULL_SYSTEM +// mode when we do have an OS +// +#if FULL_SYSTEM +#error "process.cc not compatible with FULL_SYSTEM" +#endif + +// current number of allocated processes +int num_processes = 0; + +Process::Process(const string &nm, + System *_system, + int stdin_fd, // initial I/O descriptors + int stdout_fd, + int stderr_fd) + : SimObject(nm), system(_system) +{ + // initialize first 3 fds (stdin, stdout, stderr) + fd_map[STDIN_FILENO] = stdin_fd; + fd_map[STDOUT_FILENO] = stdout_fd; + fd_map[STDERR_FILENO] = stderr_fd; + + // mark remaining fds as free + for (int i = 3; i <= MAX_FD; ++i) { + fd_map[i] = -1; + } + + mmap_start = mmap_end = 0; + nxm_start = nxm_end = 0; + pTable = new PageTable(system); + // other parameters will be initialized when the program is loaded +} + + +void +Process::regStats() +{ + using namespace Stats; + + num_syscalls + .name(name() + ".PROG:num_syscalls") + .desc("Number of system calls") + ; +} + +// +// static helper functions +// +int +Process::openInputFile(const string &filename) +{ + int fd = open(filename.c_str(), O_RDONLY); + + if (fd == -1) { + perror(NULL); + cerr << "unable to open \"" << filename << "\" for reading\n"; + fatal("can't open input file"); + } + + return fd; +} + + +int +Process::openOutputFile(const string &filename) +{ + int fd = open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0774); + + if (fd == -1) { + perror(NULL); + cerr << "unable to open \"" << filename << "\" for writing\n"; + fatal("can't open output file"); + } + + return fd; +} + + +int +Process::registerExecContext(ExecContext *xc) +{ + // add to list + int myIndex = execContexts.size(); + execContexts.push_back(xc); + + // return CPU number to caller + return myIndex; +} + +void +Process::startup() +{ + if (execContexts.empty()) + fatal("Process %s is not associated with any CPUs!\n", name()); + + // first exec context for this process... initialize & enable + ExecContext *xc = execContexts[0]; + + // mark this context as active so it will start ticking. + xc->activate(0); + + Port *mem_port; + mem_port = system->physmem->getPort("functional"); + initVirtMem = new TranslatingPort("process init port", pTable, true); + mem_port->setPeer(initVirtMem); + initVirtMem->setPeer(mem_port); +} + +void +Process::replaceExecContext(ExecContext *xc, int xcIndex) +{ + if (xcIndex >= execContexts.size()) { + panic("replaceExecContext: bad xcIndex, %d >= %d\n", + xcIndex, execContexts.size()); + } + + execContexts[xcIndex] = xc; +} + +// map simulator fd sim_fd to target fd tgt_fd +void +Process::dup_fd(int sim_fd, int tgt_fd) +{ + if (tgt_fd < 0 || tgt_fd > MAX_FD) + panic("Process::dup_fd tried to dup past MAX_FD (%d)", tgt_fd); + + fd_map[tgt_fd] = sim_fd; +} + + +// generate new target fd for sim_fd +int +Process::alloc_fd(int sim_fd) +{ + // in case open() returns an error, don't allocate a new fd + if (sim_fd == -1) + return -1; + + // find first free target fd + for (int free_fd = 0; free_fd < MAX_FD; ++free_fd) { + if (fd_map[free_fd] == -1) { + fd_map[free_fd] = sim_fd; + return free_fd; + } + } + + panic("Process::alloc_fd: out of file descriptors!"); +} + + +// free target fd (e.g., after close) +void +Process::free_fd(int tgt_fd) +{ + if (fd_map[tgt_fd] == -1) + warn("Process::free_fd: request to free unused fd %d", tgt_fd); + + fd_map[tgt_fd] = -1; +} + + +// look up simulator fd for given target fd +int +Process::sim_fd(int tgt_fd) +{ + if (tgt_fd > MAX_FD) + return -1; + + return fd_map[tgt_fd]; +} + + + +// +// need to declare these here since there is no concrete Process type +// that can be constructed (i.e., no REGISTER_SIM_OBJECT() macro call, +// which is where these get declared for concrete types). +// +DEFINE_SIM_OBJECT_CLASS_NAME("Process", Process) + + +//////////////////////////////////////////////////////////////////////// +// +// LiveProcess member definitions +// +//////////////////////////////////////////////////////////////////////// + + +void +copyStringArray(vector<string> &strings, Addr array_ptr, Addr data_ptr, + TranslatingPort* memPort) +{ + Addr data_ptr_swap; + for (int i = 0; i < strings.size(); ++i) { + data_ptr_swap = htog(data_ptr); + memPort->writeBlob(array_ptr, (uint8_t*)&data_ptr_swap, sizeof(Addr)); + memPort->writeString(data_ptr, strings[i].c_str()); + array_ptr += sizeof(Addr); + data_ptr += strings[i].size() + 1; + } + // add NULL terminator + data_ptr = 0; + + memPort->writeBlob(array_ptr, (uint8_t*)&data_ptr, sizeof(Addr)); +} + +LiveProcess::LiveProcess(const string &nm, ObjectFile *_objFile, + System *_system, + int stdin_fd, int stdout_fd, int stderr_fd, + vector<string> &_argv, vector<string> &_envp) + : Process(nm, _system, stdin_fd, stdout_fd, stderr_fd), + objFile(_objFile), argv(_argv), envp(_envp) +{ + prog_fname = argv[0]; + + // load up symbols, if any... these may be used for debugging or + // profiling. + if (!debugSymbolTable) { + debugSymbolTable = new SymbolTable(); + if (!objFile->loadGlobalSymbols(debugSymbolTable) || + !objFile->loadLocalSymbols(debugSymbolTable)) { + // didn't load any symbols + delete debugSymbolTable; + debugSymbolTable = NULL; + } + } +} + +void +LiveProcess::argsInit(int intSize, int pageSize) +{ + Process::startup(); + + // load object file into target memory + objFile->loadSections(initVirtMem); + + // Calculate how much space we need for arg & env arrays. + int argv_array_size = intSize * (argv.size() + 1); + int envp_array_size = intSize * (envp.size() + 1); + int arg_data_size = 0; + for (int i = 0; i < argv.size(); ++i) { + arg_data_size += argv[i].size() + 1; + } + int env_data_size = 0; + for (int i = 0; i < envp.size(); ++i) { + env_data_size += envp[i].size() + 1; + } + + int space_needed = + argv_array_size + envp_array_size + arg_data_size + env_data_size; + // for SimpleScalar compatibility + if (space_needed < 16384) + space_needed = 16384; + + // set bottom of stack + stack_min = stack_base - space_needed; + // align it + stack_min &= ~(intSize-1); + stack_size = stack_base - stack_min; + // map memory + pTable->allocate(roundDown(stack_min, pageSize), + roundUp(stack_size, pageSize)); + + // map out initial stack contents + Addr argv_array_base = stack_min + intSize; // room for argc + Addr envp_array_base = argv_array_base + argv_array_size; + Addr arg_data_base = envp_array_base + envp_array_size; + Addr env_data_base = arg_data_base + arg_data_size; + + // write contents to stack + uint64_t argc = argv.size(); + if (intSize == 8) + argc = htog((uint64_t)argc); + else if (intSize == 4) + argc = htog((uint32_t)argc); + else + panic("Unknown int size"); + + initVirtMem->writeBlob(stack_min, (uint8_t*)&argc, intSize); + + copyStringArray(argv, argv_array_base, arg_data_base, initVirtMem); + copyStringArray(envp, envp_array_base, env_data_base, initVirtMem); + + execContexts[0]->setIntReg(ArgumentReg0, argc); + execContexts[0]->setIntReg(ArgumentReg1, argv_array_base); + execContexts[0]->setIntReg(StackPointerReg, stack_min); + + Addr prog_entry = objFile->entryPoint(); + execContexts[0]->setPC(prog_entry); + execContexts[0]->setNextPC(prog_entry + sizeof(MachInst)); + execContexts[0]->setNextNPC(prog_entry + (2 * sizeof(MachInst))); + + num_processes++; +} + +void +LiveProcess::syscall(int64_t callnum, ExecContext *xc) +{ + num_syscalls++; + + SyscallDesc *desc = getDesc(callnum); + if (desc == NULL) + fatal("Syscall %d out of range", callnum); + + desc->doSyscall(callnum, this, xc); +} + +DEFINE_SIM_OBJECT_CLASS_NAME("LiveProcess", LiveProcess); diff --git a/src/sim/process.hh b/src/sim/process.hh new file mode 100644 index 000000000..807bf330f --- /dev/null +++ b/src/sim/process.hh @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __PROCESS_HH__ +#define __PROCESS_HH__ + +// +// The purpose of this code is to fake the loader & syscall mechanism +// when there's no OS: thus there's no reason to use it in FULL_SYSTEM +// mode when we do have an OS. +// +#include "config/full_system.hh" + +#if !FULL_SYSTEM + +#include <vector> + +#include "base/statistics.hh" +#include "sim/sim_object.hh" + +class CPUExecContext; +class ExecContext; +class SyscallDesc; +class PageTable; +class TranslatingPort; +class System; + +void +copyStringArray(std::vector<std::string> &strings, Addr array_ptr, + Addr data_ptr, TranslatingPort* memPort); + +class Process : public SimObject +{ + public: + + /// Pointer to object representing the system this process is + /// running on. + System *system; + + // have we initialized an execution context from this process? If + // yes, subsequent contexts are assumed to be for dynamically + // created threads and are not initialized. + bool initialContextLoaded; + + // execution contexts associated with this process + std::vector<ExecContext *> execContexts; + + // number of CPUs (esxec contexts, really) assigned to this process. + unsigned int numCpus() { return execContexts.size(); } + + // record of blocked context + struct WaitRec + { + Addr waitChan; + ExecContext *waitingContext; + + WaitRec(Addr chan, ExecContext *ctx) + : waitChan(chan), waitingContext(ctx) + { } + }; + + // list of all blocked contexts + std::list<WaitRec> waitList; + + Addr brk_point; // top of the data segment + + Addr stack_base; // stack segment base (highest address) + unsigned stack_size; // initial stack size + Addr stack_min; // lowest address accessed on the stack + + // addr to use for next stack region (for multithreaded apps) + Addr next_thread_stack_base; + + // Base of region for mmaps (when user doesn't specify an address). + Addr mmap_start; + Addr mmap_end; + + // Base of region for nxm data + Addr nxm_start; + Addr nxm_end; + + std::string prog_fname; // file name + + Stats::Scalar<> num_syscalls; // number of syscalls executed + + + protected: + // constructor + Process(const std::string &nm, + System *_system, + int stdin_fd, // initial I/O descriptors + int stdout_fd, + int stderr_fd); + + // post initialization startup + virtual void startup(); + + protected: + /// Memory object for initialization (image loading) + TranslatingPort *initVirtMem; + + public: + PageTable *pTable; + + private: + // file descriptor remapping support + static const int MAX_FD = 256; // max legal fd value + int fd_map[MAX_FD+1]; + + public: + // static helper functions to generate file descriptors for constructor + static int openInputFile(const std::string &filename); + static int openOutputFile(const std::string &filename); + + // override of virtual SimObject method: register statistics + virtual void regStats(); + + // register an execution context for this process. + // returns xc's cpu number (index into execContexts[]) + int registerExecContext(ExecContext *xc); + + + void replaceExecContext(ExecContext *xc, int xcIndex); + + // map simulator fd sim_fd to target fd tgt_fd + void dup_fd(int sim_fd, int tgt_fd); + + // generate new target fd for sim_fd + int alloc_fd(int sim_fd); + + // free target fd (e.g., after close) + void free_fd(int tgt_fd); + + // look up simulator fd for given target fd + int sim_fd(int tgt_fd); + + virtual void syscall(int64_t callnum, ExecContext *xc) = 0; +}; + +// +// "Live" process with system calls redirected to host system +// +class ObjectFile; +class LiveProcess : public Process +{ + protected: + ObjectFile *objFile; + std::vector<std::string> argv; + std::vector<std::string> envp; + + LiveProcess(const std::string &nm, ObjectFile *objFile, + System *_system, int stdin_fd, int stdout_fd, int stderr_fd, + std::vector<std::string> &argv, + std::vector<std::string> &envp); + + virtual void argsInit(int intSize, int pageSize); + + public: + virtual void syscall(int64_t callnum, ExecContext *xc); + + virtual SyscallDesc* getDesc(int callnum) = 0; +}; + + +#endif // !FULL_SYSTEM + +#endif // __PROCESS_HH__ diff --git a/src/sim/pseudo_inst.cc b/src/sim/pseudo_inst.cc new file mode 100644 index 000000000..12c076c08 --- /dev/null +++ b/src/sim/pseudo_inst.cc @@ -0,0 +1,290 @@ +/* + * Copyright (c) 2003-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> + +#include <string> + +#include "sim/pseudo_inst.hh" +#include "arch/vtophys.hh" +#include "cpu/base.hh" +#include "cpu/sampler/sampler.hh" +#include "cpu/exec_context.hh" +#include "cpu/quiesce_event.hh" +#include "kern/kernel_stats.hh" +#include "sim/param.hh" +#include "sim/serialize.hh" +#include "sim/sim_exit.hh" +#include "sim/stat_control.hh" +#include "sim/stats.hh" +#include "sim/system.hh" +#include "sim/debug.hh" +#include "sim/vptr.hh" + +using namespace std; + +extern Sampler *SampCPU; + +using namespace Stats; +using namespace TheISA; + +namespace AlphaPseudo +{ + bool doStatisticsInsts; + bool doCheckpointInsts; + bool doQuiesce; + + void + arm(ExecContext *xc) + { + if (xc->getKernelStats()) + xc->getKernelStats()->arm(); + } + + void + quiesce(ExecContext *xc) + { + if (!doQuiesce) + return; + + xc->suspend(); + if (xc->getKernelStats()) + xc->getKernelStats()->quiesce(); + } + + void + quiesceNs(ExecContext *xc, uint64_t ns) + { + if (!doQuiesce || ns == 0) + return; + + EndQuiesceEvent *quiesceEvent = xc->getQuiesceEvent(); + + if (quiesceEvent->scheduled()) + quiesceEvent->reschedule(curTick + Clock::Int::ns * ns); + else + quiesceEvent->schedule(curTick + Clock::Int::ns * ns); + + xc->suspend(); + if (xc->getKernelStats()) + xc->getKernelStats()->quiesce(); + } + + void + quiesceCycles(ExecContext *xc, uint64_t cycles) + { + if (!doQuiesce || cycles == 0) + return; + + EndQuiesceEvent *quiesceEvent = xc->getQuiesceEvent(); + + if (quiesceEvent->scheduled()) + quiesceEvent->reschedule(curTick + + xc->getCpuPtr()->cycles(cycles)); + else + quiesceEvent->schedule(curTick + + xc->getCpuPtr()->cycles(cycles)); + + xc->suspend(); + if (xc->getKernelStats()) + xc->getKernelStats()->quiesce(); + } + + uint64_t + quiesceTime(ExecContext *xc) + { + return (xc->readLastActivate() - xc->readLastSuspend()) / Clock::Int::ns; + } + + void + ivlb(ExecContext *xc) + { + if (xc->getKernelStats()) + xc->getKernelStats()->ivlb(); + } + + void + ivle(ExecContext *xc) + { + } + + void + m5exit_old(ExecContext *xc) + { + SimExit(curTick, "m5_exit_old instruction encountered"); + } + + void + m5exit(ExecContext *xc, Tick delay) + { + Tick when = curTick + delay * Clock::Int::ns; + SimExit(when, "m5_exit instruction encountered"); + } + + void + resetstats(ExecContext *xc, Tick delay, Tick period) + { + if (!doStatisticsInsts) + return; + + + Tick when = curTick + delay * Clock::Int::ns; + Tick repeat = period * Clock::Int::ns; + + using namespace Stats; + SetupEvent(Reset, when, repeat); + } + + void + dumpstats(ExecContext *xc, Tick delay, Tick period) + { + if (!doStatisticsInsts) + return; + + + Tick when = curTick + delay * Clock::Int::ns; + Tick repeat = period * Clock::Int::ns; + + using namespace Stats; + SetupEvent(Dump, when, repeat); + } + + void + addsymbol(ExecContext *xc, Addr addr, Addr symbolAddr) + { + char symb[100]; + CopyStringOut(xc, symb, symbolAddr, 100); + std::string symbol(symb); + + DPRINTF(Loader, "Loaded symbol: %s @ %#llx\n", symbol, addr); + + xc->getSystemPtr()->kernelSymtab->insert(addr,symbol); + } + + void + dumpresetstats(ExecContext *xc, Tick delay, Tick period) + { + if (!doStatisticsInsts) + return; + + + Tick when = curTick + delay * Clock::Int::ns; + Tick repeat = period * Clock::Int::ns; + + using namespace Stats; + SetupEvent(Dump|Reset, when, repeat); + } + + void + m5checkpoint(ExecContext *xc, Tick delay, Tick period) + { + if (!doCheckpointInsts) + return; + + + Tick when = curTick + delay * Clock::Int::ns; + Tick repeat = period * Clock::Int::ns; + + Checkpoint::setup(when, repeat); + } + + uint64_t + readfile(ExecContext *xc, Addr vaddr, uint64_t len, uint64_t offset) + { + const string &file = xc->getCpuPtr()->system->params()->readfile; + if (file.empty()) { + return ULL(0); + } + + uint64_t result = 0; + + int fd = ::open(file.c_str(), O_RDONLY, 0); + if (fd < 0) + panic("could not open file %s\n", file); + + if (::lseek(fd, offset, SEEK_SET) < 0) + panic("could not seek: %s", strerror(errno)); + + char *buf = new char[len]; + char *p = buf; + while (len > 0) { + int bytes = ::read(fd, p, len); + if (bytes <= 0) + break; + + p += bytes; + result += bytes; + len -= bytes; + } + + close(fd); + CopyIn(xc, vaddr, buf, result); + delete [] buf; + return result; + } + + class Context : public ParamContext + { + public: + Context(const string §ion) : ParamContext(section) {} + void checkParams(); + }; + + Context context("pseudo_inst"); + + Param<bool> __quiesce(&context, "quiesce", + "enable quiesce instructions", + true); + Param<bool> __statistics(&context, "statistics", + "enable statistics pseudo instructions", + true); + Param<bool> __checkpoint(&context, "checkpoint", + "enable checkpoint pseudo instructions", + true); + + void + Context::checkParams() + { + doQuiesce = __quiesce; + doStatisticsInsts = __statistics; + doCheckpointInsts = __checkpoint; + } + + void debugbreak(ExecContext *xc) + { + debug_break(); + } + + void switchcpu(ExecContext *xc) + { + if (SampCPU) + SampCPU->switchCPUs(); + } +} diff --git a/sim/pseudo_inst.hh b/src/sim/pseudo_inst.hh index 4dd427c99..4dd427c99 100644 --- a/sim/pseudo_inst.hh +++ b/src/sim/pseudo_inst.hh diff --git a/sim/root.cc b/src/sim/root.cc index 6348ec104..6348ec104 100644 --- a/sim/root.cc +++ b/src/sim/root.cc diff --git a/sim/serialize.cc b/src/sim/serialize.cc index c4ef124bb..c4ef124bb 100644 --- a/sim/serialize.cc +++ b/src/sim/serialize.cc diff --git a/sim/serialize.hh b/src/sim/serialize.hh index d8f5f8fc5..d8f5f8fc5 100644 --- a/sim/serialize.hh +++ b/src/sim/serialize.hh diff --git a/sim/sim_events.cc b/src/sim/sim_events.cc index c2bdca9df..c2bdca9df 100644 --- a/sim/sim_events.cc +++ b/src/sim/sim_events.cc diff --git a/sim/sim_events.hh b/src/sim/sim_events.hh index c93914457..c93914457 100644 --- a/sim/sim_events.hh +++ b/src/sim/sim_events.hh diff --git a/sim/sim_exit.hh b/src/sim/sim_exit.hh index f14256933..f14256933 100644 --- a/sim/sim_exit.hh +++ b/src/sim/sim_exit.hh diff --git a/src/sim/sim_object.cc b/src/sim/sim_object.cc new file mode 100644 index 000000000..17d58ba4f --- /dev/null +++ b/src/sim/sim_object.cc @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <assert.h> + +#include "base/callback.hh" +#include "base/inifile.hh" +#include "base/match.hh" +#include "base/misc.hh" +#include "base/trace.hh" +#include "base/stats/events.hh" +#include "base/serializer.hh" +#include "sim/configfile.hh" +#include "sim/host.hh" +#include "sim/sim_object.hh" +#include "sim/stats.hh" +#include "sim/param.hh" + +using namespace std; + + +//////////////////////////////////////////////////////////////////////// +// +// SimObject member definitions +// +//////////////////////////////////////////////////////////////////////// + +// +// static list of all SimObjects, used for initialization etc. +// +SimObject::SimObjectList SimObject::simObjectList; + +namespace Stats { + extern ObjectMatch event_ignore; +} + +// +// SimObject constructor: used to maintain static simObjectList +// +SimObject::SimObject(Params *p) + : _params(p) +{ +#ifdef DEBUG + doDebugBreak = false; +#endif + + doRecordEvent = !Stats::event_ignore.match(name()); + simObjectList.push_back(this); +} + +// +// SimObject constructor: used to maintain static simObjectList +// +SimObject::SimObject(const string &_name) + : _params(new Params) +{ + _params->name = _name; +#ifdef DEBUG + doDebugBreak = false; +#endif + + doRecordEvent = !Stats::event_ignore.match(name()); + simObjectList.push_back(this); +} + +void +SimObject::connect() +{ +} + +void +SimObject::init() +{ +} + +// +// no default statistics, so nothing to do in base implementation +// +void +SimObject::regStats() +{ +} + +void +SimObject::regFormulas() +{ +} + +void +SimObject::resetStats() +{ +} + +// +// static function: +// call regStats() on all SimObjects and then regFormulas() on all +// SimObjects. +// +struct SimObjectResetCB : public Callback +{ + virtual void process() { SimObject::resetAllStats(); } +}; + +namespace { + static SimObjectResetCB StatResetCB; +} + +void +SimObject::regAllStats() +{ + SimObjectList::iterator i; + SimObjectList::iterator end = simObjectList.end(); + + /** + * @todo change cprintfs to DPRINTFs + */ + for (i = simObjectList.begin(); i != end; ++i) { +#ifdef STAT_DEBUG + cprintf("registering stats for %s\n", (*i)->name()); +#endif + (*i)->regStats(); + } + + for (i = simObjectList.begin(); i != end; ++i) { +#ifdef STAT_DEBUG + cprintf("registering formulas for %s\n", (*i)->name()); +#endif + (*i)->regFormulas(); + } + + Stats::registerResetCallback(&StatResetCB); +} + +// +// static function: call connect() on all SimObjects. +// +void +SimObject::connectAll() +{ + SimObjectList::iterator i = simObjectList.begin(); + SimObjectList::iterator end = simObjectList.end(); + + for (; i != end; ++i) { + SimObject *obj = *i; + obj->connect(); + } +} + +// +// static function: call init() on all SimObjects. +// +void +SimObject::initAll() +{ + SimObjectList::iterator i = simObjectList.begin(); + SimObjectList::iterator end = simObjectList.end(); + + for (; i != end; ++i) { + SimObject *obj = *i; + obj->init(); + } +} + +// +// static function: call resetStats() on all SimObjects. +// +void +SimObject::resetAllStats() +{ + SimObjectList::iterator i = simObjectList.begin(); + SimObjectList::iterator end = simObjectList.end(); + + for (; i != end; ++i) { + SimObject *obj = *i; + obj->resetStats(); + } +} + +// +// static function: serialize all SimObjects. +// +void +SimObject::serializeAll(ostream &os) +{ + SimObjectList::reverse_iterator ri = simObjectList.rbegin(); + SimObjectList::reverse_iterator rend = simObjectList.rend(); + + for (; ri != rend; ++ri) { + SimObject *obj = *ri; + obj->nameOut(os); + obj->serialize(os); + } +} + +#ifdef DEBUG +// +// static function: flag which objects should have the debugger break +// +void +SimObject::debugObjectBreak(const string &objs) +{ + SimObjectList::const_iterator i = simObjectList.begin(); + SimObjectList::const_iterator end = simObjectList.end(); + + ObjectMatch match(objs); + for (; i != end; ++i) { + SimObject *obj = *i; + obj->doDebugBreak = match.match(obj->name()); + } +} + +extern "C" +void +debugObjectBreak(const char *objs) +{ + SimObject::debugObjectBreak(string(objs)); +} +#endif + +void +SimObject::recordEvent(const std::string &stat) +{ + if (doRecordEvent) + Stats::recordEvent(stat); +} + +void +SimObject::drain(Serializer *serializer) +{ + serializer->signalDrained(); +} + +DEFINE_SIM_OBJECT_CLASS_NAME("SimObject", SimObject) diff --git a/src/sim/sim_object.hh b/src/sim/sim_object.hh new file mode 100644 index 000000000..76aba7ea1 --- /dev/null +++ b/src/sim/sim_object.hh @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* @file + * User Console Definitions + */ + +#ifndef __SIM_OBJECT_HH__ +#define __SIM_OBJECT_HH__ + +#include <map> +#include <list> +#include <vector> +#include <iostream> + +#include "sim/serialize.hh" +#include "sim/startup.hh" + +class Serializer; + +/* + * Abstract superclass for simulation objects. Represents things that + * correspond to physical components and can be specified via the + * config file (CPUs, caches, etc.). + */ +class SimObject : public Serializable, protected StartupCallback +{ + public: + struct Params { + std::string name; + }; + + protected: + Params *_params; + + public: + const Params *params() const { return _params; } + + private: + friend class Serializer; + + typedef std::vector<SimObject *> SimObjectList; + + // list of all instantiated simulation objects + static SimObjectList simObjectList; + + public: + SimObject(Params *_params); + SimObject(const std::string &_name); + + virtual ~SimObject() {} + + virtual const std::string name() const { return params()->name; } + + // initialization pass of all objects. + // Gets invoked after construction, before unserialize. + virtual void init(); + virtual void connect(); + static void initAll(); + static void connectAll(); + + // register statistics for this object + virtual void regStats(); + virtual void regFormulas(); + virtual void resetStats(); + + // static: call reg_stats on all SimObjects + static void regAllStats(); + + // static: call resetStats on all SimObjects + static void resetAllStats(); + + // static: call nameOut() & serialize() on all SimObjects + static void serializeAll(std::ostream &); + + // Methods to drain objects in order to take checkpoints + // Or switch from timing -> atomic memory model + virtual void drain(Serializer *serializer); + virtual void resume() { return;} ; + virtual void serializationComplete() + { assert(0 && "Unimplemented"); }; + +#ifdef DEBUG + public: + bool doDebugBreak; + static void debugObjectBreak(const std::string &objs); +#endif + + public: + bool doRecordEvent; + void recordEvent(const std::string &stat); +}; + +#endif // __SIM_OBJECT_HH__ diff --git a/sim/startup.cc b/src/sim/startup.cc index 683e6c746..683e6c746 100644 --- a/sim/startup.cc +++ b/src/sim/startup.cc diff --git a/sim/startup.hh b/src/sim/startup.hh index 3c9b654f1..3c9b654f1 100644 --- a/sim/startup.hh +++ b/src/sim/startup.hh diff --git a/sim/stat_control.cc b/src/sim/stat_control.cc index 85c405b7f..85c405b7f 100644 --- a/sim/stat_control.cc +++ b/src/sim/stat_control.cc diff --git a/sim/stat_control.hh b/src/sim/stat_control.hh index a22ce76af..a22ce76af 100644 --- a/sim/stat_control.hh +++ b/src/sim/stat_control.hh diff --git a/sim/stats.hh b/src/sim/stats.hh index 8e97d041f..8e97d041f 100644 --- a/sim/stats.hh +++ b/src/sim/stats.hh diff --git a/src/sim/syscall_emul.cc b/src/sim/syscall_emul.cc new file mode 100644 index 000000000..ed0da628e --- /dev/null +++ b/src/sim/syscall_emul.cc @@ -0,0 +1,454 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <fcntl.h> +#include <unistd.h> + +#include <string> +#include <iostream> + +#include "sim/syscall_emul.hh" +#include "base/chunk_generator.hh" +#include "base/trace.hh" +#include "cpu/exec_context.hh" +#include "cpu/base.hh" +#include "mem/page_table.hh" +#include "sim/process.hh" + +#include "sim/sim_events.hh" + +using namespace std; +using namespace TheISA; + +void +SyscallDesc::doSyscall(int callnum, Process *process, ExecContext *xc) +{ + DPRINTFR(SyscallVerbose, "%d: %s: syscall %s called w/arguments %d,%d,%d,%d\n", + curTick,xc->getCpuPtr()->name(), name, + xc->getSyscallArg(0),xc->getSyscallArg(1), + xc->getSyscallArg(2),xc->getSyscallArg(3)); + + SyscallReturn retval = (*funcPtr)(this, callnum, process, xc); + + DPRINTFR(SyscallVerbose, "%d: %s: syscall %s returns %d\n", + curTick,xc->getCpuPtr()->name(), name, retval.value()); + + if (!(flags & SyscallDesc::SuppressReturnValue)) + xc->setSyscallReturn(retval); +} + + +SyscallReturn +unimplementedFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + fatal("syscall %s (#%d) unimplemented.", desc->name, callnum); + + return 1; +} + + +SyscallReturn +ignoreFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + warn("ignoring syscall %s(%d, %d, ...)", desc->name, + xc->getSyscallArg(0), xc->getSyscallArg(1)); + + return 0; +} + + +SyscallReturn +exitFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + new SimExitEvent("target called exit()", xc->getSyscallArg(0) & 0xff); + + return 1; +} + + +SyscallReturn +getpagesizeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) +{ + return (int)VMPageSize; +} + + +SyscallReturn +obreakFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) +{ + Addr junk; + + // change brk addr to first arg + Addr new_brk = xc->getSyscallArg(0); + if (new_brk != 0) { + for (ChunkGenerator gen(p->brk_point, new_brk - p->brk_point, + VMPageSize); !gen.done(); gen.next()) { + if (!p->pTable->translate(gen.addr(), junk)) + p->pTable->allocate(roundDown(gen.addr(), VMPageSize), + VMPageSize); + } + p->brk_point = new_brk; + } + DPRINTF(SyscallVerbose, "Break Point changed to: %#X\n", p->brk_point); + return p->brk_point; +} + + +SyscallReturn +closeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) +{ + int target_fd = xc->getSyscallArg(0); + int status = close(p->sim_fd(target_fd)); + if (status >= 0) + p->free_fd(target_fd); + return status; +} + + +SyscallReturn +readFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) +{ + int fd = p->sim_fd(xc->getSyscallArg(0)); + int nbytes = xc->getSyscallArg(2); + BufferArg bufArg(xc->getSyscallArg(1), nbytes); + + int bytes_read = read(fd, bufArg.bufferPtr(), nbytes); + + if (bytes_read != -1) + bufArg.copyOut(xc->getMemPort()); + + return bytes_read; +} + +SyscallReturn +writeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) +{ + int fd = p->sim_fd(xc->getSyscallArg(0)); + int nbytes = xc->getSyscallArg(2); + BufferArg bufArg(xc->getSyscallArg(1), nbytes); + + bufArg.copyIn(xc->getMemPort()); + + int bytes_written = write(fd, bufArg.bufferPtr(), nbytes); + + fsync(fd); + + return bytes_written; +} + + +SyscallReturn +lseekFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) +{ + int fd = p->sim_fd(xc->getSyscallArg(0)); + uint64_t offs = xc->getSyscallArg(1); + int whence = xc->getSyscallArg(2); + + off_t result = lseek(fd, offs, whence); + + return (result == (off_t)-1) ? -errno : result; +} + + +SyscallReturn +munmapFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) +{ + // given that we don't really implement mmap, munmap is really easy + return 0; +} + + +const char *hostname = "m5.eecs.umich.edu"; + +SyscallReturn +gethostnameFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) +{ + int name_len = xc->getSyscallArg(1); + BufferArg name(xc->getSyscallArg(0), name_len); + + strncpy((char *)name.bufferPtr(), hostname, name_len); + + name.copyOut(xc->getMemPort()); + + return 0; +} + +SyscallReturn +unlinkFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) +{ + string path; + + if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0))) + return (TheISA::IntReg)-EFAULT; + + int result = unlink(path.c_str()); + return (result == -1) ? -errno : result; +} + +SyscallReturn +renameFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) +{ + string old_name; + + if (!xc->getMemPort()->tryReadString(old_name, xc->getSyscallArg(0))) + return -EFAULT; + + string new_name; + + if (!xc->getMemPort()->tryReadString(new_name, xc->getSyscallArg(1))) + return -EFAULT; + + int64_t result = rename(old_name.c_str(), new_name.c_str()); + return (result == -1) ? -errno : result; +} + +SyscallReturn +truncateFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) +{ + string path; + + if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0))) + return -EFAULT; + + off_t length = xc->getSyscallArg(1); + + int result = truncate(path.c_str(), length); + return (result == -1) ? -errno : result; +} + +SyscallReturn +ftruncateFunc(SyscallDesc *desc, int num, Process *process, ExecContext *xc) +{ + int fd = process->sim_fd(xc->getSyscallArg(0)); + + if (fd < 0) + return -EBADF; + + off_t length = xc->getSyscallArg(1); + + int result = ftruncate(fd, length); + return (result == -1) ? -errno : result; +} + +SyscallReturn +chownFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) +{ + string path; + + if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0))) + return -EFAULT; + + /* XXX endianess */ + uint32_t owner = xc->getSyscallArg(1); + uid_t hostOwner = owner; + uint32_t group = xc->getSyscallArg(2); + gid_t hostGroup = group; + + int result = chown(path.c_str(), hostOwner, hostGroup); + return (result == -1) ? -errno : result; +} + +SyscallReturn +fchownFunc(SyscallDesc *desc, int num, Process *process, ExecContext *xc) +{ + int fd = process->sim_fd(xc->getSyscallArg(0)); + + if (fd < 0) + return -EBADF; + + /* XXX endianess */ + uint32_t owner = xc->getSyscallArg(1); + uid_t hostOwner = owner; + uint32_t group = xc->getSyscallArg(2); + gid_t hostGroup = group; + + int result = fchown(fd, hostOwner, hostGroup); + return (result == -1) ? -errno : result; +} + + +SyscallReturn +fcntlFunc(SyscallDesc *desc, int num, Process *process, + ExecContext *xc) +{ + int fd = xc->getSyscallArg(0); + + if (fd < 0 || process->sim_fd(fd) < 0) + return -EBADF; + + int cmd = xc->getSyscallArg(1); + switch (cmd) { + case 0: // F_DUPFD + // if we really wanted to support this, we'd need to do it + // in the target fd space. + warn("fcntl(%d, F_DUPFD) not supported, error returned\n", fd); + return -EMFILE; + + case 1: // F_GETFD (get close-on-exec flag) + case 2: // F_SETFD (set close-on-exec flag) + return 0; + + case 3: // F_GETFL (get file flags) + case 4: // F_SETFL (set file flags) + // not sure if this is totally valid, but we'll pass it through + // to the underlying OS + warn("fcntl(%d, %d) passed through to host\n", fd, cmd); + return fcntl(process->sim_fd(fd), cmd); + // return 0; + + case 7: // F_GETLK (get lock) + case 8: // F_SETLK (set lock) + case 9: // F_SETLKW (set lock and wait) + // don't mess with file locking... just act like it's OK + warn("File lock call (fcntl(%d, %d)) ignored.\n", fd, cmd); + return 0; + + default: + warn("Unknown fcntl command %d\n", cmd); + return 0; + } +} + +SyscallReturn +pipePseudoFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + int fds[2], sim_fds[2]; + int pipe_retval = pipe(fds); + + if (pipe_retval < 0) { + // error + return pipe_retval; + } + + sim_fds[0] = process->alloc_fd(fds[0]); + sim_fds[1] = process->alloc_fd(fds[1]); + + // Alpha Linux convention for pipe() is that fd[0] is returned as + // the return value of the function, and fd[1] is returned in r20. + xc->setIntReg(SyscallPseudoReturnReg, sim_fds[1]); + return sim_fds[0]; +} + + +SyscallReturn +getpidPseudoFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + // Make up a PID. There's no interprocess communication in + // fake_syscall mode, so there's no way for a process to know it's + // not getting a unique value. + + xc->setIntReg(SyscallPseudoReturnReg, 99); + return 100; +} + + +SyscallReturn +getuidPseudoFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + // Make up a UID and EUID... it shouldn't matter, and we want the + // simulation to be deterministic. + + // EUID goes in r20. + xc->setIntReg(SyscallPseudoReturnReg, 100); //EUID + return 100; // UID +} + + +SyscallReturn +getgidPseudoFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + // Get current group ID. EGID goes in r20. + xc->setIntReg(SyscallPseudoReturnReg, 100); //EGID + return 100; +} + + +SyscallReturn +setuidFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + // can't fathom why a benchmark would call this. + warn("Ignoring call to setuid(%d)\n", xc->getSyscallArg(0)); + return 0; +} + +SyscallReturn +getpidFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + // Make up a PID. There's no interprocess communication in + // fake_syscall mode, so there's no way for a process to know it's + // not getting a unique value. + + xc->setIntReg(SyscallPseudoReturnReg, 99); //PID + return 100; +} + +SyscallReturn +getppidFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + return 99; +} + +SyscallReturn +getuidFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + return 100; // UID +} + +SyscallReturn +geteuidFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + return 100; // UID +} + +SyscallReturn +getgidFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + return 100; +} + +SyscallReturn +getegidFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + return 100; +} + + diff --git a/src/sim/syscall_emul.hh b/src/sim/syscall_emul.hh new file mode 100644 index 000000000..00f016410 --- /dev/null +++ b/src/sim/syscall_emul.hh @@ -0,0 +1,849 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __SIM_SYSCALL_EMUL_HH__ +#define __SIM_SYSCALL_EMUL_HH__ + +#define BSD_HOST (defined(__APPLE__) || defined(__OpenBSD__) || \ + defined(__FreeBSD__)) + +/// +/// @file syscall_emul.hh +/// +/// This file defines objects used to emulate syscalls from the target +/// application on the host machine. + +#include <errno.h> +#include <string> +#ifdef __CYGWIN32__ +#include <sys/fcntl.h> // for O_BINARY +#endif +#include <sys/uio.h> + +#include "arch/isa_traits.hh" // for Addr +#include "base/chunk_generator.hh" +#include "base/intmath.hh" // for RoundUp +#include "base/misc.hh" +#include "base/trace.hh" +#include "cpu/base.hh" +#include "cpu/exec_context.hh" +#include "mem/translating_port.hh" +#include "mem/page_table.hh" +#include "sim/process.hh" + +/// +/// System call descriptor. +/// +class SyscallDesc { + + public: + + /// Typedef for target syscall handler functions. + typedef SyscallReturn (*FuncPtr)(SyscallDesc *, int num, + Process *, ExecContext *); + + const char *name; //!< Syscall name (e.g., "open"). + FuncPtr funcPtr; //!< Pointer to emulation function. + int flags; //!< Flags (see Flags enum). + + /// Flag values for controlling syscall behavior. + enum Flags { + /// Don't set return regs according to funcPtr return value. + /// Used for syscalls with non-standard return conventions + /// that explicitly set the ExecContext regs (e.g., + /// sigreturn). + SuppressReturnValue = 1 + }; + + /// Constructor. + SyscallDesc(const char *_name, FuncPtr _funcPtr, int _flags = 0) + : name(_name), funcPtr(_funcPtr), flags(_flags) + { + } + + /// Emulate the syscall. Public interface for calling through funcPtr. + void doSyscall(int callnum, Process *proc, ExecContext *xc); +}; + + +class BaseBufferArg { + + public: + + BaseBufferArg(Addr _addr, int _size) : addr(_addr), size(_size) + { + bufPtr = new uint8_t[size]; + // clear out buffer: in case we only partially populate this, + // and then do a copyOut(), we want to make sure we don't + // introduce any random junk into the simulated address space + memset(bufPtr, 0, size); + } + + virtual ~BaseBufferArg() { delete [] bufPtr; } + + // + // copy data into simulator space (read from target memory) + // + virtual bool copyIn(TranslatingPort *memport) + { + memport->readBlob(addr, bufPtr, size); + return true; // no EFAULT detection for now + } + + // + // copy data out of simulator space (write to target memory) + // + virtual bool copyOut(TranslatingPort *memport) + { + memport->writeBlob(addr, bufPtr, size); + return true; // no EFAULT detection for now + } + + protected: + Addr addr; + int size; + uint8_t *bufPtr; +}; + + +class BufferArg : public BaseBufferArg +{ + public: + BufferArg(Addr _addr, int _size) : BaseBufferArg(_addr, _size) { } + void *bufferPtr() { return bufPtr; } +}; + +template <class T> +class TypedBufferArg : public BaseBufferArg +{ + public: + // user can optionally specify a specific number of bytes to + // allocate to deal with those structs that have variable-size + // arrays at the end + TypedBufferArg(Addr _addr, int _size = sizeof(T)) + : BaseBufferArg(_addr, _size) + { } + + // type case + operator T*() { return (T *)bufPtr; } + + // dereference operators + T &operator*() { return *((T *)bufPtr); } + T* operator->() { return (T *)bufPtr; } + T &operator[](int i) { return ((T *)bufPtr)[i]; } +}; + +////////////////////////////////////////////////////////////////////// +// +// The following emulation functions are generic enough that they +// don't need to be recompiled for different emulated OS's. They are +// defined in sim/syscall_emul.cc. +// +////////////////////////////////////////////////////////////////////// + + +/// Handler for unimplemented syscalls that we haven't thought about. +SyscallReturn unimplementedFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + +/// Handler for unimplemented syscalls that we never intend to +/// implement (signal handling, etc.) and should not affect the correct +/// behavior of the program. Print a warning only if the appropriate +/// trace flag is enabled. Return success to the target program. +SyscallReturn ignoreFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + +/// Target exit() handler: terminate simulation. +SyscallReturn exitFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + +/// Target getpagesize() handler. +SyscallReturn getpagesizeFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + +/// Target obreak() handler: set brk address. +SyscallReturn obreakFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + +/// Target close() handler. +SyscallReturn closeFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + +/// Target read() handler. +SyscallReturn readFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + +/// Target write() handler. +SyscallReturn writeFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + +/// Target lseek() handler. +SyscallReturn lseekFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + +/// Target munmap() handler. +SyscallReturn munmapFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + +/// Target gethostname() handler. +SyscallReturn gethostnameFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + +/// Target unlink() handler. +SyscallReturn unlinkFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + +/// Target rename() handler. +SyscallReturn renameFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + + +/// Target truncate() handler. +SyscallReturn truncateFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + + +/// Target ftruncate() handler. +SyscallReturn ftruncateFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + + +/// Target chown() handler. +SyscallReturn chownFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + + +/// Target fchown() handler. +SyscallReturn fchownFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + +/// Target fnctl() handler. +SyscallReturn fcntlFunc(SyscallDesc *desc, int num, + Process *process, ExecContext *xc); + +/// Target setuid() handler. +SyscallReturn setuidFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + +/// Target getpid() handler. +SyscallReturn getpidFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + +/// Target getuid() handler. +SyscallReturn getuidFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + +/// Target getgid() handler. +SyscallReturn getgidFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + +/// Target getppid() handler. +SyscallReturn getppidFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + +/// Target geteuid() handler. +SyscallReturn geteuidFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + +/// Target getegid() handler. +SyscallReturn getegidFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + + + +/// Pseudo Funcs - These functions use a different return convension, +/// returning a second value in a register other than the normal return register +SyscallReturn pipePseudoFunc(SyscallDesc *desc, int num, + Process *process, ExecContext *xc); + +/// Target getpidPseudo() handler. +SyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + +/// Target getuidPseudo() handler. +SyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + +/// Target getgidPseudo() handler. +SyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + + +/// This struct is used to build an target-OS-dependent table that +/// maps the target's open() flags to the host open() flags. +struct OpenFlagTransTable { + int tgtFlag; //!< Target system flag value. + int hostFlag; //!< Corresponding host system flag value. +}; + + + +/// A readable name for 1,000,000, for converting microseconds to seconds. +const int one_million = 1000000; + +/// Approximate seconds since the epoch (1/1/1970). About a billion, +/// by my reckoning. We want to keep this a constant (not use the +/// real-world time) to keep simulations repeatable. +const unsigned seconds_since_epoch = 1000000000; + +/// Helper function to convert current elapsed time to seconds and +/// microseconds. +template <class T1, class T2> +void +getElapsedTime(T1 &sec, T2 &usec) +{ + int elapsed_usecs = curTick / Clock::Int::us; + sec = elapsed_usecs / one_million; + usec = elapsed_usecs % one_million; +} + +////////////////////////////////////////////////////////////////////// +// +// The following emulation functions are generic, but need to be +// templated to account for differences in types, constants, etc. +// +////////////////////////////////////////////////////////////////////// + +/// Target ioctl() handler. For the most part, programs call ioctl() +/// only to find out if their stdout is a tty, to determine whether to +/// do line or block buffering. +template <class OS> +SyscallReturn +ioctlFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + int fd = xc->getSyscallArg(0); + unsigned req = xc->getSyscallArg(1); + + DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", fd, req); + + if (fd < 0 || process->sim_fd(fd) < 0) { + // doesn't map to any simulator fd: not a valid target fd + return -EBADF; + } + + switch (req) { + case OS::TIOCISATTY: + case OS::TIOCGETP: + case OS::TIOCSETP: + case OS::TIOCSETN: + case OS::TIOCSETC: + case OS::TIOCGETC: + case OS::TIOCGETS: + case OS::TIOCGETA: + return -ENOTTY; + + default: + fatal("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ 0x%llx\n", + fd, req, xc->readPC()); + } +} + +/// Target open() handler. +template <class OS> +SyscallReturn +openFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + std::string path; + + if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0))) + return -EFAULT; + + if (path == "/dev/sysdev0") { + // This is a memory-mapped high-resolution timer device on Alpha. + // We don't support it, so just punt. + warn("Ignoring open(%s, ...)\n", path); + return -ENOENT; + } + + int tgtFlags = xc->getSyscallArg(1); + int mode = xc->getSyscallArg(2); + int hostFlags = 0; + + // translate open flags + for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) { + if (tgtFlags & OS::openFlagTable[i].tgtFlag) { + tgtFlags &= ~OS::openFlagTable[i].tgtFlag; + hostFlags |= OS::openFlagTable[i].hostFlag; + } + } + + // any target flags left? + if (tgtFlags != 0) + warn("Syscall: open: cannot decode flags 0x%x", tgtFlags); + +#ifdef __CYGWIN32__ + hostFlags |= O_BINARY; +#endif + + DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str()); + + // open the file + int fd = open(path.c_str(), hostFlags, mode); + + return (fd == -1) ? -errno : process->alloc_fd(fd); +} + + +/// Target chmod() handler. +template <class OS> +SyscallReturn +chmodFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + std::string path; + + if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0))) + return -EFAULT; + + uint32_t mode = xc->getSyscallArg(1); + mode_t hostMode = 0; + + // XXX translate mode flags via OS::something??? + hostMode = mode; + + // do the chmod + int result = chmod(path.c_str(), hostMode); + if (result < 0) + return -errno; + + return 0; +} + + +/// Target fchmod() handler. +template <class OS> +SyscallReturn +fchmodFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + int fd = xc->getSyscallArg(0); + if (fd < 0 || process->sim_fd(fd) < 0) { + // doesn't map to any simulator fd: not a valid target fd + return -EBADF; + } + + uint32_t mode = xc->getSyscallArg(1); + mode_t hostMode = 0; + + // XXX translate mode flags via OS::someting??? + hostMode = mode; + + // do the fchmod + int result = fchmod(process->sim_fd(fd), hostMode); + if (result < 0) + return -errno; + + return 0; +} + + +/// Target stat() handler. +template <class OS> +SyscallReturn +statFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + std::string path; + + if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0))) + return -EFAULT; + + struct stat hostBuf; + int result = stat(path.c_str(), &hostBuf); + + if (result < 0) + return -errno; + + OS::copyOutStatBuf(xc->getMemPort(), xc->getSyscallArg(1), &hostBuf); + + return 0; +} + + +/// Target fstat64() handler. +template <class OS> +SyscallReturn +fstat64Func(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + int fd = xc->getSyscallArg(0); + if (fd < 0 || process->sim_fd(fd) < 0) { + // doesn't map to any simulator fd: not a valid target fd + return -EBADF; + } + +#if BSD_HOST + struct stat hostBuf; + int result = fstat(process->sim_fd(fd), &hostBuf); +#else + struct stat64 hostBuf; + int result = fstat64(process->sim_fd(fd), &hostBuf); +#endif + + if (result < 0) + return -errno; + + OS::copyOutStat64Buf(xc->getMemPort(), fd, xc->getSyscallArg(1), &hostBuf); + + return 0; +} + + +/// Target lstat() handler. +template <class OS> +SyscallReturn +lstatFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + std::string path; + + if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0))) + return -EFAULT; + + struct stat hostBuf; + int result = lstat(path.c_str(), &hostBuf); + + if (result < 0) + return -errno; + + OS::copyOutStatBuf(xc->getMemPort(), xc->getSyscallArg(1), &hostBuf); + + return 0; +} + +/// Target lstat64() handler. +template <class OS> +SyscallReturn +lstat64Func(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + std::string path; + + if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0))) + return -EFAULT; + +#if BSD_HOST + struct stat hostBuf; + int result = lstat(path.c_str(), &hostBuf); +#else + struct stat64 hostBuf; + int result = lstat64(path.c_str(), &hostBuf); +#endif + + if (result < 0) + return -errno; + + OS::copyOutStat64Buf(xc->getMemPort(), -1, xc->getSyscallArg(1), &hostBuf); + + return 0; +} + +/// Target fstat() handler. +template <class OS> +SyscallReturn +fstatFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + int fd = process->sim_fd(xc->getSyscallArg(0)); + + DPRINTF(SyscallVerbose, "fstat(%d, ...)\n", fd); + + if (fd < 0) + return -EBADF; + + struct stat hostBuf; + int result = fstat(fd, &hostBuf); + + if (result < 0) + return -errno; + + OS::copyOutStatBuf(xc->getMemPort(), xc->getSyscallArg(1), &hostBuf); + + return 0; +} + + +/// Target statfs() handler. +template <class OS> +SyscallReturn +statfsFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + std::string path; + + if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0))) + return -EFAULT; + + struct statfs hostBuf; + int result = statfs(path.c_str(), &hostBuf); + + if (result < 0) + return -errno; + + OS::copyOutStatfsBuf(xc->getMemPort(), xc->getSyscallArg(1), &hostBuf); + + return 0; +} + + +/// Target fstatfs() handler. +template <class OS> +SyscallReturn +fstatfsFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + int fd = process->sim_fd(xc->getSyscallArg(0)); + + if (fd < 0) + return -EBADF; + + struct statfs hostBuf; + int result = fstatfs(fd, &hostBuf); + + if (result < 0) + return -errno; + + OS::copyOutStatfsBuf(xc->getMemPort(), xc->getSyscallArg(1), &hostBuf); + + return 0; +} + + +/// Target writev() handler. +template <class OS> +SyscallReturn +writevFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + int fd = xc->getSyscallArg(0); + if (fd < 0 || process->sim_fd(fd) < 0) { + // doesn't map to any simulator fd: not a valid target fd + return -EBADF; + } + + TranslatingPort *p = xc->getMemPort(); + uint64_t tiov_base = xc->getSyscallArg(1); + size_t count = xc->getSyscallArg(2); + struct iovec hiov[count]; + for (int i = 0; i < count; ++i) + { + typename OS::tgt_iovec tiov; + + p->readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec), + (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec)); + hiov[i].iov_len = gtoh(tiov.iov_len); + hiov[i].iov_base = new char [hiov[i].iov_len]; + p->readBlob(gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base, + hiov[i].iov_len); + } + + int result = writev(process->sim_fd(fd), hiov, count); + + for (int i = 0; i < count; ++i) + { + delete [] (char *)hiov[i].iov_base; + } + + if (result < 0) + return -errno; + + return 0; +} + + +/// Target mmap() handler. +/// +/// We don't really handle mmap(). If the target is mmaping an +/// anonymous region or /dev/zero, we can get away with doing basically +/// nothing (since memory is initialized to zero and the simulator +/// doesn't really check addresses anyway). Always print a warning, +/// since this could be seriously broken if we're not mapping +/// /dev/zero. +// +/// Someday we should explicitly check for /dev/zero in open, flag the +/// file descriptor, and fail (or implement!) a non-anonymous mmap to +/// anything else. +template <class OS> +SyscallReturn +mmapFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) +{ + Addr start = xc->getSyscallArg(0); + uint64_t length = xc->getSyscallArg(1); + // int prot = xc->getSyscallArg(2); + int flags = xc->getSyscallArg(3); + // int fd = p->sim_fd(xc->getSyscallArg(4)); + // int offset = xc->getSyscallArg(5); + + if ((start % TheISA::VMPageSize) != 0 || + (length % TheISA::VMPageSize) != 0) { + warn("mmap failing: arguments not page-aligned: " + "start 0x%x length 0x%x", + start, length); + return -EINVAL; + } + + if (start != 0) { + warn("mmap: ignoring suggested map address 0x%x, using 0x%x", + start, p->mmap_end); + } + + // pick next address from our "mmap region" + start = p->mmap_end; + p->pTable->allocate(start, length); + p->mmap_end += length; + + if (!(flags & OS::TGT_MAP_ANONYMOUS)) { + warn("allowing mmap of file @ fd %d. " + "This will break if not /dev/zero.", xc->getSyscallArg(4)); + } + + return start; +} + +/// Target getrlimit() handler. +template <class OS> +SyscallReturn +getrlimitFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + unsigned resource = xc->getSyscallArg(0); + TypedBufferArg<typename OS::rlimit> rlp(xc->getSyscallArg(1)); + + switch (resource) { + case OS::TGT_RLIMIT_STACK: + // max stack size in bytes: make up a number (2MB for now) + rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; + rlp->rlim_cur = htog(rlp->rlim_cur); + rlp->rlim_max = htog(rlp->rlim_max); + break; + + default: + std::cerr << "getrlimitFunc: unimplemented resource " << resource + << std::endl; + abort(); + break; + } + + rlp.copyOut(xc->getMemPort()); + return 0; +} + +/// Target gettimeofday() handler. +template <class OS> +SyscallReturn +gettimeofdayFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + TypedBufferArg<typename OS::timeval> tp(xc->getSyscallArg(0)); + + getElapsedTime(tp->tv_sec, tp->tv_usec); + tp->tv_sec += seconds_since_epoch; + tp->tv_sec = htog(tp->tv_sec); + tp->tv_usec = htog(tp->tv_usec); + + tp.copyOut(xc->getMemPort()); + + return 0; +} + + +/// Target utimes() handler. +template <class OS> +SyscallReturn +utimesFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + std::string path; + + if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0))) + return -EFAULT; + + TypedBufferArg<typename OS::timeval [2]> tp(xc->getSyscallArg(1)); + tp.copyIn(xc->getMemPort()); + + struct timeval hostTimeval[2]; + for (int i = 0; i < 2; ++i) + { + hostTimeval[i].tv_sec = gtoh((*tp)[i].tv_sec); + hostTimeval[i].tv_usec = gtoh((*tp)[i].tv_usec); + } + int result = utimes(path.c_str(), hostTimeval); + + if (result < 0) + return -errno; + + return 0; +} +/// Target getrusage() function. +template <class OS> +SyscallReturn +getrusageFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + int who = xc->getSyscallArg(0); // THREAD, SELF, or CHILDREN + TypedBufferArg<typename OS::rusage> rup(xc->getSyscallArg(1)); + + if (who != OS::TGT_RUSAGE_SELF) { + // don't really handle THREAD or CHILDREN, but just warn and + // plow ahead + warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.", + who); + } + + getElapsedTime(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec); + rup->ru_utime.tv_sec = htog(rup->ru_utime.tv_sec); + rup->ru_utime.tv_usec = htog(rup->ru_utime.tv_usec); + + rup->ru_stime.tv_sec = 0; + rup->ru_stime.tv_usec = 0; + rup->ru_maxrss = 0; + rup->ru_ixrss = 0; + rup->ru_idrss = 0; + rup->ru_isrss = 0; + rup->ru_minflt = 0; + rup->ru_majflt = 0; + rup->ru_nswap = 0; + rup->ru_inblock = 0; + rup->ru_oublock = 0; + rup->ru_msgsnd = 0; + rup->ru_msgrcv = 0; + rup->ru_nsignals = 0; + rup->ru_nvcsw = 0; + rup->ru_nivcsw = 0; + + rup.copyOut(xc->getMemPort()); + + return 0; +} + + + + +#endif // __SIM_SYSCALL_EMUL_HH__ diff --git a/src/sim/system.cc b/src/sim/system.cc new file mode 100644 index 000000000..89f39491e --- /dev/null +++ b/src/sim/system.cc @@ -0,0 +1,267 @@ +#include "arch/isa_traits.hh" +#include "base/loader/object_file.hh" +#include "base/loader/symtab.hh" +#include "base/trace.hh" +#include "cpu/exec_context.hh" +#include "mem/mem_object.hh" +#include "mem/physical.hh" +#include "sim/builder.hh" +#include "sim/byteswap.hh" +#include "sim/system.hh" +#if FULL_SYSTEM +#include "arch/vtophys.hh" +#include "base/remote_gdb.hh" +#include "kern/kernel_stats.hh" +#endif + +using namespace std; +using namespace TheISA; + +vector<System *> System::systemList; + +int System::numSystemsRunning = 0; + +System::System(Params *p) + : SimObject(p->name), physmem(p->physmem), numcpus(0), +#if FULL_SYSTEM + init_param(p->init_param), + functionalPort(p->name + "-fport"), + virtPort(p->name + "-vport"), +#else + page_ptr(0), +#endif + _params(p) +{ + // add self to global system list + systemList.push_back(this); + +#if FULL_SYSTEM + kernelSymtab = new SymbolTable; + debugSymbolTable = new SymbolTable; + + + /** + * Get a functional port to memory + */ + Port *mem_port; + mem_port = physmem->getPort("functional"); + functionalPort.setPeer(mem_port); + mem_port->setPeer(&functionalPort); + + mem_port = physmem->getPort("functional"); + virtPort.setPeer(mem_port); + mem_port->setPeer(&virtPort); + + + /** + * Load the kernel code into memory + */ + // Load kernel code + kernel = createObjectFile(params()->kernel_path); + if (kernel == NULL) + fatal("Could not load kernel file %s", params()->kernel_path); + + // Load program sections into memory + kernel->loadSections(&functionalPort, LoadAddrMask); + + // setup entry points + kernelStart = kernel->textBase(); + kernelEnd = kernel->bssBase() + kernel->bssSize(); + kernelEntry = kernel->entryPoint(); + + // load symbols + if (!kernel->loadGlobalSymbols(kernelSymtab)) + panic("could not load kernel symbols\n"); + + if (!kernel->loadLocalSymbols(kernelSymtab)) + panic("could not load kernel local symbols\n"); + + if (!kernel->loadGlobalSymbols(debugSymbolTable)) + panic("could not load kernel symbols\n"); + + if (!kernel->loadLocalSymbols(debugSymbolTable)) + panic("could not load kernel local symbols\n"); + + DPRINTF(Loader, "Kernel start = %#x\n", kernelStart); + DPRINTF(Loader, "Kernel end = %#x\n", kernelEnd); + DPRINTF(Loader, "Kernel entry = %#x\n", kernelEntry); + DPRINTF(Loader, "Kernel loaded...\n"); + + kernelBinning = new Kernel::Binning(this); +#endif // FULL_SYSTEM + + // increment the number of running systms + numSystemsRunning++; +} + +System::~System() +{ +#if FULL_SYSTEM + delete kernelSymtab; + delete kernel; + + delete kernelBinning; +#else + panic("System::fixFuncEventAddr needs to be rewritten " + "to work with syscall emulation"); +#endif // FULL_SYSTEM} +} + +#if FULL_SYSTEM + + +int rgdb_wait = -1; + +#endif // FULL_SYSTEM + +int +System::registerExecContext(ExecContext *xc, int id) +{ + if (id == -1) { + for (id = 0; id < execContexts.size(); id++) { + if (!execContexts[id]) + break; + } + } + + if (execContexts.size() <= id) + execContexts.resize(id + 1); + + if (execContexts[id]) + panic("Cannot have two CPUs with the same id (%d)\n", id); + + execContexts[id] = xc; + numcpus++; + +#if FULL_SYSTEM + RemoteGDB *rgdb = new RemoteGDB(this, xc); + GDBListener *gdbl = new GDBListener(rgdb, 7000 + id); + gdbl->listen(); + /** + * Uncommenting this line waits for a remote debugger to connect + * to the simulator before continuing. + */ + if (rgdb_wait != -1 && rgdb_wait == id) + gdbl->accept(); + + if (remoteGDB.size() <= id) { + remoteGDB.resize(id + 1); + } + + remoteGDB[id] = rgdb; +#endif // FULL_SYSTEM + + return id; +} + +void +System::startup() +{ + int i; + for (i = 0; i < execContexts.size(); i++) + execContexts[i]->activate(0); +} + +void +System::replaceExecContext(ExecContext *xc, int id) +{ + if (id >= execContexts.size()) { + panic("replaceExecContext: bad id, %d >= %d\n", + id, execContexts.size()); + } + + execContexts[id] = xc; +#if FULL_SYSTEM + remoteGDB[id]->replaceExecContext(xc); +#endif // FULL_SYSTEM +} + +#if !FULL_SYSTEM +Addr +System::new_page() +{ + Addr return_addr = page_ptr << LogVMPageSize; + ++page_ptr; + return return_addr; +} +#endif + +void +System::regStats() +{ +#if FULL_SYSTEM + kernelBinning->regStats(name() + ".kern"); +#endif // FULL_SYSTEM +} + +void +System::serialize(ostream &os) +{ +#if FULL_SYSTEM + kernelBinning->serialize(os); + + kernelSymtab->serialize("kernel_symtab", os); +#endif // FULL_SYSTEM +} + + +void +System::unserialize(Checkpoint *cp, const string §ion) +{ +#if FULL_SYSTEM + kernelBinning->unserialize(cp, section); + + kernelSymtab->unserialize("kernel_symtab", cp, section); +#endif // FULL_SYSTEM +} + +void +System::printSystems() +{ + vector<System *>::iterator i = systemList.begin(); + vector<System *>::iterator end = systemList.end(); + for (; i != end; ++i) { + System *sys = *i; + cerr << "System " << sys->name() << ": " << hex << sys << endl; + } +} + +extern "C" +void +printSystems() +{ + System::printSystems(); +} + +#if FULL_SYSTEM + +// In full system mode, only derived classes (e.g. AlphaLinuxSystem) +// can be created directly. + +DEFINE_SIM_OBJECT_CLASS_NAME("System", System) + +#else + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(System) + + SimObjectParam<PhysicalMemory *> physmem; + +END_DECLARE_SIM_OBJECT_PARAMS(System) + +BEGIN_INIT_SIM_OBJECT_PARAMS(System) + + INIT_PARAM(physmem, "physical memory") + +END_INIT_SIM_OBJECT_PARAMS(System) + +CREATE_SIM_OBJECT(System) +{ + System::Params *p = new System::Params; + p->name = getInstanceName(); + p->physmem = physmem; + return new System(p); +} + +REGISTER_SIM_OBJECT("System", System) + +#endif diff --git a/src/sim/system.hh b/src/sim/system.hh new file mode 100644 index 000000000..7e21bd587 --- /dev/null +++ b/src/sim/system.hh @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __SYSTEM_HH__ +#define __SYSTEM_HH__ + +#include <string> +#include <vector> + +#include "base/loader/symtab.hh" +#include "base/misc.hh" +#include "base/statistics.hh" +#include "cpu/pc_event.hh" +#include "mem/port.hh" +#include "sim/sim_object.hh" +#if FULL_SYSTEM +#include "kern/system_events.hh" +#include "mem/vport.hh" +#endif + +class BaseCPU; +class ExecContext; +class ObjectFile; +class PhysicalMemory; + +#if FULL_SYSTEM +class Platform; +class GDBListener; +class RemoteGDB; +namespace Kernel { class Binning; } +#endif + +class System : public SimObject +{ + public: + PhysicalMemory *physmem; + PCEventQueue pcEventQueue; + + std::vector<ExecContext *> execContexts; + int numcpus; + + int getNumCPUs() + { + if (numcpus != execContexts.size()) + panic("cpu array not fully populated!"); + + return numcpus; + } + +#if FULL_SYSTEM + Platform *platform; + uint64_t init_param; + + /** Port to physical memory used for writing object files into ram at + * boot.*/ + FunctionalPort functionalPort; + VirtualPort virtPort; + + /** kernel symbol table */ + SymbolTable *kernelSymtab; + + /** Object pointer for the kernel code */ + ObjectFile *kernel; + + /** Begining of kernel code */ + Addr kernelStart; + + /** End of kernel code */ + Addr kernelEnd; + + /** Entry point in the kernel to start at */ + Addr kernelEntry; + + Kernel::Binning *kernelBinning; + +#else + + int page_ptr; + + +#endif // FULL_SYSTEM + + protected: + +#if FULL_SYSTEM + /** + * Fix up an address used to match PCs for hooking simulator + * events on to target function executions. See comment in + * system.cc for details. + */ + virtual Addr fixFuncEventAddr(Addr addr) = 0; + + /** + * Add a function-based event to the given function, to be looked + * up in the specified symbol table. + */ + template <class T> + T *System::addFuncEvent(SymbolTable *symtab, const char *lbl) + { + Addr addr = 0; // initialize only to avoid compiler warning + + if (symtab->findAddress(lbl, addr)) { + T *ev = new T(&pcEventQueue, lbl, fixFuncEventAddr(addr)); + return ev; + } + + return NULL; + } + + /** Add a function-based event to kernel code. */ + template <class T> + T *System::addKernelFuncEvent(const char *lbl) + { + return addFuncEvent<T>(kernelSymtab, lbl); + } + +#endif + public: +#if FULL_SYSTEM + std::vector<RemoteGDB *> remoteGDB; + std::vector<GDBListener *> gdbListen; + virtual bool breakpoint() = 0; +#endif // FULL_SYSTEM + + public: + struct Params + { + std::string name; + PhysicalMemory *physmem; + +#if FULL_SYSTEM + Tick boot_cpu_frequency; + std::string boot_osflags; + uint64_t init_param; + bool bin; + std::vector<std::string> binned_fns; + bool bin_int; + + std::string kernel_path; + std::string readfile; +#endif + }; + + protected: + Params *_params; + + public: + System(Params *p); + ~System(); + + void startup(); + + const Params *params() const { return (const Params *)_params; } + + public: + +#if FULL_SYSTEM + /** + * Returns the addess the kernel starts at. + * @return address the kernel starts at + */ + Addr getKernelStart() const { return kernelStart; } + + /** + * Returns the addess the kernel ends at. + * @return address the kernel ends at + */ + Addr getKernelEnd() const { return kernelEnd; } + + /** + * Returns the addess the entry point to the kernel code. + * @return entry point of the kernel code + */ + Addr getKernelEntry() const { return kernelEntry; } + +#else + + Addr new_page(); + +#endif // FULL_SYSTEM + + int registerExecContext(ExecContext *xc, int xcIndex); + void replaceExecContext(ExecContext *xc, int xcIndex); + + void regStats(); + void serialize(std::ostream &os); + void unserialize(Checkpoint *cp, const std::string §ion); + + public: + //////////////////////////////////////////// + // + // STATIC GLOBAL SYSTEM LIST + // + //////////////////////////////////////////// + + static std::vector<System *> systemList; + static int numSystemsRunning; + + static void printSystems(); + + +}; + +#endif // __SYSTEM_HH__ diff --git a/src/sim/vptr.hh b/src/sim/vptr.hh new file mode 100644 index 000000000..cc57e63f0 --- /dev/null +++ b/src/sim/vptr.hh @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ARCH_ALPHA_VPTR_HH__ +#define __ARCH_ALPHA_VPTR_HH__ + +#include "arch/vtophys.hh" +#include "arch/isa_traits.hh" + +class ExecContext; + +template <class T> +class VPtr +{ + public: + typedef T Type; + + private: + ExecContext *xc; + Addr ptr; + + public: + ExecContext *GetXC() const { return xc; } + Addr GetPointer() const { return ptr; } + + public: + explicit VPtr(ExecContext *_xc, Addr p = 0) : xc(_xc), ptr(p) { } + template <class U> + VPtr(const VPtr<U> &vp) : xc(vp.GetXC()), ptr(vp.GetPointer()) {} + ~VPtr() {} + + bool operator!() const + { + return ptr == 0; + } + + VPtr<T> operator+(int offset) + { + VPtr<T> ptr(*this); + ptr += offset; + + return ptr; + } + + const VPtr<T> &operator+=(int offset) + { + ptr += offset; + assert((ptr & (TheISA::PageBytes - 1)) + sizeof(T) + < TheISA::PageBytes); + + return *this; + } + + const VPtr<T> &operator=(Addr p) + { + assert((p & (TheISA::PageBytes - 1)) + sizeof(T) + < TheISA::PageBytes); + ptr = p; + + return *this; + } + + template <class U> + const VPtr<T> &operator=(const VPtr<U> &vp) + { + xc = vp.GetXC(); + ptr = vp.GetPointer(); + + return *this; + } + + operator T *() + { + panic("Needs to be rewritten\n"); +/* void *addr = vtomem(xc, ptr, sizeof(T)); + return (T *)addr; + */ + } + + T *operator->() + { + panic("Needs to be rewritten\n"); +/* void *addr = vtomem(xc, ptr, sizeof(T)); + return (T *)addr; + */ + } + + T &operator*() + { + panic("Needs to be rewritten\n"); +/* void *addr = vtomem(xc, ptr, sizeof(T)); + return *(T *)addr; + */ + } +}; + +#endif // __ARCH_ALPHA_VPTR_HH__ diff --git a/src/unittest/Makefile b/src/unittest/Makefile new file mode 100644 index 000000000..1f0584066 --- /dev/null +++ b/src/unittest/Makefile @@ -0,0 +1,98 @@ +# Copyright (c) 2006 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Nathan Binkert +# Steve Reinhardt + +CC?= gcc +CXX?= g++ +PYTHON?=/usr/bin/env python + +CURDIR?= $(shell /bin/pwd) +SRCDIR?= $(CURDIR)/.. + +CCFLAGS= -g -O0 -MMD -I. -I$(SRCDIR) -I- -DTRACING_ON=0 +MYSQL= -I/usr/include/mysql -L/usr/lib/mysql -lmysqlclient + +VPATH=$(SRCDIR):$(CURDIR) + +default: + @echo "You must specify a target" + +base/traceflags.cc base/traceflags.hh: $(SRCDIR)/base/traceflags.py + mkdir -p base; \ + cd base; \ + $(PYTHON) $< + +bitvectest: test/bitvectest.cc + $(CXX) $(CCFLAGS) -o $@ $^ + +circletest: test/circletest.cc base/circlebuf.cc + $(CXX) $(CCFLAGS) -o $@ $^ + +cprintftest: test/cprintftest.cc base/cprintf.cc + $(CXX) $(CCFLAGS) -o $@ $^ + +initest: test/initest.cc base/str.cc base/inifile.cc base/cprintf.cc + $(CXX) $(CCFLAGS) -o $@ $^ + +lrutest: test/lru_test.cc + $(CXX) $(CCFLAGS) -o $@ $^ + +nmtest: test/nmtest.cc base/output.cc base/hostinfo.cc base/cprintf.cc base/misc.cc base/loader/object_file.cc base/loader/symtab.cc base/misc.cc base/str.cc base/loader/aout_object.cc base/loader/ecoff_object.cc base/loader/elf_object.cc + $(CXX) $(CCFLAGS) -I/n/ziff/z/binkertn/build/work/ALPHA_FS -lelf -o $@ $^ + +offtest: test/offtest.cc + $(CXX) $(CCFLAGS) -o $@ $^ + +rangetest: test/rangetest.cc base/range.cc base/str.cc + $(CXX) $(CCFLAGS) -o $@ $^ + +STATTEST+= base/cprintf.cc base/hostinfo.cc base/misc.cc base/mysql.cc +STATTEST+= base/python.cc base/str.cc base/time.cc +STATTEST+= base/statistics.cc base/stats/mysql.cc base/stats/python.cc +STATTEST+= base/stats/statdb.cc base/stats/text.cc base/stats/visit.cc +STATTEST+= test/stattest.cc +stattest: $(STATTEST) + $(CXX) $(CCFLAGS) $(MYSQL) -o $@ $^ + +strnumtest: test/strnumtest.cc base/str.cc + $(CXX) $(CCFLAGS) -o $@ $^ + +symtest: test/symtest.cc base/misc.cc base/symtab.cc base/str.cc + $(CXX) $(CCFLAGS) -o $@ $^ + +tokentest: test/tokentest.cc base/str.cc + $(CXX) $(CCFLAGS) -o $@ $^ + +TRACE+=test/tracetest.cc base/trace.cc base/trace_flags.cc base/cprintf.cc +TRACE+=base/str.cc base/misc.cc +tracetest: $(TRACE) + $(CXX) $(CCFLAGS) -o $@ $^ + +clean: + @rm -rf *test *~ .#* *.core core base +.PHONY: clean diff --git a/test/bitvectest.cc b/src/unittest/bitvectest.cc index 1b8c332f5..1b8c332f5 100644 --- a/test/bitvectest.cc +++ b/src/unittest/bitvectest.cc diff --git a/test/circletest.cc b/src/unittest/circletest.cc index bb15f8c64..bb15f8c64 100644 --- a/test/circletest.cc +++ b/src/unittest/circletest.cc diff --git a/src/unittest/cprintftest.cc b/src/unittest/cprintftest.cc new file mode 100644 index 000000000..361f84028 --- /dev/null +++ b/src/unittest/cprintftest.cc @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <iostream> +#include <list> +#include <string> +#include <sstream> + +#include "base/cprintf.hh" + +using namespace std; + +int +main() +{ + char foo[9]; + cprintf("%s\n", foo); + + cprintf("%shits%%s + %smisses%%s\n", "test", "test"); + cprintf("%%s%-10s %c he went home \'\"%d %#o %#x %1.5f %1.2E\n", + "hello", 'A', 1, 0xff, 0xfffffffffffffULL, 3.141592653589, 1.1e10); + + cout << cformat("%s %#x %s\n") << "hello" << 0 << "foo 0\n"; + cerr << cformat("%s %#x\n") << "hello" << 1 << "foo 1\n"; + + cprintf("another test\n"); + + stringstream buffer; + ccprintf(buffer, "%-10s %c he home \'\"%d %#o %#x %1.5f %1.2E\n", + "hello", 'A', 1, 0xff, 0xfffffffffffffULL, 3.14159265, 1.1e10); + + double f = 314159.26535897932384; + + #define ctest(x, y) printf(x, y); cprintf(x, y); cprintf("\n"); + ctest("%1.8f\n", f); + ctest("%2.8f\n", f); + ctest("%3.8f\n", f); + ctest("%4.8f\n", f); + ctest("%5.8f\n", f); + ctest("%6.8f\n", f); + ctest("%12.8f\n", f); + ctest("%1000.8f\n", f); + ctest("%1.0f\n", f); + ctest("%1.1f\n", f); + ctest("%1.2f\n", f); + ctest("%1.3f\n", f); + ctest("%1.4f\n", f); + ctest("%1.5f\n", f); + ctest("%1.6f\n", f); + ctest("%1.7f\n", f); + ctest("%1.8f\n", f); + ctest("%1.9f\n", f); + ctest("%1.10f\n", f); + ctest("%1.11f\n", f); + ctest("%1.12f\n", f); + ctest("%1.13f\n", f); + ctest("%1.14f\n", f); + ctest("%1.15f\n", f); + ctest("%1.16f\n", f); + ctest("%1.17f\n", f); + ctest("%1.18f\n", f); + + cout << "foo\n"; + + f = 0.00000026535897932384; + ctest("%1.8f\n", f); + ctest("%2.8f\n", f); + ctest("%3.8f\n", f); + ctest("%4.8f\n", f); + ctest("%5.8f\n", f); + ctest("%6.8f\n", f); + ctest("%12.8f\n", f); + ctest("%1.0f\n", f); + ctest("%1.1f\n", f); + ctest("%1.2f\n", f); + ctest("%1.3f\n", f); + ctest("%1.4f\n", f); + ctest("%1.5f\n", f); + ctest("%1.6f\n", f); + ctest("%1.7f\n", f); + ctest("%1.8f\n", f); + ctest("%1.9f\n", f); + ctest("%1.10f\n", f); + ctest("%1.11f\n", f); + ctest("%1.12f\n", f); + ctest("%1.13f\n", f); + ctest("%1.14f\n", f); + ctest("%1.15f\n", f); + ctest("%1.16f\n", f); + ctest("%1.17f\n", f); + ctest("%1.18f\n", f); + + f = 0.00000026535897932384; + ctest("%1.8e\n", f); + ctest("%2.8e\n", f); + ctest("%3.8e\n", f); + ctest("%4.8e\n", f); + ctest("%5.8e\n", f); + ctest("%6.8e\n", f); + ctest("%12.8e\n", f); + ctest("%1.0e\n", f); + ctest("%1.1e\n", f); + ctest("%1.2e\n", f); + ctest("%1.3e\n", f); + ctest("%1.4e\n", f); + ctest("%1.5e\n", f); + ctest("%1.6e\n", f); + ctest("%1.7e\n", f); + ctest("%1.8e\n", f); + ctest("%1.9e\n", f); + ctest("%1.10e\n", f); + ctest("%1.11e\n", f); + ctest("%1.12e\n", f); + ctest("%1.13e\n", f); + ctest("%1.14e\n", f); + ctest("%1.15e\n", f); + ctest("%1.16e\n", f); + ctest("%1.17e\n", f); + ctest("%1.18e\n", f); + + cout << buffer.str(); + + cout.width(0); + cout.precision(1); + cout << f << "\n"; + + string foo1 = "string test"; + cprintf("%s\n", foo1); + + stringstream foo2; + foo2 << "stringstream test"; + cprintf("%s\n", foo2); + + cprintf("%c %c\n", 'c', 65); + + cout << '9'; + return 0; +} diff --git a/test/foo.ini b/src/unittest/foo.ini index 534a4e001..534a4e001 100644 --- a/test/foo.ini +++ b/src/unittest/foo.ini diff --git a/test/genini.py b/src/unittest/genini.py index 2af81fe2b..2af81fe2b 100755 --- a/test/genini.py +++ b/src/unittest/genini.py diff --git a/test/initest.cc b/src/unittest/initest.cc index 0c5ac2343..0c5ac2343 100644 --- a/test/initest.cc +++ b/src/unittest/initest.cc diff --git a/test/initest.ini b/src/unittest/initest.ini index ebf2719d8..ebf2719d8 100644 --- a/test/initest.ini +++ b/src/unittest/initest.ini diff --git a/test/lru_test.cc b/src/unittest/lru_test.cc index 2829163de..2829163de 100644 --- a/test/lru_test.cc +++ b/src/unittest/lru_test.cc diff --git a/test/nmtest.cc b/src/unittest/nmtest.cc index e9c20d19d..e9c20d19d 100644 --- a/test/nmtest.cc +++ b/src/unittest/nmtest.cc diff --git a/test/offtest.cc b/src/unittest/offtest.cc index d3f035b73..d3f035b73 100644 --- a/test/offtest.cc +++ b/src/unittest/offtest.cc diff --git a/test/paramtest.cc b/src/unittest/paramtest.cc index cb31c49d5..cb31c49d5 100644 --- a/test/paramtest.cc +++ b/src/unittest/paramtest.cc diff --git a/test/rangetest.cc b/src/unittest/rangetest.cc index 41d438f48..41d438f48 100644 --- a/test/rangetest.cc +++ b/src/unittest/rangetest.cc diff --git a/test/sized_test.cc b/src/unittest/sized_test.cc index 86cd13e5b..86cd13e5b 100644 --- a/test/sized_test.cc +++ b/src/unittest/sized_test.cc diff --git a/test/stattest.cc b/src/unittest/stattest.cc index b944eff45..b944eff45 100644 --- a/test/stattest.cc +++ b/src/unittest/stattest.cc diff --git a/test/strnumtest.cc b/src/unittest/strnumtest.cc index a80dd7c36..a80dd7c36 100644 --- a/test/strnumtest.cc +++ b/src/unittest/strnumtest.cc diff --git a/test/symtest.cc b/src/unittest/symtest.cc index 5fba71736..5fba71736 100644 --- a/test/symtest.cc +++ b/src/unittest/symtest.cc diff --git a/test/tokentest.cc b/src/unittest/tokentest.cc index 7f27d58fe..7f27d58fe 100644 --- a/test/tokentest.cc +++ b/src/unittest/tokentest.cc diff --git a/test/tracetest.cc b/src/unittest/tracetest.cc index 866b67d9b..866b67d9b 100644 --- a/test/tracetest.cc +++ b/src/unittest/tracetest.cc diff --git a/test/Makefile b/test/Makefile deleted file mode 100644 index 6fe0e5f48..000000000 --- a/test/Makefile +++ /dev/null @@ -1,69 +0,0 @@ -CC?= gcc -CXX?= g++ -PYTHON?=/usr/bin/env python - -CURDIR?= $(shell /bin/pwd) -SRCDIR?= $(CURDIR)/.. - -CCFLAGS= -g -O0 -MMD -I. -I$(SRCDIR) -I- -DTRACING_ON=0 -MYSQL= -I/usr/include/mysql -L/usr/lib/mysql -lmysqlclient - -VPATH=$(SRCDIR):$(CURDIR) - -default: - @echo "You must specify a target" - -base/traceflags.cc base/traceflags.hh: $(SRCDIR)/base/traceflags.py - mkdir -p base; \ - cd base; \ - $(PYTHON) $< - -bitvectest: test/bitvectest.cc - $(CXX) $(CCFLAGS) -o $@ $^ - -circletest: test/circletest.cc base/circlebuf.cc - $(CXX) $(CCFLAGS) -o $@ $^ - -cprintftest: test/cprintftest.cc base/cprintf.cc - $(CXX) $(CCFLAGS) -o $@ $^ - -initest: test/initest.cc base/str.cc base/inifile.cc base/cprintf.cc - $(CXX) $(CCFLAGS) -o $@ $^ - -lrutest: test/lru_test.cc - $(CXX) $(CCFLAGS) -o $@ $^ - -nmtest: test/nmtest.cc base/output.cc base/hostinfo.cc base/cprintf.cc base/misc.cc base/loader/object_file.cc base/loader/symtab.cc base/misc.cc base/str.cc base/loader/aout_object.cc base/loader/ecoff_object.cc base/loader/elf_object.cc - $(CXX) $(CCFLAGS) -I/n/ziff/z/binkertn/build/work/ALPHA_FS -lelf -o $@ $^ - -offtest: test/offtest.cc - $(CXX) $(CCFLAGS) -o $@ $^ - -rangetest: test/rangetest.cc base/range.cc base/str.cc - $(CXX) $(CCFLAGS) -o $@ $^ - -STATTEST+= base/cprintf.cc base/hostinfo.cc base/misc.cc base/mysql.cc -STATTEST+= base/python.cc base/str.cc base/time.cc -STATTEST+= base/statistics.cc base/stats/mysql.cc base/stats/python.cc -STATTEST+= base/stats/statdb.cc base/stats/text.cc base/stats/visit.cc -STATTEST+= test/stattest.cc -stattest: $(STATTEST) - $(CXX) $(CCFLAGS) $(MYSQL) -o $@ $^ - -strnumtest: test/strnumtest.cc base/str.cc - $(CXX) $(CCFLAGS) -o $@ $^ - -symtest: test/symtest.cc base/misc.cc base/symtab.cc base/str.cc - $(CXX) $(CCFLAGS) -o $@ $^ - -tokentest: test/tokentest.cc base/str.cc - $(CXX) $(CCFLAGS) -o $@ $^ - -TRACE+=test/tracetest.cc base/trace.cc base/trace_flags.cc base/cprintf.cc -TRACE+=base/str.cc base/misc.cc -tracetest: $(TRACE) - $(CXX) $(CCFLAGS) -o $@ $^ - -clean: - @rm -rf *test *~ .#* *.core core base -.PHONY: clean diff --git a/test/cprintftest.cc b/test/cprintftest.cc deleted file mode 100644 index 611f01bc2..000000000 --- a/test/cprintftest.cc +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (c) 2002-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <cstdio> -#include <iostream> -#include <list> -#include <string> -#include <sstream> - -#include "base/cprintf.hh" - -using namespace std; - -int -main() -{ - char foo[9]; - cprintf("%s\n", foo); - - cprintf("%shits%%s + %smisses%%s\n", "test", "test"); - cprintf("%%s%-10s %c he went home \'\"%d %#o %#x %1.5f %1.2E\n", - "hello", 'A', 1, 0xff, 0xfffffffffffffULL, 3.141592653589, 1.1e10); - - cout << cformat("%s %#x %s\n") << "hello" << 0 << "foo 0\n"; - cerr << cformat("%s %#x\n") << "hello" << 1 << "foo 1\n"; - - cprintf("another test\n"); - - stringstream buffer; - ccprintf(buffer, "%-10s %c he home \'\"%d %#o %#x %1.5f %1.2E\n", - "hello", 'A', 1, 0xff, 0xfffffffffffffULL, 3.14159265, 1.1e10); - - double f = 314159.26535897932384; - - #define ctest(x, y) printf(x, y); cprintf(x, y); cprintf("\n"); - ctest("%1.8f\n", f); - ctest("%2.8f\n", f); - ctest("%3.8f\n", f); - ctest("%4.8f\n", f); - ctest("%5.8f\n", f); - ctest("%6.8f\n", f); - ctest("%12.8f\n", f); - ctest("%1000.8f\n", f); - ctest("%1.0f\n", f); - ctest("%1.1f\n", f); - ctest("%1.2f\n", f); - ctest("%1.3f\n", f); - ctest("%1.4f\n", f); - ctest("%1.5f\n", f); - ctest("%1.6f\n", f); - ctest("%1.7f\n", f); - ctest("%1.8f\n", f); - ctest("%1.9f\n", f); - ctest("%1.10f\n", f); - ctest("%1.11f\n", f); - ctest("%1.12f\n", f); - ctest("%1.13f\n", f); - ctest("%1.14f\n", f); - ctest("%1.15f\n", f); - ctest("%1.16f\n", f); - ctest("%1.17f\n", f); - ctest("%1.18f\n", f); - - cout << "foo\n"; - - f = 0.00000026535897932384; - ctest("%1.8f\n", f); - ctest("%2.8f\n", f); - ctest("%3.8f\n", f); - ctest("%4.8f\n", f); - ctest("%5.8f\n", f); - ctest("%6.8f\n", f); - ctest("%12.8f\n", f); - ctest("%1.0f\n", f); - ctest("%1.1f\n", f); - ctest("%1.2f\n", f); - ctest("%1.3f\n", f); - ctest("%1.4f\n", f); - ctest("%1.5f\n", f); - ctest("%1.6f\n", f); - ctest("%1.7f\n", f); - ctest("%1.8f\n", f); - ctest("%1.9f\n", f); - ctest("%1.10f\n", f); - ctest("%1.11f\n", f); - ctest("%1.12f\n", f); - ctest("%1.13f\n", f); - ctest("%1.14f\n", f); - ctest("%1.15f\n", f); - ctest("%1.16f\n", f); - ctest("%1.17f\n", f); - ctest("%1.18f\n", f); - - f = 0.00000026535897932384; - ctest("%1.8e\n", f); - ctest("%2.8e\n", f); - ctest("%3.8e\n", f); - ctest("%4.8e\n", f); - ctest("%5.8e\n", f); - ctest("%6.8e\n", f); - ctest("%12.8e\n", f); - ctest("%1.0e\n", f); - ctest("%1.1e\n", f); - ctest("%1.2e\n", f); - ctest("%1.3e\n", f); - ctest("%1.4e\n", f); - ctest("%1.5e\n", f); - ctest("%1.6e\n", f); - ctest("%1.7e\n", f); - ctest("%1.8e\n", f); - ctest("%1.9e\n", f); - ctest("%1.10e\n", f); - ctest("%1.11e\n", f); - ctest("%1.12e\n", f); - ctest("%1.13e\n", f); - ctest("%1.14e\n", f); - ctest("%1.15e\n", f); - ctest("%1.16e\n", f); - ctest("%1.17e\n", f); - ctest("%1.18e\n", f); - - cout << buffer.str(); - - cout.width(0); - cout.precision(1); - cout << f << "\n"; - - string foo1 = "string test"; - cprintf("%s\n", foo1); - - stringstream foo2; - foo2 << "stringstream test"; - cprintf("%s\n", foo2); - - cprintf("%c %c\n", 'c', 65); - - cout << '9'; - return 0; -} @@ -179,10 +179,10 @@ try: if output_dir: secs_waited = 0 - while not shell.dir_exists(output_dir) and secs_waited < 45: + while not shell.dir_exists(output_dir) and secs_waited < 90: time.sleep(5) secs_waited += 5 - if secs_waited > 10: + if secs_waited > 30: print "waited", secs_waited, "seconds for", output_dir # run command |